1 ; -----------------------------------
2 ; PROG100k.f = 110 x RC5toLCD.f
3 ; -----------------------------------
6 \ MSP_EXP430FR5739 MSP_EXP430FR5969 MSP_EXP430FR5994 MSP_EXP430FR6989
9 \ MY_MSP430FR5738 MY_MSP430FR5738_1 MY_MSP430FR5738_2
10 \ MY_MSP430FR5948 MY_MSP430FR5948_1
13 \ Copyright (C) <2016> <J.M. THOORENS>
15 \ This program is free software: you can redistribute it and/or modify
16 \ it under the terms of the GNU General Public License as published by
17 \ the Free Software Foundation, either version 3 of the License, or
18 \ (at your option) any later version.
20 \ This program is distributed in the hope that it will be useful,
21 \ but WITHOUT ANY WARRANTY\ without even the implied warranty of
22 \ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 \ GNU General Public License for more details.
25 \ You should have received a copy of the GNU General Public License
26 \ along with this program. If not, see <http://www.gnu.org/licenses/>.
29 \ ===========================================================================
30 \ remember: for good downloading to target, all lines must be ended with CR+LF !
31 \ ===========================================================================
35 \ R4 to R7 must be saved before use and restored after
36 \ scratch registers Y to S are free for use
37 \ under interrupt, IP is free for use
38 \ interrupts reset SR register !
40 \ PUSHM order : PSP,TOS, IP, S, T, W, X, Y, rEXIT,rDOVAR,rDOCON, rDODOES, R3, SR,RSP, PC
41 \ PUSHM order : R15,R14,R13,R12,R11,R10, R9, R8, R7 , R6 , R5 , R4 , R3, R2, R1, R0
43 \ example : PUSHM #6,IP pushes IP,S,T,W,X,Y registers to return stack
45 \ POPM order : PC,RSP, SR, R3, rDODOES,rDOCON,rDOVAR,rEXIT, Y, X, W, T, S, IP,TOS,PSP
46 \ POPM order : R0, R1, R2, R3, R4 , R5 , R6 , R7 , R8, R9,R10,R11,R12,R13,R14,R15
48 \ example : POPM #6,IP pop Y,X,W,T,S,IP registers from return stack
50 \ ASSEMBLER conditionnal usage after IF UNTIL WHILE : S< S>= U< U>= 0= 0<> 0>=
51 \ ASSEMBLER conditionnal usage before ?JMP ?GOTO : S< S>= U< U>= 0= 0<> 0<
53 \ FORTH conditionnal : 0= 0< = < > U<
55 \ display on a LCD 2x20 CHAR the code sent by an IR remote under philips RC5 protocol
56 \ target : any TI MSP-EXP430FRxxxx launchpad (FRAM)
57 \ LPM_MODE = LPM0 because use SMCLK for LCDVo
59 \ DEMO : driver for IR remote compatible with the PHILIPS RC5 protocol
60 \ plus : driver for 5V LCD 2x20 characters display with 4 bits data interface
61 \ without usage of an auxiliary 5V to feed the LCD_Vo
62 \ and without potentiometer to adjust the LCD contrast :
63 \ to adjust LCD contrast, just press S1 (-) or S2 (+)
64 \ LCDVo current consumption ~ 500 uA.
66 \ ===================================================================================
67 \ notice : adjust WDT_TIM_EX0,LCD_TIM_CTL,LCD_TIM_EX0 and 20_us to the target frequency if <> 8MHz !
68 \ ===================================================================================
71 \ layout : I/O are defined in the launchpad.pat file (don't work with ChipStick_FR2433)
73 \ GND <-------+---0V0----------> 1 LCD_Vss
74 \ VCC >------ | --3V6-----+----> 2 LCD_Vdd
81 \ LCD_TIM_.2 >---||--+--^/\/\/v--+----> 3 LCD_Vo (= 0V6 without modulation)
82 \ -------------------------> 4 LCD_RW
83 \ -------------------------> 5 LCD_RW
84 \ -------------------------> 6 LCD_EN
85 \ <------------------------> 11 LCD_DB4
86 \ <------------------------> 12 LCD_DB5
87 \ <------------------------> 13 LCD_DB5
88 \ <------------------------> 14 LCD_DB7
90 \ <----- LCD contrast + <--- Sw1 <--- (finger) :-)
91 \ <----- LCD contrast - <--- Sw2 <--- (finger) :-)
93 \ rc5 <--- OUT IR_Receiver (1 TSOP32236)
95 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
99 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
101 CODE MAX \ n1 n2 -- n3 signed maximum
108 CODE MIN \ n1 n2 -- n3 signed minimum
118 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
119 : U.R \ u n -- display u unsigned in n width (n >= 2)
121 R> OVER - 0 MAX SPACES TYPE
126 \ CODE 20_US \ n -- n * 20 us
127 \ BEGIN \ 3 cycles loop + 6~
128 \ \ MOV #5,W \ 3 MCLK = 1 MHz
129 \ \ MOV #23,W \ 3 MCLK = 4 MHz
130 \ \ MOV #51,W \ 3 MCLK = 8 MHz
131 \ MOV #104,W \ 3 MCLK = 16 MHz
132 \ \ MOV #158,W \ 3 MCLK = 24 MHz
133 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
143 CODE 20_US \ n -- n * 20 us
144 BEGIN \ here we presume that LCD_TIM_IFG = 1...
146 BIT #1,&LCD_TIM_CTL \ 3
147 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
148 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
150 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
156 CODE TOP_LCD \ LCD Sample
157 \ \ if write : %xxxxWWWW --
158 \ \ if read : -- %0000RRRR
159 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
160 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
161 0= IF \ write LCD bits pattern
163 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
164 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
167 THEN \ read LCD bits pattern
170 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
171 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
177 CODE LCD_W \ byte -- write byte to LCD
179 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
180 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
181 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
182 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
183 COLON \ high level word starts here
184 TOP_LCD 2 20_US \ write high nibble first
189 CODE LCD_WrC \ char -- Write Char
190 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
195 CODE LCD_WrF \ func -- Write Fonction
196 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
202 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
207 $02 LCD_WrF 100 20_us
213 \ https://forth-standard.org/standard/core/OR
214 \ C OR x1 x2 -- x3 logical OR
223 : LCD_Entry_set $04 OR LCD_WrF ;
225 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
227 : LCD_DSP_Shift $10 OR LCD_WrF ;
229 : LCD_Fn_Set $20 OR LCD_WrF ;
231 : LCD_CGRAM_Set $40 OR LCD_WrF ;
233 : LCD_Goto $80 OR LCD_WrF ;
235 CODE LCD_R \ -- byte read byte from LCD
236 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
237 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
238 COLON \ starts a FORTH word
239 TOP_LCD 2 20_us \ -- %0000HHHH
240 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
241 HI2LO \ switch from FORTH to assembler
242 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
243 ADD.B @PSP+,TOS \ -- %HHHHLLLL
244 MOV @RSP+,IP \ restore IP saved by COLON
249 CODE LCD_RdS \ -- status Read Status
250 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
255 CODE LCD_RdC \ -- char Read Char
256 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
262 \ ******************************\
263 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
264 \ ******************************\
265 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
266 BIT.B #SW2,&SW2_IN \ test switch S2
267 0= IF \ case of switch S2 pressed
268 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
270 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
273 BIT.B #SW1,&SW1_IN \ test switch S1 input
274 0= IF \ case of Switch S1 pressed
275 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
277 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
281 BW1 \ from quit on truncated RC5 message
282 BW2 \ from repeated RC5 command
283 BW3 \ from end of RC5_INT
284 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
289 \ ******************************\
290 ASM RC5_INT \ wake up on Px.RC5 change interrupt
291 \ ******************************\
292 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
293 \ ******************************\
294 \ \ in : SR(9)=old Toggle bit memory (ADD on)
295 \ \ SMclock = 8|16|24 MHz
296 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
297 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
298 \ \ SR(9)=new Toggle bit memory (ADD on)
299 \ ******************************\
300 \ RC5_FirstStartBitHalfCycle: \
301 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
302 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
303 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
304 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
305 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
306 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
307 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
308 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
309 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
310 MOV #1778,X \ RC5_Period * 1us
311 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
312 MOV #14,W \ count of loop
314 \ ******************************\
315 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
316 \ ******************************\ |
317 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
318 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
319 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
320 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
321 \ RC5_Compute_3/4_Period: \ |
322 RRUM #1,X \ X=1/2 cycle |
325 ADD X,Y \ Y=3/4 cycle
326 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
328 \ ******************************\
329 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
330 \ ******************************\
331 BIT.B #RC5,&IR_IN \ C_flag = IR bit
332 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
333 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
334 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
335 SUB #1,W \ decrement count loop
336 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
337 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
338 0<> WHILE \ ----> out of loop ----+
339 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
341 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
342 CMP Y,X \ 1 | cycle time out of bound ?
344 BIC #$30,&RC5_TIM_CTL \ | | stop timer
345 GOTO BW1 \ | | quit on truncated RC5 message
347 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
349 REPEAT \ ----> loop back --+ | with X = new RC5_period value
350 \ ******************************\ |
351 \ RC5_SampleEndOf: \ <---------------------+
352 \ ******************************\
353 BIC #$30,&RC5_TIM_CTL \ stop timer
354 \ ******************************\
355 \ RC5_ComputeNewRC5word \
356 \ ******************************\
357 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
358 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
359 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
360 \ ******************************\
362 \ ******************************\
363 BIT #BIT14,T \ test /C6 bit in T
364 0= IF BIS #BIT6,X \ set C6 bit in X
365 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
366 \ ******************************\
367 \ RC5_CommandByteIsDone \ -- BASE RC5_code
368 \ ******************************\
369 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
370 \ ******************************\
371 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
372 XOR @RSP,T \ (new XOR old) Toggle bits
373 BIT #UF10,T \ repeated RC5_command ?
374 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
375 XOR #UF10,0(RSP) \ 5 toggle bit memory
376 \ ******************************\
377 \ Display IR_RC5 code \ X = RC5 code
378 \ ******************************\
380 MOV &BASE,2(PSP) \ save current base
381 MOV #$10,&BASE \ set hex base
382 MOV TOS,0(PSP) \ save TOS
384 LO2HI \ switch from assembler to FORTH
385 ['] LCD_CLEAR IS CR \ redirects CR
386 ['] LCD_WrC IS EMIT \ redirects EMIT
387 CR ." $" 2 U.R \ print IR_RC5 code
388 ['] CR >BODY IS CR \ restore CR
389 ['] EMIT >BODY IS EMIT \ restore EMIT
390 HI2LO \ switch from FORTH to assembler
391 MOV TOS,&BASE \ restore current BASE
393 \ ******************************\
395 \ ******************************\
399 \ ------------------------------\
401 \ ------------------------------\
402 \ ... \ insert here your background task
405 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
406 ADD #4,X \ 1 X = BODY of SLEEP
409 \ ------------------------------\
413 \ ------------------------------\
414 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
415 \ - - \CNTL Counter lentgh \ 00 = 16 bits
416 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
417 \ -- \ID input divider \ 10 = /4
418 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
419 \ - \TBCLR TimerB Clear
422 \ -------------------------------\
423 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
424 \ -- \CM Capture Mode
429 \ --- \OUTMOD \ 011 = set/reset
435 \ -------------------------------\
437 \ -------------------------------\
439 \ ------------------------------\
440 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
441 \ ------------------------------\
442 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
443 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
444 \ ------------------------------\
445 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
446 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
447 \ ------------------------------\
448 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
449 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
450 \ ------------------------------\
451 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
452 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
453 \ ------------------------------\
454 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
455 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
456 \ ------------------------------\
457 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
458 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
459 \ ------------------------------\
460 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
461 \ ------------------------------\
462 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
463 \ ------------------------------\
464 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
465 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
466 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
467 \ ------------------------------\
468 BIS.B #LCDVo,&LCDVo_DIR \
469 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
470 \ ------------------------------\
471 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
472 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
473 \ ------------------------------\
474 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
475 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
476 \ ******************************\
478 \ ******************************\
479 BIS.B #RC5,&IR_IE \ enable RC5_Int
480 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
481 MOV #RC5_INT,&IR_Vec \ init interrupt vector
482 \ ******************************\
483 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
484 \ ******************************\
485 \ %01 0001 0100 \ TAxCTL
486 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
487 \ -- \ ID divided by 1
488 \ -- \ MC MODE = up to TAxCCRn
489 \ - \ TACLR clear timer count
492 \ ------------------------------\
493 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
494 \ ------------------------------\
496 \ --- \ TAIDEX pre divisor
497 \ ------------------------------\
498 \ %0000 0000 0000 0101 \ TAxCCR0
499 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
500 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
501 \ ------------------------------\
502 \ %0000 0000 0001 0000 \ TAxCCTL0
503 \ - \ CAP capture/compare mode = compare
506 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
507 \ ------------------------------\
508 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
509 \ ------------------------------\
510 \ define LPM mode for ACCEPT \
511 \ ------------------------------\
512 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
513 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
514 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
516 \ ------------------------------\
517 \ redirects to background task \
518 \ ------------------------------\
520 MOV #BACKGROUND,2(X) \
521 \ ------------------------------\
523 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
525 \ ------------------------------\
527 \ ------------------------------\
528 $03E8 20_US \ 1- wait 20 ms
529 $03 TOP_LCD \ 2- send DB5=DB4=1
530 $CD 20_US \ 3- wait 4,1 ms
531 $03 TOP_LCD \ 4- send again DB5=DB4=1
532 $5 20_US \ 5- wait 0,1 ms
533 $03 TOP_LCD \ 6- send again again DB5=DB4=1
534 $2 20_US \ wait 40 us = LCD cycle
535 $02 TOP_LCD \ 7- send DB5=1 DB4=0
536 $2 20_US \ wait 40 us = LCD cycle
537 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
538 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
539 LCD_Clear \ 10- "LCD_Clear"
540 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
541 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
542 LCD_Clear \ 10- "LCD_Clear"
543 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
544 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
547 ['] EMIT >BODY IS EMIT \
548 ." RC5toLCD is running. Type STOP to quit"
549 LIT RECURSE IS WARM \ replace WARM by this START routine
550 ABORT \ and continue with the next word after WARM...
551 ; \ ...until interpreter falls in sleep mode within ACCEPT.
554 CODE STOP \ stops multitasking, must to be used before downloading app
555 \ restore default action of primary DEFERred word SLEEP, assembly version
556 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
557 ADD #4,X \ X = BODY of SLEEP
558 MOV X,-2(X) \ restore the default background
561 \ restore default action of primary DEFERred word WARM, FORTH version
562 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
564 COLD \ because we want to reset CPU and interrupt vectors
569 ; downloading RC5toLCD.4th is done
570 RST_HERE ; this app is protected against <reset>
578 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
580 [DEFINED] ASM [IF] \ security test
584 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
586 CODE MAX \ n1 n2 -- n3 signed maximum
594 CODE MIN \ n1 n2 -- n3 signed minimum
604 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
605 : U.R \ u n -- display u unsigned in n width (n >= 2)
607 R> OVER - 0 MAX SPACES TYPE
612 \ CODE 20_US \ n -- n * 20 us
613 \ BEGIN \ 3 cycles loop + 6~
614 \ \ MOV #5,W \ 3 MCLK = 1 MHz
615 \ \ MOV #23,W \ 3 MCLK = 4 MHz
616 \ \ MOV #51,W \ 3 MCLK = 8 MHz
617 \ MOV #104,W \ 3 MCLK = 16 MHz
618 \ \ MOV #158,W \ 3 MCLK = 24 MHz
619 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
629 CODE 20_US \ n -- n * 20 us
630 BEGIN \ here we presume that LCD_TIM_IFG = 1...
632 BIT #1,&LCD_TIM_CTL \ 3
633 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
634 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
636 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
642 CODE TOP_LCD \ LCD Sample
643 \ \ if write : %xxxxWWWW --
644 \ \ if read : -- %0000RRRR
645 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
646 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
647 0= IF \ write LCD bits pattern
649 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
650 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
653 THEN \ read LCD bits pattern
656 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
657 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
663 CODE LCD_W \ byte -- write byte to LCD
665 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
666 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
667 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
668 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
669 COLON \ high level word starts here
670 TOP_LCD 2 20_US \ write high nibble first
675 CODE LCD_WrC \ char -- Write Char
676 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
681 CODE LCD_WrF \ func -- Write Fonction
682 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
688 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
693 $02 LCD_WrF 100 20_us
699 \ https://forth-standard.org/standard/core/OR
700 \ C OR x1 x2 -- x3 logical OR
709 : LCD_Entry_set $04 OR LCD_WrF ;
711 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
713 : LCD_DSP_Shift $10 OR LCD_WrF ;
715 : LCD_Fn_Set $20 OR LCD_WrF ;
717 : LCD_CGRAM_Set $40 OR LCD_WrF ;
719 : LCD_Goto $80 OR LCD_WrF ;
721 CODE LCD_R \ -- byte read byte from LCD
722 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
723 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
724 COLON \ starts a FORTH word
725 TOP_LCD 2 20_us \ -- %0000HHHH
726 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
727 HI2LO \ switch from FORTH to assembler
728 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
729 ADD.B @PSP+,TOS \ -- %HHHHLLLL
730 MOV @RSP+,IP \ restore IP saved by COLON
735 CODE LCD_RdS \ -- status Read Status
736 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
741 CODE LCD_RdC \ -- char Read Char
742 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
748 \ ******************************\
749 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
750 \ ******************************\
751 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
752 BIT.B #SW2,&SW2_IN \ test switch S2
753 0= IF \ case of switch S2 pressed
754 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
756 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
759 BIT.B #SW1,&SW1_IN \ test switch S1 input
760 0= IF \ case of Switch S1 pressed
761 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
763 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
767 BW1 \ from quit on truncated RC5 message
768 BW2 \ from repeated RC5 command
769 BW3 \ from end of RC5_INT
770 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
775 \ ******************************\
776 ASM RC5_INT \ wake up on Px.RC5 change interrupt
777 \ ******************************\
778 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
779 \ ******************************\
780 \ \ in : SR(9)=old Toggle bit memory (ADD on)
781 \ \ SMclock = 8|16|24 MHz
782 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
783 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
784 \ \ SR(9)=new Toggle bit memory (ADD on)
785 \ ******************************\
786 \ RC5_FirstStartBitHalfCycle: \
787 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
788 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
789 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
790 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
791 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
792 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
793 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
794 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
795 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
796 MOV #1778,X \ RC5_Period * 1us
797 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
798 MOV #14,W \ count of loop
800 \ ******************************\
801 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
802 \ ******************************\ |
803 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
804 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
805 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
806 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
807 \ RC5_Compute_3/4_Period: \ |
808 RRUM #1,X \ X=1/2 cycle |
811 ADD X,Y \ Y=3/4 cycle
812 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
814 \ ******************************\
815 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
816 \ ******************************\
817 BIT.B #RC5,&IR_IN \ C_flag = IR bit
818 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
819 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
820 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
821 SUB #1,W \ decrement count loop
822 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
823 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
824 0<> WHILE \ ----> out of loop ----+
825 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
827 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
828 CMP Y,X \ 1 | cycle time out of bound ?
830 BIC #$30,&RC5_TIM_CTL \ | | stop timer
831 GOTO BW1 \ | | quit on truncated RC5 message
833 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
835 REPEAT \ ----> loop back --+ | with X = new RC5_period value
836 \ ******************************\ |
837 \ RC5_SampleEndOf: \ <---------------------+
838 \ ******************************\
839 BIC #$30,&RC5_TIM_CTL \ stop timer
840 \ ******************************\
841 \ RC5_ComputeNewRC5word \
842 \ ******************************\
843 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
844 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
845 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
846 \ ******************************\
848 \ ******************************\
849 BIT #BIT14,T \ test /C6 bit in T
850 0= IF BIS #BIT6,X \ set C6 bit in X
851 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
852 \ ******************************\
853 \ RC5_CommandByteIsDone \ -- BASE RC5_code
854 \ ******************************\
855 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
856 \ ******************************\
857 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
858 XOR @RSP,T \ (new XOR old) Toggle bits
859 BIT #UF10,T \ repeated RC5_command ?
860 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
861 XOR #UF10,0(RSP) \ 5 toggle bit memory
862 \ ******************************\
863 \ Display IR_RC5 code \ X = RC5 code
864 \ ******************************\
866 MOV &BASE,2(PSP) \ save current base
867 MOV #$10,&BASE \ set hex base
868 MOV TOS,0(PSP) \ save TOS
870 LO2HI \ switch from assembler to FORTH
871 ['] LCD_CLEAR IS CR \ redirects CR
872 ['] LCD_WrC IS EMIT \ redirects EMIT
873 CR ." $" 2 U.R \ print IR_RC5 code
874 ['] CR >BODY IS CR \ restore CR
875 ['] EMIT >BODY IS EMIT \ restore EMIT
876 HI2LO \ switch from FORTH to assembler
877 MOV TOS,&BASE \ restore current BASE
879 \ ******************************\
881 \ ******************************\
885 \ ------------------------------\
887 \ ------------------------------\
888 \ ... \ insert here your background task
891 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
892 ADD #4,X \ 1 X = BODY of SLEEP
895 \ ------------------------------\
899 \ ------------------------------\
900 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
901 \ - - \CNTL Counter lentgh \ 00 = 16 bits
902 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
903 \ -- \ID input divider \ 10 = /4
904 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
905 \ - \TBCLR TimerB Clear
908 \ -------------------------------\
909 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
910 \ -- \CM Capture Mode
915 \ --- \OUTMOD \ 011 = set/reset
921 \ -------------------------------\
923 \ -------------------------------\
925 \ ------------------------------\
926 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
927 \ ------------------------------\
928 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
929 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
930 \ ------------------------------\
931 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
932 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
933 \ ------------------------------\
934 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
935 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
936 \ ------------------------------\
937 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
938 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
939 \ ------------------------------\
940 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
941 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
942 \ ------------------------------\
943 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
944 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
945 \ ------------------------------\
946 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
947 \ ------------------------------\
948 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
949 \ ------------------------------\
950 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
951 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
952 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
953 \ ------------------------------\
954 BIS.B #LCDVo,&LCDVo_DIR \
955 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
956 \ ------------------------------\
957 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
958 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
959 \ ------------------------------\
960 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
961 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
962 \ ******************************\
964 \ ******************************\
965 BIS.B #RC5,&IR_IE \ enable RC5_Int
966 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
967 MOV #RC5_INT,&IR_Vec \ init interrupt vector
968 \ ******************************\
969 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
970 \ ******************************\
971 \ %01 0001 0100 \ TAxCTL
972 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
973 \ -- \ ID divided by 1
974 \ -- \ MC MODE = up to TAxCCRn
975 \ - \ TACLR clear timer count
978 \ ------------------------------\
979 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
980 \ ------------------------------\
982 \ --- \ TAIDEX pre divisor
983 \ ------------------------------\
984 \ %0000 0000 0000 0101 \ TAxCCR0
985 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
986 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
987 \ ------------------------------\
988 \ %0000 0000 0001 0000 \ TAxCCTL0
989 \ - \ CAP capture/compare mode = compare
992 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
993 \ ------------------------------\
994 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
995 \ ------------------------------\
996 \ define LPM mode for ACCEPT \
997 \ ------------------------------\
998 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
999 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1000 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1002 \ ------------------------------\
1003 \ redirects to background task \
1004 \ ------------------------------\
1006 MOV #BACKGROUND,2(X) \
1007 \ ------------------------------\
1009 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
1011 \ ------------------------------\
1013 \ ------------------------------\
1014 $03E8 20_US \ 1- wait 20 ms
1015 $03 TOP_LCD \ 2- send DB5=DB4=1
1016 $CD 20_US \ 3- wait 4,1 ms
1017 $03 TOP_LCD \ 4- send again DB5=DB4=1
1018 $5 20_US \ 5- wait 0,1 ms
1019 $03 TOP_LCD \ 6- send again again DB5=DB4=1
1020 $2 20_US \ wait 40 us = LCD cycle
1021 $02 TOP_LCD \ 7- send DB5=1 DB4=0
1022 $2 20_US \ wait 40 us = LCD cycle
1023 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
1024 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
1025 LCD_Clear \ 10- "LCD_Clear"
1026 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
1027 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
1028 LCD_Clear \ 10- "LCD_Clear"
1029 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
1030 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
1032 ['] CR >BODY IS CR \
1033 ['] EMIT >BODY IS EMIT \
1034 ." RC5toLCD is running. Type STOP to quit"
1035 LIT RECURSE IS WARM \ replace WARM by this START routine
1036 ABORT \ and continue with the next word after WARM...
1037 ; \ ...until interpreter falls in sleep mode within ACCEPT.
1040 CODE STOP \ stops multitasking, must to be used before downloading app
1041 \ restore default action of primary DEFERred word SLEEP, assembly version
1042 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
1043 ADD #4,X \ X = BODY of SLEEP
1044 MOV X,-2(X) \ restore the default background
1047 \ restore default action of primary DEFERred word WARM, FORTH version
1048 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
1050 COLD \ because we want to reset CPU and interrupt vectors
1055 ; downloading RC5toLCD.4th is done
1056 RST_HERE ; this app is protected against <reset>
1064 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
1066 [DEFINED] ASM [IF] \ security test
1070 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
1072 CODE MAX \ n1 n2 -- n3 signed maximum
1073 CMP @PSP,TOS \ n2-n1
1074 S< ?GOTO FW1 \ n2<n1
1080 CODE MIN \ n1 n2 -- n3 signed minimum
1081 CMP @PSP,TOS \ n2-n1
1082 S< ?GOTO BW1 \ n2<n1
1090 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
1091 : U.R \ u n -- display u unsigned in n width (n >= 2)
1093 R> OVER - 0 MAX SPACES TYPE
1098 \ CODE 20_US \ n -- n * 20 us
1099 \ BEGIN \ 3 cycles loop + 6~
1100 \ \ MOV #5,W \ 3 MCLK = 1 MHz
1101 \ \ MOV #23,W \ 3 MCLK = 4 MHz
1102 \ \ MOV #51,W \ 3 MCLK = 8 MHz
1103 \ MOV #104,W \ 3 MCLK = 16 MHz
1104 \ \ MOV #158,W \ 3 MCLK = 24 MHz
1105 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
1115 CODE 20_US \ n -- n * 20 us
1116 BEGIN \ here we presume that LCD_TIM_IFG = 1...
1118 BIT #1,&LCD_TIM_CTL \ 3
1119 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
1120 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
1122 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
1128 CODE TOP_LCD \ LCD Sample
1129 \ \ if write : %xxxxWWWW --
1130 \ \ if read : -- %0000RRRR
1131 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
1132 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
1133 0= IF \ write LCD bits pattern
1135 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
1136 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
1139 THEN \ read LCD bits pattern
1142 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
1143 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
1149 CODE LCD_W \ byte -- write byte to LCD
1151 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
1152 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
1153 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
1154 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
1155 COLON \ high level word starts here
1156 TOP_LCD 2 20_US \ write high nibble first
1161 CODE LCD_WrC \ char -- Write Char
1162 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
1167 CODE LCD_WrF \ func -- Write Fonction
1168 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
1174 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
1179 $02 LCD_WrF 100 20_us
1185 \ https://forth-standard.org/standard/core/OR
1186 \ C OR x1 x2 -- x3 logical OR
1195 : LCD_Entry_set $04 OR LCD_WrF ;
1197 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
1199 : LCD_DSP_Shift $10 OR LCD_WrF ;
1201 : LCD_Fn_Set $20 OR LCD_WrF ;
1203 : LCD_CGRAM_Set $40 OR LCD_WrF ;
1205 : LCD_Goto $80 OR LCD_WrF ;
1207 CODE LCD_R \ -- byte read byte from LCD
1208 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
1209 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
1210 COLON \ starts a FORTH word
1211 TOP_LCD 2 20_us \ -- %0000HHHH
1212 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
1213 HI2LO \ switch from FORTH to assembler
1214 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
1215 ADD.B @PSP+,TOS \ -- %HHHHLLLL
1216 MOV @RSP+,IP \ restore IP saved by COLON
1221 CODE LCD_RdS \ -- status Read Status
1222 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
1227 CODE LCD_RdC \ -- char Read Char
1228 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
1234 \ ******************************\
1235 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
1236 \ ******************************\
1237 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
1238 BIT.B #SW2,&SW2_IN \ test switch S2
1239 0= IF \ case of switch S2 pressed
1240 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
1242 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
1245 BIT.B #SW1,&SW1_IN \ test switch S1 input
1246 0= IF \ case of Switch S1 pressed
1247 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
1249 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
1253 BW1 \ from quit on truncated RC5 message
1254 BW2 \ from repeated RC5 command
1255 BW3 \ from end of RC5_INT
1256 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
1261 \ ******************************\
1262 ASM RC5_INT \ wake up on Px.RC5 change interrupt
1263 \ ******************************\
1264 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
1265 \ ******************************\
1266 \ \ in : SR(9)=old Toggle bit memory (ADD on)
1267 \ \ SMclock = 8|16|24 MHz
1268 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
1269 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
1270 \ \ SR(9)=new Toggle bit memory (ADD on)
1271 \ ******************************\
1272 \ RC5_FirstStartBitHalfCycle: \
1273 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
1274 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
1275 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
1276 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
1277 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
1278 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
1279 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
1280 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
1281 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
1282 MOV #1778,X \ RC5_Period * 1us
1283 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
1284 MOV #14,W \ count of loop
1286 \ ******************************\
1287 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
1288 \ ******************************\ |
1289 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
1290 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
1291 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
1292 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
1293 \ RC5_Compute_3/4_Period: \ |
1294 RRUM #1,X \ X=1/2 cycle |
1297 ADD X,Y \ Y=3/4 cycle
1298 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
1300 \ ******************************\
1301 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
1302 \ ******************************\
1303 BIT.B #RC5,&IR_IN \ C_flag = IR bit
1304 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
1305 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
1306 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
1307 SUB #1,W \ decrement count loop
1308 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
1309 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
1310 0<> WHILE \ ----> out of loop ----+
1311 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
1313 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
1314 CMP Y,X \ 1 | cycle time out of bound ?
1316 BIC #$30,&RC5_TIM_CTL \ | | stop timer
1317 GOTO BW1 \ | | quit on truncated RC5 message
1319 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
1321 REPEAT \ ----> loop back --+ | with X = new RC5_period value
1322 \ ******************************\ |
1323 \ RC5_SampleEndOf: \ <---------------------+
1324 \ ******************************\
1325 BIC #$30,&RC5_TIM_CTL \ stop timer
1326 \ ******************************\
1327 \ RC5_ComputeNewRC5word \
1328 \ ******************************\
1329 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
1330 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
1331 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
1332 \ ******************************\
1333 \ RC5_ComputeC6bit \
1334 \ ******************************\
1335 BIT #BIT14,T \ test /C6 bit in T
1336 0= IF BIS #BIT6,X \ set C6 bit in X
1337 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
1338 \ ******************************\
1339 \ RC5_CommandByteIsDone \ -- BASE RC5_code
1340 \ ******************************\
1341 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
1342 \ ******************************\
1343 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
1344 XOR @RSP,T \ (new XOR old) Toggle bits
1345 BIT #UF10,T \ repeated RC5_command ?
1346 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
1347 XOR #UF10,0(RSP) \ 5 toggle bit memory
1348 \ ******************************\
1349 \ Display IR_RC5 code \ X = RC5 code
1350 \ ******************************\
1352 MOV &BASE,2(PSP) \ save current base
1353 MOV #$10,&BASE \ set hex base
1354 MOV TOS,0(PSP) \ save TOS
1356 LO2HI \ switch from assembler to FORTH
1357 ['] LCD_CLEAR IS CR \ redirects CR
1358 ['] LCD_WrC IS EMIT \ redirects EMIT
1359 CR ." $" 2 U.R \ print IR_RC5 code
1360 ['] CR >BODY IS CR \ restore CR
1361 ['] EMIT >BODY IS EMIT \ restore EMIT
1362 HI2LO \ switch from FORTH to assembler
1363 MOV TOS,&BASE \ restore current BASE
1365 \ ******************************\
1367 \ ******************************\
1371 \ ------------------------------\
1373 \ ------------------------------\
1374 \ ... \ insert here your background task
1377 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
1378 ADD #4,X \ 1 X = BODY of SLEEP
1381 \ ------------------------------\
1385 \ ------------------------------\
1386 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
1387 \ - - \CNTL Counter lentgh \ 00 = 16 bits
1388 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
1389 \ -- \ID input divider \ 10 = /4
1390 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
1391 \ - \TBCLR TimerB Clear
1394 \ -------------------------------\
1395 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
1396 \ -- \CM Capture Mode
1401 \ --- \OUTMOD \ 011 = set/reset
1407 \ -------------------------------\
1409 \ -------------------------------\
1411 \ ------------------------------\
1412 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
1413 \ ------------------------------\
1414 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
1415 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
1416 \ ------------------------------\
1417 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
1418 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
1419 \ ------------------------------\
1420 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
1421 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
1422 \ ------------------------------\
1423 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
1424 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
1425 \ ------------------------------\
1426 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
1427 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
1428 \ ------------------------------\
1429 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
1430 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
1431 \ ------------------------------\
1432 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
1433 \ ------------------------------\
1434 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
1435 \ ------------------------------\
1436 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
1437 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
1438 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
1439 \ ------------------------------\
1440 BIS.B #LCDVo,&LCDVo_DIR \
1441 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
1442 \ ------------------------------\
1443 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
1444 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
1445 \ ------------------------------\
1446 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
1447 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
1448 \ ******************************\
1450 \ ******************************\
1451 BIS.B #RC5,&IR_IE \ enable RC5_Int
1452 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
1453 MOV #RC5_INT,&IR_Vec \ init interrupt vector
1454 \ ******************************\
1455 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
1456 \ ******************************\
1457 \ %01 0001 0100 \ TAxCTL
1458 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
1459 \ -- \ ID divided by 1
1460 \ -- \ MC MODE = up to TAxCCRn
1461 \ - \ TACLR clear timer count
1464 \ ------------------------------\
1465 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
1466 \ ------------------------------\
1468 \ --- \ TAIDEX pre divisor
1469 \ ------------------------------\
1470 \ %0000 0000 0000 0101 \ TAxCCR0
1471 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
1472 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
1473 \ ------------------------------\
1474 \ %0000 0000 0001 0000 \ TAxCCTL0
1475 \ - \ CAP capture/compare mode = compare
1478 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
1479 \ ------------------------------\
1480 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
1481 \ ------------------------------\
1482 \ define LPM mode for ACCEPT \
1483 \ ------------------------------\
1484 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
1485 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1486 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1488 \ ------------------------------\
1489 \ redirects to background task \
1490 \ ------------------------------\
1492 MOV #BACKGROUND,2(X) \
1493 \ ------------------------------\
1495 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
1497 \ ------------------------------\
1499 \ ------------------------------\
1500 $03E8 20_US \ 1- wait 20 ms
1501 $03 TOP_LCD \ 2- send DB5=DB4=1
1502 $CD 20_US \ 3- wait 4,1 ms
1503 $03 TOP_LCD \ 4- send again DB5=DB4=1
1504 $5 20_US \ 5- wait 0,1 ms
1505 $03 TOP_LCD \ 6- send again again DB5=DB4=1
1506 $2 20_US \ wait 40 us = LCD cycle
1507 $02 TOP_LCD \ 7- send DB5=1 DB4=0
1508 $2 20_US \ wait 40 us = LCD cycle
1509 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
1510 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
1511 LCD_Clear \ 10- "LCD_Clear"
1512 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
1513 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
1514 LCD_Clear \ 10- "LCD_Clear"
1515 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
1516 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
1518 ['] CR >BODY IS CR \
1519 ['] EMIT >BODY IS EMIT \
1520 ." RC5toLCD is running. Type STOP to quit"
1521 LIT RECURSE IS WARM \ replace WARM by this START routine
1522 ABORT \ and continue with the next word after WARM...
1523 ; \ ...until interpreter falls in sleep mode within ACCEPT.
1526 CODE STOP \ stops multitasking, must to be used before downloading app
1527 \ restore default action of primary DEFERred word SLEEP, assembly version
1528 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
1529 ADD #4,X \ X = BODY of SLEEP
1530 MOV X,-2(X) \ restore the default background
1533 \ restore default action of primary DEFERred word WARM, FORTH version
1534 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
1536 COLD \ because we want to reset CPU and interrupt vectors
1541 ; downloading RC5toLCD.4th is done
1542 RST_HERE ; this app is protected against <reset>
1550 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
1552 [DEFINED] ASM [IF] \ security test
1556 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
1558 CODE MAX \ n1 n2 -- n3 signed maximum
1559 CMP @PSP,TOS \ n2-n1
1560 S< ?GOTO FW1 \ n2<n1
1566 CODE MIN \ n1 n2 -- n3 signed minimum
1567 CMP @PSP,TOS \ n2-n1
1568 S< ?GOTO BW1 \ n2<n1
1576 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
1577 : U.R \ u n -- display u unsigned in n width (n >= 2)
1579 R> OVER - 0 MAX SPACES TYPE
1584 \ CODE 20_US \ n -- n * 20 us
1585 \ BEGIN \ 3 cycles loop + 6~
1586 \ \ MOV #5,W \ 3 MCLK = 1 MHz
1587 \ \ MOV #23,W \ 3 MCLK = 4 MHz
1588 \ \ MOV #51,W \ 3 MCLK = 8 MHz
1589 \ MOV #104,W \ 3 MCLK = 16 MHz
1590 \ \ MOV #158,W \ 3 MCLK = 24 MHz
1591 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
1601 CODE 20_US \ n -- n * 20 us
1602 BEGIN \ here we presume that LCD_TIM_IFG = 1...
1604 BIT #1,&LCD_TIM_CTL \ 3
1605 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
1606 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
1608 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
1614 CODE TOP_LCD \ LCD Sample
1615 \ \ if write : %xxxxWWWW --
1616 \ \ if read : -- %0000RRRR
1617 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
1618 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
1619 0= IF \ write LCD bits pattern
1621 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
1622 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
1625 THEN \ read LCD bits pattern
1628 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
1629 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
1635 CODE LCD_W \ byte -- write byte to LCD
1637 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
1638 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
1639 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
1640 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
1641 COLON \ high level word starts here
1642 TOP_LCD 2 20_US \ write high nibble first
1647 CODE LCD_WrC \ char -- Write Char
1648 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
1653 CODE LCD_WrF \ func -- Write Fonction
1654 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
1660 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
1665 $02 LCD_WrF 100 20_us
1671 \ https://forth-standard.org/standard/core/OR
1672 \ C OR x1 x2 -- x3 logical OR
1681 : LCD_Entry_set $04 OR LCD_WrF ;
1683 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
1685 : LCD_DSP_Shift $10 OR LCD_WrF ;
1687 : LCD_Fn_Set $20 OR LCD_WrF ;
1689 : LCD_CGRAM_Set $40 OR LCD_WrF ;
1691 : LCD_Goto $80 OR LCD_WrF ;
1693 CODE LCD_R \ -- byte read byte from LCD
1694 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
1695 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
1696 COLON \ starts a FORTH word
1697 TOP_LCD 2 20_us \ -- %0000HHHH
1698 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
1699 HI2LO \ switch from FORTH to assembler
1700 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
1701 ADD.B @PSP+,TOS \ -- %HHHHLLLL
1702 MOV @RSP+,IP \ restore IP saved by COLON
1707 CODE LCD_RdS \ -- status Read Status
1708 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
1713 CODE LCD_RdC \ -- char Read Char
1714 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
1720 \ ******************************\
1721 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
1722 \ ******************************\
1723 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
1724 BIT.B #SW2,&SW2_IN \ test switch S2
1725 0= IF \ case of switch S2 pressed
1726 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
1728 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
1731 BIT.B #SW1,&SW1_IN \ test switch S1 input
1732 0= IF \ case of Switch S1 pressed
1733 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
1735 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
1739 BW1 \ from quit on truncated RC5 message
1740 BW2 \ from repeated RC5 command
1741 BW3 \ from end of RC5_INT
1742 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
1747 \ ******************************\
1748 ASM RC5_INT \ wake up on Px.RC5 change interrupt
1749 \ ******************************\
1750 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
1751 \ ******************************\
1752 \ \ in : SR(9)=old Toggle bit memory (ADD on)
1753 \ \ SMclock = 8|16|24 MHz
1754 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
1755 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
1756 \ \ SR(9)=new Toggle bit memory (ADD on)
1757 \ ******************************\
1758 \ RC5_FirstStartBitHalfCycle: \
1759 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
1760 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
1761 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
1762 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
1763 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
1764 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
1765 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
1766 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
1767 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
1768 MOV #1778,X \ RC5_Period * 1us
1769 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
1770 MOV #14,W \ count of loop
1772 \ ******************************\
1773 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
1774 \ ******************************\ |
1775 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
1776 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
1777 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
1778 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
1779 \ RC5_Compute_3/4_Period: \ |
1780 RRUM #1,X \ X=1/2 cycle |
1783 ADD X,Y \ Y=3/4 cycle
1784 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
1786 \ ******************************\
1787 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
1788 \ ******************************\
1789 BIT.B #RC5,&IR_IN \ C_flag = IR bit
1790 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
1791 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
1792 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
1793 SUB #1,W \ decrement count loop
1794 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
1795 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
1796 0<> WHILE \ ----> out of loop ----+
1797 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
1799 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
1800 CMP Y,X \ 1 | cycle time out of bound ?
1802 BIC #$30,&RC5_TIM_CTL \ | | stop timer
1803 GOTO BW1 \ | | quit on truncated RC5 message
1805 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
1807 REPEAT \ ----> loop back --+ | with X = new RC5_period value
1808 \ ******************************\ |
1809 \ RC5_SampleEndOf: \ <---------------------+
1810 \ ******************************\
1811 BIC #$30,&RC5_TIM_CTL \ stop timer
1812 \ ******************************\
1813 \ RC5_ComputeNewRC5word \
1814 \ ******************************\
1815 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
1816 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
1817 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
1818 \ ******************************\
1819 \ RC5_ComputeC6bit \
1820 \ ******************************\
1821 BIT #BIT14,T \ test /C6 bit in T
1822 0= IF BIS #BIT6,X \ set C6 bit in X
1823 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
1824 \ ******************************\
1825 \ RC5_CommandByteIsDone \ -- BASE RC5_code
1826 \ ******************************\
1827 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
1828 \ ******************************\
1829 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
1830 XOR @RSP,T \ (new XOR old) Toggle bits
1831 BIT #UF10,T \ repeated RC5_command ?
1832 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
1833 XOR #UF10,0(RSP) \ 5 toggle bit memory
1834 \ ******************************\
1835 \ Display IR_RC5 code \ X = RC5 code
1836 \ ******************************\
1838 MOV &BASE,2(PSP) \ save current base
1839 MOV #$10,&BASE \ set hex base
1840 MOV TOS,0(PSP) \ save TOS
1842 LO2HI \ switch from assembler to FORTH
1843 ['] LCD_CLEAR IS CR \ redirects CR
1844 ['] LCD_WrC IS EMIT \ redirects EMIT
1845 CR ." $" 2 U.R \ print IR_RC5 code
1846 ['] CR >BODY IS CR \ restore CR
1847 ['] EMIT >BODY IS EMIT \ restore EMIT
1848 HI2LO \ switch from FORTH to assembler
1849 MOV TOS,&BASE \ restore current BASE
1851 \ ******************************\
1853 \ ******************************\
1857 \ ------------------------------\
1859 \ ------------------------------\
1860 \ ... \ insert here your background task
1863 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
1864 ADD #4,X \ 1 X = BODY of SLEEP
1867 \ ------------------------------\
1871 \ ------------------------------\
1872 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
1873 \ - - \CNTL Counter lentgh \ 00 = 16 bits
1874 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
1875 \ -- \ID input divider \ 10 = /4
1876 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
1877 \ - \TBCLR TimerB Clear
1880 \ -------------------------------\
1881 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
1882 \ -- \CM Capture Mode
1887 \ --- \OUTMOD \ 011 = set/reset
1893 \ -------------------------------\
1895 \ -------------------------------\
1897 \ ------------------------------\
1898 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
1899 \ ------------------------------\
1900 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
1901 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
1902 \ ------------------------------\
1903 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
1904 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
1905 \ ------------------------------\
1906 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
1907 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
1908 \ ------------------------------\
1909 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
1910 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
1911 \ ------------------------------\
1912 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
1913 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
1914 \ ------------------------------\
1915 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
1916 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
1917 \ ------------------------------\
1918 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
1919 \ ------------------------------\
1920 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
1921 \ ------------------------------\
1922 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
1923 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
1924 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
1925 \ ------------------------------\
1926 BIS.B #LCDVo,&LCDVo_DIR \
1927 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
1928 \ ------------------------------\
1929 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
1930 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
1931 \ ------------------------------\
1932 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
1933 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
1934 \ ******************************\
1936 \ ******************************\
1937 BIS.B #RC5,&IR_IE \ enable RC5_Int
1938 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
1939 MOV #RC5_INT,&IR_Vec \ init interrupt vector
1940 \ ******************************\
1941 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
1942 \ ******************************\
1943 \ %01 0001 0100 \ TAxCTL
1944 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
1945 \ -- \ ID divided by 1
1946 \ -- \ MC MODE = up to TAxCCRn
1947 \ - \ TACLR clear timer count
1950 \ ------------------------------\
1951 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
1952 \ ------------------------------\
1954 \ --- \ TAIDEX pre divisor
1955 \ ------------------------------\
1956 \ %0000 0000 0000 0101 \ TAxCCR0
1957 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
1958 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
1959 \ ------------------------------\
1960 \ %0000 0000 0001 0000 \ TAxCCTL0
1961 \ - \ CAP capture/compare mode = compare
1964 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
1965 \ ------------------------------\
1966 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
1967 \ ------------------------------\
1968 \ define LPM mode for ACCEPT \
1969 \ ------------------------------\
1970 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
1971 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1972 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1974 \ ------------------------------\
1975 \ redirects to background task \
1976 \ ------------------------------\
1978 MOV #BACKGROUND,2(X) \
1979 \ ------------------------------\
1981 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
1983 \ ------------------------------\
1985 \ ------------------------------\
1986 $03E8 20_US \ 1- wait 20 ms
1987 $03 TOP_LCD \ 2- send DB5=DB4=1
1988 $CD 20_US \ 3- wait 4,1 ms
1989 $03 TOP_LCD \ 4- send again DB5=DB4=1
1990 $5 20_US \ 5- wait 0,1 ms
1991 $03 TOP_LCD \ 6- send again again DB5=DB4=1
1992 $2 20_US \ wait 40 us = LCD cycle
1993 $02 TOP_LCD \ 7- send DB5=1 DB4=0
1994 $2 20_US \ wait 40 us = LCD cycle
1995 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
1996 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
1997 LCD_Clear \ 10- "LCD_Clear"
1998 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
1999 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
2000 LCD_Clear \ 10- "LCD_Clear"
2001 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
2002 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
2004 ['] CR >BODY IS CR \
2005 ['] EMIT >BODY IS EMIT \
2006 ." RC5toLCD is running. Type STOP to quit"
2007 LIT RECURSE IS WARM \ replace WARM by this START routine
2008 ABORT \ and continue with the next word after WARM...
2009 ; \ ...until interpreter falls in sleep mode within ACCEPT.
2012 CODE STOP \ stops multitasking, must to be used before downloading app
2013 \ restore default action of primary DEFERred word SLEEP, assembly version
2014 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
2015 ADD #4,X \ X = BODY of SLEEP
2016 MOV X,-2(X) \ restore the default background
2019 \ restore default action of primary DEFERred word WARM, FORTH version
2020 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
2022 COLD \ because we want to reset CPU and interrupt vectors
2027 ; downloading RC5toLCD.4th is done
2028 RST_HERE ; this app is protected against <reset>
2036 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
2038 [DEFINED] ASM [IF] \ security test
2042 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
2044 CODE MAX \ n1 n2 -- n3 signed maximum
2045 CMP @PSP,TOS \ n2-n1
2046 S< ?GOTO FW1 \ n2<n1
2052 CODE MIN \ n1 n2 -- n3 signed minimum
2053 CMP @PSP,TOS \ n2-n1
2054 S< ?GOTO BW1 \ n2<n1
2062 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
2063 : U.R \ u n -- display u unsigned in n width (n >= 2)
2065 R> OVER - 0 MAX SPACES TYPE
2070 \ CODE 20_US \ n -- n * 20 us
2071 \ BEGIN \ 3 cycles loop + 6~
2072 \ \ MOV #5,W \ 3 MCLK = 1 MHz
2073 \ \ MOV #23,W \ 3 MCLK = 4 MHz
2074 \ \ MOV #51,W \ 3 MCLK = 8 MHz
2075 \ MOV #104,W \ 3 MCLK = 16 MHz
2076 \ \ MOV #158,W \ 3 MCLK = 24 MHz
2077 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
2087 CODE 20_US \ n -- n * 20 us
2088 BEGIN \ here we presume that LCD_TIM_IFG = 1...
2090 BIT #1,&LCD_TIM_CTL \ 3
2091 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
2092 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
2094 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
2100 CODE TOP_LCD \ LCD Sample
2101 \ \ if write : %xxxxWWWW --
2102 \ \ if read : -- %0000RRRR
2103 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
2104 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
2105 0= IF \ write LCD bits pattern
2107 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
2108 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
2111 THEN \ read LCD bits pattern
2114 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
2115 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
2121 CODE LCD_W \ byte -- write byte to LCD
2123 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
2124 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
2125 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
2126 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
2127 COLON \ high level word starts here
2128 TOP_LCD 2 20_US \ write high nibble first
2133 CODE LCD_WrC \ char -- Write Char
2134 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
2139 CODE LCD_WrF \ func -- Write Fonction
2140 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
2146 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
2151 $02 LCD_WrF 100 20_us
2157 \ https://forth-standard.org/standard/core/OR
2158 \ C OR x1 x2 -- x3 logical OR
2167 : LCD_Entry_set $04 OR LCD_WrF ;
2169 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
2171 : LCD_DSP_Shift $10 OR LCD_WrF ;
2173 : LCD_Fn_Set $20 OR LCD_WrF ;
2175 : LCD_CGRAM_Set $40 OR LCD_WrF ;
2177 : LCD_Goto $80 OR LCD_WrF ;
2179 CODE LCD_R \ -- byte read byte from LCD
2180 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
2181 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
2182 COLON \ starts a FORTH word
2183 TOP_LCD 2 20_us \ -- %0000HHHH
2184 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
2185 HI2LO \ switch from FORTH to assembler
2186 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
2187 ADD.B @PSP+,TOS \ -- %HHHHLLLL
2188 MOV @RSP+,IP \ restore IP saved by COLON
2193 CODE LCD_RdS \ -- status Read Status
2194 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
2199 CODE LCD_RdC \ -- char Read Char
2200 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
2206 \ ******************************\
2207 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
2208 \ ******************************\
2209 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
2210 BIT.B #SW2,&SW2_IN \ test switch S2
2211 0= IF \ case of switch S2 pressed
2212 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
2214 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
2217 BIT.B #SW1,&SW1_IN \ test switch S1 input
2218 0= IF \ case of Switch S1 pressed
2219 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
2221 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
2225 BW1 \ from quit on truncated RC5 message
2226 BW2 \ from repeated RC5 command
2227 BW3 \ from end of RC5_INT
2228 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
2233 \ ******************************\
2234 ASM RC5_INT \ wake up on Px.RC5 change interrupt
2235 \ ******************************\
2236 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
2237 \ ******************************\
2238 \ \ in : SR(9)=old Toggle bit memory (ADD on)
2239 \ \ SMclock = 8|16|24 MHz
2240 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
2241 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
2242 \ \ SR(9)=new Toggle bit memory (ADD on)
2243 \ ******************************\
2244 \ RC5_FirstStartBitHalfCycle: \
2245 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
2246 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
2247 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
2248 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
2249 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
2250 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
2251 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
2252 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
2253 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
2254 MOV #1778,X \ RC5_Period * 1us
2255 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
2256 MOV #14,W \ count of loop
2258 \ ******************************\
2259 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
2260 \ ******************************\ |
2261 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
2262 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
2263 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
2264 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
2265 \ RC5_Compute_3/4_Period: \ |
2266 RRUM #1,X \ X=1/2 cycle |
2269 ADD X,Y \ Y=3/4 cycle
2270 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
2272 \ ******************************\
2273 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
2274 \ ******************************\
2275 BIT.B #RC5,&IR_IN \ C_flag = IR bit
2276 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
2277 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
2278 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
2279 SUB #1,W \ decrement count loop
2280 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
2281 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
2282 0<> WHILE \ ----> out of loop ----+
2283 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
2285 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
2286 CMP Y,X \ 1 | cycle time out of bound ?
2288 BIC #$30,&RC5_TIM_CTL \ | | stop timer
2289 GOTO BW1 \ | | quit on truncated RC5 message
2291 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
2293 REPEAT \ ----> loop back --+ | with X = new RC5_period value
2294 \ ******************************\ |
2295 \ RC5_SampleEndOf: \ <---------------------+
2296 \ ******************************\
2297 BIC #$30,&RC5_TIM_CTL \ stop timer
2298 \ ******************************\
2299 \ RC5_ComputeNewRC5word \
2300 \ ******************************\
2301 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
2302 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
2303 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
2304 \ ******************************\
2305 \ RC5_ComputeC6bit \
2306 \ ******************************\
2307 BIT #BIT14,T \ test /C6 bit in T
2308 0= IF BIS #BIT6,X \ set C6 bit in X
2309 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
2310 \ ******************************\
2311 \ RC5_CommandByteIsDone \ -- BASE RC5_code
2312 \ ******************************\
2313 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
2314 \ ******************************\
2315 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
2316 XOR @RSP,T \ (new XOR old) Toggle bits
2317 BIT #UF10,T \ repeated RC5_command ?
2318 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
2319 XOR #UF10,0(RSP) \ 5 toggle bit memory
2320 \ ******************************\
2321 \ Display IR_RC5 code \ X = RC5 code
2322 \ ******************************\
2324 MOV &BASE,2(PSP) \ save current base
2325 MOV #$10,&BASE \ set hex base
2326 MOV TOS,0(PSP) \ save TOS
2328 LO2HI \ switch from assembler to FORTH
2329 ['] LCD_CLEAR IS CR \ redirects CR
2330 ['] LCD_WrC IS EMIT \ redirects EMIT
2331 CR ." $" 2 U.R \ print IR_RC5 code
2332 ['] CR >BODY IS CR \ restore CR
2333 ['] EMIT >BODY IS EMIT \ restore EMIT
2334 HI2LO \ switch from FORTH to assembler
2335 MOV TOS,&BASE \ restore current BASE
2337 \ ******************************\
2339 \ ******************************\
2343 \ ------------------------------\
2345 \ ------------------------------\
2346 \ ... \ insert here your background task
2349 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
2350 ADD #4,X \ 1 X = BODY of SLEEP
2353 \ ------------------------------\
2357 \ ------------------------------\
2358 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
2359 \ - - \CNTL Counter lentgh \ 00 = 16 bits
2360 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
2361 \ -- \ID input divider \ 10 = /4
2362 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
2363 \ - \TBCLR TimerB Clear
2366 \ -------------------------------\
2367 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
2368 \ -- \CM Capture Mode
2373 \ --- \OUTMOD \ 011 = set/reset
2379 \ -------------------------------\
2381 \ -------------------------------\
2383 \ ------------------------------\
2384 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
2385 \ ------------------------------\
2386 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
2387 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
2388 \ ------------------------------\
2389 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
2390 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
2391 \ ------------------------------\
2392 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
2393 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
2394 \ ------------------------------\
2395 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
2396 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
2397 \ ------------------------------\
2398 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
2399 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
2400 \ ------------------------------\
2401 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
2402 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
2403 \ ------------------------------\
2404 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
2405 \ ------------------------------\
2406 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
2407 \ ------------------------------\
2408 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
2409 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
2410 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
2411 \ ------------------------------\
2412 BIS.B #LCDVo,&LCDVo_DIR \
2413 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
2414 \ ------------------------------\
2415 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
2416 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
2417 \ ------------------------------\
2418 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
2419 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
2420 \ ******************************\
2422 \ ******************************\
2423 BIS.B #RC5,&IR_IE \ enable RC5_Int
2424 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
2425 MOV #RC5_INT,&IR_Vec \ init interrupt vector
2426 \ ******************************\
2427 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
2428 \ ******************************\
2429 \ %01 0001 0100 \ TAxCTL
2430 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
2431 \ -- \ ID divided by 1
2432 \ -- \ MC MODE = up to TAxCCRn
2433 \ - \ TACLR clear timer count
2436 \ ------------------------------\
2437 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
2438 \ ------------------------------\
2440 \ --- \ TAIDEX pre divisor
2441 \ ------------------------------\
2442 \ %0000 0000 0000 0101 \ TAxCCR0
2443 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
2444 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
2445 \ ------------------------------\
2446 \ %0000 0000 0001 0000 \ TAxCCTL0
2447 \ - \ CAP capture/compare mode = compare
2450 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
2451 \ ------------------------------\
2452 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
2453 \ ------------------------------\
2454 \ define LPM mode for ACCEPT \
2455 \ ------------------------------\
2456 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
2457 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
2458 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
2460 \ ------------------------------\
2461 \ redirects to background task \
2462 \ ------------------------------\
2464 MOV #BACKGROUND,2(X) \
2465 \ ------------------------------\
2467 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
2469 \ ------------------------------\
2471 \ ------------------------------\
2472 $03E8 20_US \ 1- wait 20 ms
2473 $03 TOP_LCD \ 2- send DB5=DB4=1
2474 $CD 20_US \ 3- wait 4,1 ms
2475 $03 TOP_LCD \ 4- send again DB5=DB4=1
2476 $5 20_US \ 5- wait 0,1 ms
2477 $03 TOP_LCD \ 6- send again again DB5=DB4=1
2478 $2 20_US \ wait 40 us = LCD cycle
2479 $02 TOP_LCD \ 7- send DB5=1 DB4=0
2480 $2 20_US \ wait 40 us = LCD cycle
2481 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
2482 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
2483 LCD_Clear \ 10- "LCD_Clear"
2484 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
2485 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
2486 LCD_Clear \ 10- "LCD_Clear"
2487 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
2488 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
2490 ['] CR >BODY IS CR \
2491 ['] EMIT >BODY IS EMIT \
2492 ." RC5toLCD is running. Type STOP to quit"
2493 LIT RECURSE IS WARM \ replace WARM by this START routine
2494 ABORT \ and continue with the next word after WARM...
2495 ; \ ...until interpreter falls in sleep mode within ACCEPT.
2498 CODE STOP \ stops multitasking, must to be used before downloading app
2499 \ restore default action of primary DEFERred word SLEEP, assembly version
2500 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
2501 ADD #4,X \ X = BODY of SLEEP
2502 MOV X,-2(X) \ restore the default background
2505 \ restore default action of primary DEFERred word WARM, FORTH version
2506 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
2508 COLD \ because we want to reset CPU and interrupt vectors
2513 ; downloading RC5toLCD.4th is done
2514 RST_HERE ; this app is protected against <reset>
2522 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
2524 [DEFINED] ASM [IF] \ security test
2528 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
2530 CODE MAX \ n1 n2 -- n3 signed maximum
2531 CMP @PSP,TOS \ n2-n1
2532 S< ?GOTO FW1 \ n2<n1
2538 CODE MIN \ n1 n2 -- n3 signed minimum
2539 CMP @PSP,TOS \ n2-n1
2540 S< ?GOTO BW1 \ n2<n1
2548 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
2549 : U.R \ u n -- display u unsigned in n width (n >= 2)
2551 R> OVER - 0 MAX SPACES TYPE
2556 \ CODE 20_US \ n -- n * 20 us
2557 \ BEGIN \ 3 cycles loop + 6~
2558 \ \ MOV #5,W \ 3 MCLK = 1 MHz
2559 \ \ MOV #23,W \ 3 MCLK = 4 MHz
2560 \ \ MOV #51,W \ 3 MCLK = 8 MHz
2561 \ MOV #104,W \ 3 MCLK = 16 MHz
2562 \ \ MOV #158,W \ 3 MCLK = 24 MHz
2563 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
2573 CODE 20_US \ n -- n * 20 us
2574 BEGIN \ here we presume that LCD_TIM_IFG = 1...
2576 BIT #1,&LCD_TIM_CTL \ 3
2577 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
2578 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
2580 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
2586 CODE TOP_LCD \ LCD Sample
2587 \ \ if write : %xxxxWWWW --
2588 \ \ if read : -- %0000RRRR
2589 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
2590 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
2591 0= IF \ write LCD bits pattern
2593 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
2594 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
2597 THEN \ read LCD bits pattern
2600 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
2601 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
2607 CODE LCD_W \ byte -- write byte to LCD
2609 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
2610 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
2611 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
2612 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
2613 COLON \ high level word starts here
2614 TOP_LCD 2 20_US \ write high nibble first
2619 CODE LCD_WrC \ char -- Write Char
2620 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
2625 CODE LCD_WrF \ func -- Write Fonction
2626 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
2632 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
2637 $02 LCD_WrF 100 20_us
2643 \ https://forth-standard.org/standard/core/OR
2644 \ C OR x1 x2 -- x3 logical OR
2653 : LCD_Entry_set $04 OR LCD_WrF ;
2655 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
2657 : LCD_DSP_Shift $10 OR LCD_WrF ;
2659 : LCD_Fn_Set $20 OR LCD_WrF ;
2661 : LCD_CGRAM_Set $40 OR LCD_WrF ;
2663 : LCD_Goto $80 OR LCD_WrF ;
2665 CODE LCD_R \ -- byte read byte from LCD
2666 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
2667 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
2668 COLON \ starts a FORTH word
2669 TOP_LCD 2 20_us \ -- %0000HHHH
2670 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
2671 HI2LO \ switch from FORTH to assembler
2672 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
2673 ADD.B @PSP+,TOS \ -- %HHHHLLLL
2674 MOV @RSP+,IP \ restore IP saved by COLON
2679 CODE LCD_RdS \ -- status Read Status
2680 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
2685 CODE LCD_RdC \ -- char Read Char
2686 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
2692 \ ******************************\
2693 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
2694 \ ******************************\
2695 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
2696 BIT.B #SW2,&SW2_IN \ test switch S2
2697 0= IF \ case of switch S2 pressed
2698 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
2700 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
2703 BIT.B #SW1,&SW1_IN \ test switch S1 input
2704 0= IF \ case of Switch S1 pressed
2705 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
2707 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
2711 BW1 \ from quit on truncated RC5 message
2712 BW2 \ from repeated RC5 command
2713 BW3 \ from end of RC5_INT
2714 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
2719 \ ******************************\
2720 ASM RC5_INT \ wake up on Px.RC5 change interrupt
2721 \ ******************************\
2722 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
2723 \ ******************************\
2724 \ \ in : SR(9)=old Toggle bit memory (ADD on)
2725 \ \ SMclock = 8|16|24 MHz
2726 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
2727 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
2728 \ \ SR(9)=new Toggle bit memory (ADD on)
2729 \ ******************************\
2730 \ RC5_FirstStartBitHalfCycle: \
2731 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
2732 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
2733 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
2734 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
2735 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
2736 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
2737 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
2738 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
2739 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
2740 MOV #1778,X \ RC5_Period * 1us
2741 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
2742 MOV #14,W \ count of loop
2744 \ ******************************\
2745 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
2746 \ ******************************\ |
2747 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
2748 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
2749 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
2750 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
2751 \ RC5_Compute_3/4_Period: \ |
2752 RRUM #1,X \ X=1/2 cycle |
2755 ADD X,Y \ Y=3/4 cycle
2756 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
2758 \ ******************************\
2759 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
2760 \ ******************************\
2761 BIT.B #RC5,&IR_IN \ C_flag = IR bit
2762 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
2763 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
2764 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
2765 SUB #1,W \ decrement count loop
2766 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
2767 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
2768 0<> WHILE \ ----> out of loop ----+
2769 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
2771 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
2772 CMP Y,X \ 1 | cycle time out of bound ?
2774 BIC #$30,&RC5_TIM_CTL \ | | stop timer
2775 GOTO BW1 \ | | quit on truncated RC5 message
2777 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
2779 REPEAT \ ----> loop back --+ | with X = new RC5_period value
2780 \ ******************************\ |
2781 \ RC5_SampleEndOf: \ <---------------------+
2782 \ ******************************\
2783 BIC #$30,&RC5_TIM_CTL \ stop timer
2784 \ ******************************\
2785 \ RC5_ComputeNewRC5word \
2786 \ ******************************\
2787 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
2788 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
2789 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
2790 \ ******************************\
2791 \ RC5_ComputeC6bit \
2792 \ ******************************\
2793 BIT #BIT14,T \ test /C6 bit in T
2794 0= IF BIS #BIT6,X \ set C6 bit in X
2795 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
2796 \ ******************************\
2797 \ RC5_CommandByteIsDone \ -- BASE RC5_code
2798 \ ******************************\
2799 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
2800 \ ******************************\
2801 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
2802 XOR @RSP,T \ (new XOR old) Toggle bits
2803 BIT #UF10,T \ repeated RC5_command ?
2804 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
2805 XOR #UF10,0(RSP) \ 5 toggle bit memory
2806 \ ******************************\
2807 \ Display IR_RC5 code \ X = RC5 code
2808 \ ******************************\
2810 MOV &BASE,2(PSP) \ save current base
2811 MOV #$10,&BASE \ set hex base
2812 MOV TOS,0(PSP) \ save TOS
2814 LO2HI \ switch from assembler to FORTH
2815 ['] LCD_CLEAR IS CR \ redirects CR
2816 ['] LCD_WrC IS EMIT \ redirects EMIT
2817 CR ." $" 2 U.R \ print IR_RC5 code
2818 ['] CR >BODY IS CR \ restore CR
2819 ['] EMIT >BODY IS EMIT \ restore EMIT
2820 HI2LO \ switch from FORTH to assembler
2821 MOV TOS,&BASE \ restore current BASE
2823 \ ******************************\
2825 \ ******************************\
2829 \ ------------------------------\
2831 \ ------------------------------\
2832 \ ... \ insert here your background task
2835 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
2836 ADD #4,X \ 1 X = BODY of SLEEP
2839 \ ------------------------------\
2843 \ ------------------------------\
2844 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
2845 \ - - \CNTL Counter lentgh \ 00 = 16 bits
2846 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
2847 \ -- \ID input divider \ 10 = /4
2848 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
2849 \ - \TBCLR TimerB Clear
2852 \ -------------------------------\
2853 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
2854 \ -- \CM Capture Mode
2859 \ --- \OUTMOD \ 011 = set/reset
2865 \ -------------------------------\
2867 \ -------------------------------\
2869 \ ------------------------------\
2870 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
2871 \ ------------------------------\
2872 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
2873 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
2874 \ ------------------------------\
2875 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
2876 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
2877 \ ------------------------------\
2878 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
2879 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
2880 \ ------------------------------\
2881 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
2882 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
2883 \ ------------------------------\
2884 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
2885 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
2886 \ ------------------------------\
2887 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
2888 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
2889 \ ------------------------------\
2890 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
2891 \ ------------------------------\
2892 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
2893 \ ------------------------------\
2894 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
2895 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
2896 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
2897 \ ------------------------------\
2898 BIS.B #LCDVo,&LCDVo_DIR \
2899 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
2900 \ ------------------------------\
2901 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
2902 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
2903 \ ------------------------------\
2904 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
2905 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
2906 \ ******************************\
2908 \ ******************************\
2909 BIS.B #RC5,&IR_IE \ enable RC5_Int
2910 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
2911 MOV #RC5_INT,&IR_Vec \ init interrupt vector
2912 \ ******************************\
2913 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
2914 \ ******************************\
2915 \ %01 0001 0100 \ TAxCTL
2916 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
2917 \ -- \ ID divided by 1
2918 \ -- \ MC MODE = up to TAxCCRn
2919 \ - \ TACLR clear timer count
2922 \ ------------------------------\
2923 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
2924 \ ------------------------------\
2926 \ --- \ TAIDEX pre divisor
2927 \ ------------------------------\
2928 \ %0000 0000 0000 0101 \ TAxCCR0
2929 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
2930 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
2931 \ ------------------------------\
2932 \ %0000 0000 0001 0000 \ TAxCCTL0
2933 \ - \ CAP capture/compare mode = compare
2936 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
2937 \ ------------------------------\
2938 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
2939 \ ------------------------------\
2940 \ define LPM mode for ACCEPT \
2941 \ ------------------------------\
2942 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
2943 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
2944 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
2946 \ ------------------------------\
2947 \ redirects to background task \
2948 \ ------------------------------\
2950 MOV #BACKGROUND,2(X) \
2951 \ ------------------------------\
2953 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
2955 \ ------------------------------\
2957 \ ------------------------------\
2958 $03E8 20_US \ 1- wait 20 ms
2959 $03 TOP_LCD \ 2- send DB5=DB4=1
2960 $CD 20_US \ 3- wait 4,1 ms
2961 $03 TOP_LCD \ 4- send again DB5=DB4=1
2962 $5 20_US \ 5- wait 0,1 ms
2963 $03 TOP_LCD \ 6- send again again DB5=DB4=1
2964 $2 20_US \ wait 40 us = LCD cycle
2965 $02 TOP_LCD \ 7- send DB5=1 DB4=0
2966 $2 20_US \ wait 40 us = LCD cycle
2967 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
2968 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
2969 LCD_Clear \ 10- "LCD_Clear"
2970 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
2971 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
2972 LCD_Clear \ 10- "LCD_Clear"
2973 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
2974 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
2976 ['] CR >BODY IS CR \
2977 ['] EMIT >BODY IS EMIT \
2978 ." RC5toLCD is running. Type STOP to quit"
2979 LIT RECURSE IS WARM \ replace WARM by this START routine
2980 ABORT \ and continue with the next word after WARM...
2981 ; \ ...until interpreter falls in sleep mode within ACCEPT.
2984 CODE STOP \ stops multitasking, must to be used before downloading app
2985 \ restore default action of primary DEFERred word SLEEP, assembly version
2986 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
2987 ADD #4,X \ X = BODY of SLEEP
2988 MOV X,-2(X) \ restore the default background
2991 \ restore default action of primary DEFERred word WARM, FORTH version
2992 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
2994 COLD \ because we want to reset CPU and interrupt vectors
2999 ; downloading RC5toLCD.4th is done
3000 RST_HERE ; this app is protected against <reset>
3008 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
3010 [DEFINED] ASM [IF] \ security test
3014 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
3016 CODE MAX \ n1 n2 -- n3 signed maximum
3017 CMP @PSP,TOS \ n2-n1
3018 S< ?GOTO FW1 \ n2<n1
3024 CODE MIN \ n1 n2 -- n3 signed minimum
3025 CMP @PSP,TOS \ n2-n1
3026 S< ?GOTO BW1 \ n2<n1
3034 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
3035 : U.R \ u n -- display u unsigned in n width (n >= 2)
3037 R> OVER - 0 MAX SPACES TYPE
3042 \ CODE 20_US \ n -- n * 20 us
3043 \ BEGIN \ 3 cycles loop + 6~
3044 \ \ MOV #5,W \ 3 MCLK = 1 MHz
3045 \ \ MOV #23,W \ 3 MCLK = 4 MHz
3046 \ \ MOV #51,W \ 3 MCLK = 8 MHz
3047 \ MOV #104,W \ 3 MCLK = 16 MHz
3048 \ \ MOV #158,W \ 3 MCLK = 24 MHz
3049 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
3059 CODE 20_US \ n -- n * 20 us
3060 BEGIN \ here we presume that LCD_TIM_IFG = 1...
3062 BIT #1,&LCD_TIM_CTL \ 3
3063 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
3064 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
3066 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
3072 CODE TOP_LCD \ LCD Sample
3073 \ \ if write : %xxxxWWWW --
3074 \ \ if read : -- %0000RRRR
3075 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
3076 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
3077 0= IF \ write LCD bits pattern
3079 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
3080 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
3083 THEN \ read LCD bits pattern
3086 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
3087 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
3093 CODE LCD_W \ byte -- write byte to LCD
3095 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
3096 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
3097 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
3098 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
3099 COLON \ high level word starts here
3100 TOP_LCD 2 20_US \ write high nibble first
3105 CODE LCD_WrC \ char -- Write Char
3106 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
3111 CODE LCD_WrF \ func -- Write Fonction
3112 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
3118 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
3123 $02 LCD_WrF 100 20_us
3129 \ https://forth-standard.org/standard/core/OR
3130 \ C OR x1 x2 -- x3 logical OR
3139 : LCD_Entry_set $04 OR LCD_WrF ;
3141 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
3143 : LCD_DSP_Shift $10 OR LCD_WrF ;
3145 : LCD_Fn_Set $20 OR LCD_WrF ;
3147 : LCD_CGRAM_Set $40 OR LCD_WrF ;
3149 : LCD_Goto $80 OR LCD_WrF ;
3151 CODE LCD_R \ -- byte read byte from LCD
3152 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
3153 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
3154 COLON \ starts a FORTH word
3155 TOP_LCD 2 20_us \ -- %0000HHHH
3156 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
3157 HI2LO \ switch from FORTH to assembler
3158 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
3159 ADD.B @PSP+,TOS \ -- %HHHHLLLL
3160 MOV @RSP+,IP \ restore IP saved by COLON
3165 CODE LCD_RdS \ -- status Read Status
3166 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
3171 CODE LCD_RdC \ -- char Read Char
3172 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
3178 \ ******************************\
3179 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
3180 \ ******************************\
3181 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
3182 BIT.B #SW2,&SW2_IN \ test switch S2
3183 0= IF \ case of switch S2 pressed
3184 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
3186 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
3189 BIT.B #SW1,&SW1_IN \ test switch S1 input
3190 0= IF \ case of Switch S1 pressed
3191 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
3193 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
3197 BW1 \ from quit on truncated RC5 message
3198 BW2 \ from repeated RC5 command
3199 BW3 \ from end of RC5_INT
3200 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
3205 \ ******************************\
3206 ASM RC5_INT \ wake up on Px.RC5 change interrupt
3207 \ ******************************\
3208 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
3209 \ ******************************\
3210 \ \ in : SR(9)=old Toggle bit memory (ADD on)
3211 \ \ SMclock = 8|16|24 MHz
3212 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
3213 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
3214 \ \ SR(9)=new Toggle bit memory (ADD on)
3215 \ ******************************\
3216 \ RC5_FirstStartBitHalfCycle: \
3217 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
3218 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
3219 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
3220 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
3221 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
3222 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
3223 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
3224 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
3225 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
3226 MOV #1778,X \ RC5_Period * 1us
3227 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
3228 MOV #14,W \ count of loop
3230 \ ******************************\
3231 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
3232 \ ******************************\ |
3233 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
3234 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
3235 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
3236 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
3237 \ RC5_Compute_3/4_Period: \ |
3238 RRUM #1,X \ X=1/2 cycle |
3241 ADD X,Y \ Y=3/4 cycle
3242 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
3244 \ ******************************\
3245 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
3246 \ ******************************\
3247 BIT.B #RC5,&IR_IN \ C_flag = IR bit
3248 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
3249 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
3250 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
3251 SUB #1,W \ decrement count loop
3252 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
3253 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
3254 0<> WHILE \ ----> out of loop ----+
3255 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
3257 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
3258 CMP Y,X \ 1 | cycle time out of bound ?
3260 BIC #$30,&RC5_TIM_CTL \ | | stop timer
3261 GOTO BW1 \ | | quit on truncated RC5 message
3263 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
3265 REPEAT \ ----> loop back --+ | with X = new RC5_period value
3266 \ ******************************\ |
3267 \ RC5_SampleEndOf: \ <---------------------+
3268 \ ******************************\
3269 BIC #$30,&RC5_TIM_CTL \ stop timer
3270 \ ******************************\
3271 \ RC5_ComputeNewRC5word \
3272 \ ******************************\
3273 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
3274 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
3275 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
3276 \ ******************************\
3277 \ RC5_ComputeC6bit \
3278 \ ******************************\
3279 BIT #BIT14,T \ test /C6 bit in T
3280 0= IF BIS #BIT6,X \ set C6 bit in X
3281 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
3282 \ ******************************\
3283 \ RC5_CommandByteIsDone \ -- BASE RC5_code
3284 \ ******************************\
3285 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
3286 \ ******************************\
3287 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
3288 XOR @RSP,T \ (new XOR old) Toggle bits
3289 BIT #UF10,T \ repeated RC5_command ?
3290 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
3291 XOR #UF10,0(RSP) \ 5 toggle bit memory
3292 \ ******************************\
3293 \ Display IR_RC5 code \ X = RC5 code
3294 \ ******************************\
3296 MOV &BASE,2(PSP) \ save current base
3297 MOV #$10,&BASE \ set hex base
3298 MOV TOS,0(PSP) \ save TOS
3300 LO2HI \ switch from assembler to FORTH
3301 ['] LCD_CLEAR IS CR \ redirects CR
3302 ['] LCD_WrC IS EMIT \ redirects EMIT
3303 CR ." $" 2 U.R \ print IR_RC5 code
3304 ['] CR >BODY IS CR \ restore CR
3305 ['] EMIT >BODY IS EMIT \ restore EMIT
3306 HI2LO \ switch from FORTH to assembler
3307 MOV TOS,&BASE \ restore current BASE
3309 \ ******************************\
3311 \ ******************************\
3315 \ ------------------------------\
3317 \ ------------------------------\
3318 \ ... \ insert here your background task
3321 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
3322 ADD #4,X \ 1 X = BODY of SLEEP
3325 \ ------------------------------\
3329 \ ------------------------------\
3330 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
3331 \ - - \CNTL Counter lentgh \ 00 = 16 bits
3332 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
3333 \ -- \ID input divider \ 10 = /4
3334 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
3335 \ - \TBCLR TimerB Clear
3338 \ -------------------------------\
3339 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
3340 \ -- \CM Capture Mode
3345 \ --- \OUTMOD \ 011 = set/reset
3351 \ -------------------------------\
3353 \ -------------------------------\
3355 \ ------------------------------\
3356 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
3357 \ ------------------------------\
3358 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
3359 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
3360 \ ------------------------------\
3361 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
3362 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
3363 \ ------------------------------\
3364 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
3365 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
3366 \ ------------------------------\
3367 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
3368 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
3369 \ ------------------------------\
3370 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
3371 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
3372 \ ------------------------------\
3373 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
3374 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
3375 \ ------------------------------\
3376 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
3377 \ ------------------------------\
3378 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
3379 \ ------------------------------\
3380 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
3381 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
3382 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
3383 \ ------------------------------\
3384 BIS.B #LCDVo,&LCDVo_DIR \
3385 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
3386 \ ------------------------------\
3387 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
3388 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
3389 \ ------------------------------\
3390 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
3391 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
3392 \ ******************************\
3394 \ ******************************\
3395 BIS.B #RC5,&IR_IE \ enable RC5_Int
3396 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
3397 MOV #RC5_INT,&IR_Vec \ init interrupt vector
3398 \ ******************************\
3399 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
3400 \ ******************************\
3401 \ %01 0001 0100 \ TAxCTL
3402 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
3403 \ -- \ ID divided by 1
3404 \ -- \ MC MODE = up to TAxCCRn
3405 \ - \ TACLR clear timer count
3408 \ ------------------------------\
3409 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
3410 \ ------------------------------\
3412 \ --- \ TAIDEX pre divisor
3413 \ ------------------------------\
3414 \ %0000 0000 0000 0101 \ TAxCCR0
3415 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
3416 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
3417 \ ------------------------------\
3418 \ %0000 0000 0001 0000 \ TAxCCTL0
3419 \ - \ CAP capture/compare mode = compare
3422 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
3423 \ ------------------------------\
3424 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
3425 \ ------------------------------\
3426 \ define LPM mode for ACCEPT \
3427 \ ------------------------------\
3428 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
3429 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
3430 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
3432 \ ------------------------------\
3433 \ redirects to background task \
3434 \ ------------------------------\
3436 MOV #BACKGROUND,2(X) \
3437 \ ------------------------------\
3439 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
3441 \ ------------------------------\
3443 \ ------------------------------\
3444 $03E8 20_US \ 1- wait 20 ms
3445 $03 TOP_LCD \ 2- send DB5=DB4=1
3446 $CD 20_US \ 3- wait 4,1 ms
3447 $03 TOP_LCD \ 4- send again DB5=DB4=1
3448 $5 20_US \ 5- wait 0,1 ms
3449 $03 TOP_LCD \ 6- send again again DB5=DB4=1
3450 $2 20_US \ wait 40 us = LCD cycle
3451 $02 TOP_LCD \ 7- send DB5=1 DB4=0
3452 $2 20_US \ wait 40 us = LCD cycle
3453 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
3454 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
3455 LCD_Clear \ 10- "LCD_Clear"
3456 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
3457 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
3458 LCD_Clear \ 10- "LCD_Clear"
3459 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
3460 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
3462 ['] CR >BODY IS CR \
3463 ['] EMIT >BODY IS EMIT \
3464 ." RC5toLCD is running. Type STOP to quit"
3465 LIT RECURSE IS WARM \ replace WARM by this START routine
3466 ABORT \ and continue with the next word after WARM...
3467 ; \ ...until interpreter falls in sleep mode within ACCEPT.
3470 CODE STOP \ stops multitasking, must to be used before downloading app
3471 \ restore default action of primary DEFERred word SLEEP, assembly version
3472 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
3473 ADD #4,X \ X = BODY of SLEEP
3474 MOV X,-2(X) \ restore the default background
3477 \ restore default action of primary DEFERred word WARM, FORTH version
3478 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
3480 COLD \ because we want to reset CPU and interrupt vectors
3485 ; downloading RC5toLCD.4th is done
3486 RST_HERE ; this app is protected against <reset>
3494 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
3496 [DEFINED] ASM [IF] \ security test
3500 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
3502 CODE MAX \ n1 n2 -- n3 signed maximum
3503 CMP @PSP,TOS \ n2-n1
3504 S< ?GOTO FW1 \ n2<n1
3510 CODE MIN \ n1 n2 -- n3 signed minimum
3511 CMP @PSP,TOS \ n2-n1
3512 S< ?GOTO BW1 \ n2<n1
3520 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
3521 : U.R \ u n -- display u unsigned in n width (n >= 2)
3523 R> OVER - 0 MAX SPACES TYPE
3528 \ CODE 20_US \ n -- n * 20 us
3529 \ BEGIN \ 3 cycles loop + 6~
3530 \ \ MOV #5,W \ 3 MCLK = 1 MHz
3531 \ \ MOV #23,W \ 3 MCLK = 4 MHz
3532 \ \ MOV #51,W \ 3 MCLK = 8 MHz
3533 \ MOV #104,W \ 3 MCLK = 16 MHz
3534 \ \ MOV #158,W \ 3 MCLK = 24 MHz
3535 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
3545 CODE 20_US \ n -- n * 20 us
3546 BEGIN \ here we presume that LCD_TIM_IFG = 1...
3548 BIT #1,&LCD_TIM_CTL \ 3
3549 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
3550 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
3552 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
3558 CODE TOP_LCD \ LCD Sample
3559 \ \ if write : %xxxxWWWW --
3560 \ \ if read : -- %0000RRRR
3561 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
3562 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
3563 0= IF \ write LCD bits pattern
3565 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
3566 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
3569 THEN \ read LCD bits pattern
3572 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
3573 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
3579 CODE LCD_W \ byte -- write byte to LCD
3581 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
3582 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
3583 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
3584 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
3585 COLON \ high level word starts here
3586 TOP_LCD 2 20_US \ write high nibble first
3591 CODE LCD_WrC \ char -- Write Char
3592 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
3597 CODE LCD_WrF \ func -- Write Fonction
3598 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
3604 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
3609 $02 LCD_WrF 100 20_us
3615 \ https://forth-standard.org/standard/core/OR
3616 \ C OR x1 x2 -- x3 logical OR
3625 : LCD_Entry_set $04 OR LCD_WrF ;
3627 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
3629 : LCD_DSP_Shift $10 OR LCD_WrF ;
3631 : LCD_Fn_Set $20 OR LCD_WrF ;
3633 : LCD_CGRAM_Set $40 OR LCD_WrF ;
3635 : LCD_Goto $80 OR LCD_WrF ;
3637 CODE LCD_R \ -- byte read byte from LCD
3638 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
3639 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
3640 COLON \ starts a FORTH word
3641 TOP_LCD 2 20_us \ -- %0000HHHH
3642 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
3643 HI2LO \ switch from FORTH to assembler
3644 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
3645 ADD.B @PSP+,TOS \ -- %HHHHLLLL
3646 MOV @RSP+,IP \ restore IP saved by COLON
3651 CODE LCD_RdS \ -- status Read Status
3652 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
3657 CODE LCD_RdC \ -- char Read Char
3658 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
3664 \ ******************************\
3665 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
3666 \ ******************************\
3667 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
3668 BIT.B #SW2,&SW2_IN \ test switch S2
3669 0= IF \ case of switch S2 pressed
3670 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
3672 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
3675 BIT.B #SW1,&SW1_IN \ test switch S1 input
3676 0= IF \ case of Switch S1 pressed
3677 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
3679 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
3683 BW1 \ from quit on truncated RC5 message
3684 BW2 \ from repeated RC5 command
3685 BW3 \ from end of RC5_INT
3686 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
3691 \ ******************************\
3692 ASM RC5_INT \ wake up on Px.RC5 change interrupt
3693 \ ******************************\
3694 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
3695 \ ******************************\
3696 \ \ in : SR(9)=old Toggle bit memory (ADD on)
3697 \ \ SMclock = 8|16|24 MHz
3698 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
3699 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
3700 \ \ SR(9)=new Toggle bit memory (ADD on)
3701 \ ******************************\
3702 \ RC5_FirstStartBitHalfCycle: \
3703 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
3704 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
3705 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
3706 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
3707 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
3708 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
3709 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
3710 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
3711 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
3712 MOV #1778,X \ RC5_Period * 1us
3713 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
3714 MOV #14,W \ count of loop
3716 \ ******************************\
3717 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
3718 \ ******************************\ |
3719 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
3720 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
3721 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
3722 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
3723 \ RC5_Compute_3/4_Period: \ |
3724 RRUM #1,X \ X=1/2 cycle |
3727 ADD X,Y \ Y=3/4 cycle
3728 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
3730 \ ******************************\
3731 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
3732 \ ******************************\
3733 BIT.B #RC5,&IR_IN \ C_flag = IR bit
3734 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
3735 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
3736 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
3737 SUB #1,W \ decrement count loop
3738 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
3739 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
3740 0<> WHILE \ ----> out of loop ----+
3741 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
3743 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
3744 CMP Y,X \ 1 | cycle time out of bound ?
3746 BIC #$30,&RC5_TIM_CTL \ | | stop timer
3747 GOTO BW1 \ | | quit on truncated RC5 message
3749 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
3751 REPEAT \ ----> loop back --+ | with X = new RC5_period value
3752 \ ******************************\ |
3753 \ RC5_SampleEndOf: \ <---------------------+
3754 \ ******************************\
3755 BIC #$30,&RC5_TIM_CTL \ stop timer
3756 \ ******************************\
3757 \ RC5_ComputeNewRC5word \
3758 \ ******************************\
3759 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
3760 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
3761 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
3762 \ ******************************\
3763 \ RC5_ComputeC6bit \
3764 \ ******************************\
3765 BIT #BIT14,T \ test /C6 bit in T
3766 0= IF BIS #BIT6,X \ set C6 bit in X
3767 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
3768 \ ******************************\
3769 \ RC5_CommandByteIsDone \ -- BASE RC5_code
3770 \ ******************************\
3771 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
3772 \ ******************************\
3773 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
3774 XOR @RSP,T \ (new XOR old) Toggle bits
3775 BIT #UF10,T \ repeated RC5_command ?
3776 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
3777 XOR #UF10,0(RSP) \ 5 toggle bit memory
3778 \ ******************************\
3779 \ Display IR_RC5 code \ X = RC5 code
3780 \ ******************************\
3782 MOV &BASE,2(PSP) \ save current base
3783 MOV #$10,&BASE \ set hex base
3784 MOV TOS,0(PSP) \ save TOS
3786 LO2HI \ switch from assembler to FORTH
3787 ['] LCD_CLEAR IS CR \ redirects CR
3788 ['] LCD_WrC IS EMIT \ redirects EMIT
3789 CR ." $" 2 U.R \ print IR_RC5 code
3790 ['] CR >BODY IS CR \ restore CR
3791 ['] EMIT >BODY IS EMIT \ restore EMIT
3792 HI2LO \ switch from FORTH to assembler
3793 MOV TOS,&BASE \ restore current BASE
3795 \ ******************************\
3797 \ ******************************\
3801 \ ------------------------------\
3803 \ ------------------------------\
3804 \ ... \ insert here your background task
3807 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
3808 ADD #4,X \ 1 X = BODY of SLEEP
3811 \ ------------------------------\
3815 \ ------------------------------\
3816 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
3817 \ - - \CNTL Counter lentgh \ 00 = 16 bits
3818 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
3819 \ -- \ID input divider \ 10 = /4
3820 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
3821 \ - \TBCLR TimerB Clear
3824 \ -------------------------------\
3825 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
3826 \ -- \CM Capture Mode
3831 \ --- \OUTMOD \ 011 = set/reset
3837 \ -------------------------------\
3839 \ -------------------------------\
3841 \ ------------------------------\
3842 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
3843 \ ------------------------------\
3844 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
3845 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
3846 \ ------------------------------\
3847 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
3848 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
3849 \ ------------------------------\
3850 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
3851 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
3852 \ ------------------------------\
3853 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
3854 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
3855 \ ------------------------------\
3856 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
3857 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
3858 \ ------------------------------\
3859 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
3860 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
3861 \ ------------------------------\
3862 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
3863 \ ------------------------------\
3864 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
3865 \ ------------------------------\
3866 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
3867 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
3868 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
3869 \ ------------------------------\
3870 BIS.B #LCDVo,&LCDVo_DIR \
3871 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
3872 \ ------------------------------\
3873 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
3874 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
3875 \ ------------------------------\
3876 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
3877 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
3878 \ ******************************\
3880 \ ******************************\
3881 BIS.B #RC5,&IR_IE \ enable RC5_Int
3882 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
3883 MOV #RC5_INT,&IR_Vec \ init interrupt vector
3884 \ ******************************\
3885 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
3886 \ ******************************\
3887 \ %01 0001 0100 \ TAxCTL
3888 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
3889 \ -- \ ID divided by 1
3890 \ -- \ MC MODE = up to TAxCCRn
3891 \ - \ TACLR clear timer count
3894 \ ------------------------------\
3895 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
3896 \ ------------------------------\
3898 \ --- \ TAIDEX pre divisor
3899 \ ------------------------------\
3900 \ %0000 0000 0000 0101 \ TAxCCR0
3901 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
3902 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
3903 \ ------------------------------\
3904 \ %0000 0000 0001 0000 \ TAxCCTL0
3905 \ - \ CAP capture/compare mode = compare
3908 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
3909 \ ------------------------------\
3910 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
3911 \ ------------------------------\
3912 \ define LPM mode for ACCEPT \
3913 \ ------------------------------\
3914 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
3915 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
3916 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
3918 \ ------------------------------\
3919 \ redirects to background task \
3920 \ ------------------------------\
3922 MOV #BACKGROUND,2(X) \
3923 \ ------------------------------\
3925 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
3927 \ ------------------------------\
3929 \ ------------------------------\
3930 $03E8 20_US \ 1- wait 20 ms
3931 $03 TOP_LCD \ 2- send DB5=DB4=1
3932 $CD 20_US \ 3- wait 4,1 ms
3933 $03 TOP_LCD \ 4- send again DB5=DB4=1
3934 $5 20_US \ 5- wait 0,1 ms
3935 $03 TOP_LCD \ 6- send again again DB5=DB4=1
3936 $2 20_US \ wait 40 us = LCD cycle
3937 $02 TOP_LCD \ 7- send DB5=1 DB4=0
3938 $2 20_US \ wait 40 us = LCD cycle
3939 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
3940 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
3941 LCD_Clear \ 10- "LCD_Clear"
3942 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
3943 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
3944 LCD_Clear \ 10- "LCD_Clear"
3945 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
3946 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
3948 ['] CR >BODY IS CR \
3949 ['] EMIT >BODY IS EMIT \
3950 ." RC5toLCD is running. Type STOP to quit"
3951 LIT RECURSE IS WARM \ replace WARM by this START routine
3952 ABORT \ and continue with the next word after WARM...
3953 ; \ ...until interpreter falls in sleep mode within ACCEPT.
3956 CODE STOP \ stops multitasking, must to be used before downloading app
3957 \ restore default action of primary DEFERred word SLEEP, assembly version
3958 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
3959 ADD #4,X \ X = BODY of SLEEP
3960 MOV X,-2(X) \ restore the default background
3963 \ restore default action of primary DEFERred word WARM, FORTH version
3964 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
3966 COLD \ because we want to reset CPU and interrupt vectors
3971 ; downloading RC5toLCD.4th is done
3972 RST_HERE ; this app is protected against <reset>
3980 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
3982 [DEFINED] ASM [IF] \ security test
3986 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
3988 CODE MAX \ n1 n2 -- n3 signed maximum
3989 CMP @PSP,TOS \ n2-n1
3990 S< ?GOTO FW1 \ n2<n1
3996 CODE MIN \ n1 n2 -- n3 signed minimum
3997 CMP @PSP,TOS \ n2-n1
3998 S< ?GOTO BW1 \ n2<n1
4006 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
4007 : U.R \ u n -- display u unsigned in n width (n >= 2)
4009 R> OVER - 0 MAX SPACES TYPE
4014 \ CODE 20_US \ n -- n * 20 us
4015 \ BEGIN \ 3 cycles loop + 6~
4016 \ \ MOV #5,W \ 3 MCLK = 1 MHz
4017 \ \ MOV #23,W \ 3 MCLK = 4 MHz
4018 \ \ MOV #51,W \ 3 MCLK = 8 MHz
4019 \ MOV #104,W \ 3 MCLK = 16 MHz
4020 \ \ MOV #158,W \ 3 MCLK = 24 MHz
4021 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
4031 CODE 20_US \ n -- n * 20 us
4032 BEGIN \ here we presume that LCD_TIM_IFG = 1...
4034 BIT #1,&LCD_TIM_CTL \ 3
4035 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
4036 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
4038 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
4044 CODE TOP_LCD \ LCD Sample
4045 \ \ if write : %xxxxWWWW --
4046 \ \ if read : -- %0000RRRR
4047 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
4048 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
4049 0= IF \ write LCD bits pattern
4051 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
4052 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
4055 THEN \ read LCD bits pattern
4058 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
4059 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
4065 CODE LCD_W \ byte -- write byte to LCD
4067 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
4068 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
4069 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
4070 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
4071 COLON \ high level word starts here
4072 TOP_LCD 2 20_US \ write high nibble first
4077 CODE LCD_WrC \ char -- Write Char
4078 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
4083 CODE LCD_WrF \ func -- Write Fonction
4084 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
4090 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
4095 $02 LCD_WrF 100 20_us
4101 \ https://forth-standard.org/standard/core/OR
4102 \ C OR x1 x2 -- x3 logical OR
4111 : LCD_Entry_set $04 OR LCD_WrF ;
4113 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
4115 : LCD_DSP_Shift $10 OR LCD_WrF ;
4117 : LCD_Fn_Set $20 OR LCD_WrF ;
4119 : LCD_CGRAM_Set $40 OR LCD_WrF ;
4121 : LCD_Goto $80 OR LCD_WrF ;
4123 CODE LCD_R \ -- byte read byte from LCD
4124 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
4125 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
4126 COLON \ starts a FORTH word
4127 TOP_LCD 2 20_us \ -- %0000HHHH
4128 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
4129 HI2LO \ switch from FORTH to assembler
4130 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
4131 ADD.B @PSP+,TOS \ -- %HHHHLLLL
4132 MOV @RSP+,IP \ restore IP saved by COLON
4137 CODE LCD_RdS \ -- status Read Status
4138 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
4143 CODE LCD_RdC \ -- char Read Char
4144 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
4150 \ ******************************\
4151 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
4152 \ ******************************\
4153 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
4154 BIT.B #SW2,&SW2_IN \ test switch S2
4155 0= IF \ case of switch S2 pressed
4156 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
4158 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
4161 BIT.B #SW1,&SW1_IN \ test switch S1 input
4162 0= IF \ case of Switch S1 pressed
4163 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
4165 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
4169 BW1 \ from quit on truncated RC5 message
4170 BW2 \ from repeated RC5 command
4171 BW3 \ from end of RC5_INT
4172 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
4177 \ ******************************\
4178 ASM RC5_INT \ wake up on Px.RC5 change interrupt
4179 \ ******************************\
4180 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
4181 \ ******************************\
4182 \ \ in : SR(9)=old Toggle bit memory (ADD on)
4183 \ \ SMclock = 8|16|24 MHz
4184 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
4185 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
4186 \ \ SR(9)=new Toggle bit memory (ADD on)
4187 \ ******************************\
4188 \ RC5_FirstStartBitHalfCycle: \
4189 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
4190 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
4191 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
4192 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
4193 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
4194 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
4195 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
4196 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
4197 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
4198 MOV #1778,X \ RC5_Period * 1us
4199 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
4200 MOV #14,W \ count of loop
4202 \ ******************************\
4203 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
4204 \ ******************************\ |
4205 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
4206 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
4207 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
4208 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
4209 \ RC5_Compute_3/4_Period: \ |
4210 RRUM #1,X \ X=1/2 cycle |
4213 ADD X,Y \ Y=3/4 cycle
4214 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
4216 \ ******************************\
4217 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
4218 \ ******************************\
4219 BIT.B #RC5,&IR_IN \ C_flag = IR bit
4220 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
4221 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
4222 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
4223 SUB #1,W \ decrement count loop
4224 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
4225 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
4226 0<> WHILE \ ----> out of loop ----+
4227 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
4229 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
4230 CMP Y,X \ 1 | cycle time out of bound ?
4232 BIC #$30,&RC5_TIM_CTL \ | | stop timer
4233 GOTO BW1 \ | | quit on truncated RC5 message
4235 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
4237 REPEAT \ ----> loop back --+ | with X = new RC5_period value
4238 \ ******************************\ |
4239 \ RC5_SampleEndOf: \ <---------------------+
4240 \ ******************************\
4241 BIC #$30,&RC5_TIM_CTL \ stop timer
4242 \ ******************************\
4243 \ RC5_ComputeNewRC5word \
4244 \ ******************************\
4245 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
4246 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
4247 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
4248 \ ******************************\
4249 \ RC5_ComputeC6bit \
4250 \ ******************************\
4251 BIT #BIT14,T \ test /C6 bit in T
4252 0= IF BIS #BIT6,X \ set C6 bit in X
4253 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
4254 \ ******************************\
4255 \ RC5_CommandByteIsDone \ -- BASE RC5_code
4256 \ ******************************\
4257 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
4258 \ ******************************\
4259 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
4260 XOR @RSP,T \ (new XOR old) Toggle bits
4261 BIT #UF10,T \ repeated RC5_command ?
4262 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
4263 XOR #UF10,0(RSP) \ 5 toggle bit memory
4264 \ ******************************\
4265 \ Display IR_RC5 code \ X = RC5 code
4266 \ ******************************\
4268 MOV &BASE,2(PSP) \ save current base
4269 MOV #$10,&BASE \ set hex base
4270 MOV TOS,0(PSP) \ save TOS
4272 LO2HI \ switch from assembler to FORTH
4273 ['] LCD_CLEAR IS CR \ redirects CR
4274 ['] LCD_WrC IS EMIT \ redirects EMIT
4275 CR ." $" 2 U.R \ print IR_RC5 code
4276 ['] CR >BODY IS CR \ restore CR
4277 ['] EMIT >BODY IS EMIT \ restore EMIT
4278 HI2LO \ switch from FORTH to assembler
4279 MOV TOS,&BASE \ restore current BASE
4281 \ ******************************\
4283 \ ******************************\
4287 \ ------------------------------\
4289 \ ------------------------------\
4290 \ ... \ insert here your background task
4293 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
4294 ADD #4,X \ 1 X = BODY of SLEEP
4297 \ ------------------------------\
4301 \ ------------------------------\
4302 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
4303 \ - - \CNTL Counter lentgh \ 00 = 16 bits
4304 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
4305 \ -- \ID input divider \ 10 = /4
4306 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
4307 \ - \TBCLR TimerB Clear
4310 \ -------------------------------\
4311 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
4312 \ -- \CM Capture Mode
4317 \ --- \OUTMOD \ 011 = set/reset
4323 \ -------------------------------\
4325 \ -------------------------------\
4327 \ ------------------------------\
4328 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
4329 \ ------------------------------\
4330 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
4331 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
4332 \ ------------------------------\
4333 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
4334 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
4335 \ ------------------------------\
4336 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
4337 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
4338 \ ------------------------------\
4339 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
4340 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
4341 \ ------------------------------\
4342 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
4343 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
4344 \ ------------------------------\
4345 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
4346 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
4347 \ ------------------------------\
4348 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
4349 \ ------------------------------\
4350 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
4351 \ ------------------------------\
4352 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
4353 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
4354 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
4355 \ ------------------------------\
4356 BIS.B #LCDVo,&LCDVo_DIR \
4357 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
4358 \ ------------------------------\
4359 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
4360 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
4361 \ ------------------------------\
4362 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
4363 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
4364 \ ******************************\
4366 \ ******************************\
4367 BIS.B #RC5,&IR_IE \ enable RC5_Int
4368 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
4369 MOV #RC5_INT,&IR_Vec \ init interrupt vector
4370 \ ******************************\
4371 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
4372 \ ******************************\
4373 \ %01 0001 0100 \ TAxCTL
4374 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
4375 \ -- \ ID divided by 1
4376 \ -- \ MC MODE = up to TAxCCRn
4377 \ - \ TACLR clear timer count
4380 \ ------------------------------\
4381 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
4382 \ ------------------------------\
4384 \ --- \ TAIDEX pre divisor
4385 \ ------------------------------\
4386 \ %0000 0000 0000 0101 \ TAxCCR0
4387 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
4388 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
4389 \ ------------------------------\
4390 \ %0000 0000 0001 0000 \ TAxCCTL0
4391 \ - \ CAP capture/compare mode = compare
4394 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
4395 \ ------------------------------\
4396 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
4397 \ ------------------------------\
4398 \ define LPM mode for ACCEPT \
4399 \ ------------------------------\
4400 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
4401 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
4402 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
4404 \ ------------------------------\
4405 \ redirects to background task \
4406 \ ------------------------------\
4408 MOV #BACKGROUND,2(X) \
4409 \ ------------------------------\
4411 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
4413 \ ------------------------------\
4415 \ ------------------------------\
4416 $03E8 20_US \ 1- wait 20 ms
4417 $03 TOP_LCD \ 2- send DB5=DB4=1
4418 $CD 20_US \ 3- wait 4,1 ms
4419 $03 TOP_LCD \ 4- send again DB5=DB4=1
4420 $5 20_US \ 5- wait 0,1 ms
4421 $03 TOP_LCD \ 6- send again again DB5=DB4=1
4422 $2 20_US \ wait 40 us = LCD cycle
4423 $02 TOP_LCD \ 7- send DB5=1 DB4=0
4424 $2 20_US \ wait 40 us = LCD cycle
4425 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
4426 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
4427 LCD_Clear \ 10- "LCD_Clear"
4428 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
4429 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
4430 LCD_Clear \ 10- "LCD_Clear"
4431 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
4432 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
4434 ['] CR >BODY IS CR \
4435 ['] EMIT >BODY IS EMIT \
4436 ." RC5toLCD is running. Type STOP to quit"
4437 LIT RECURSE IS WARM \ replace WARM by this START routine
4438 ABORT \ and continue with the next word after WARM...
4439 ; \ ...until interpreter falls in sleep mode within ACCEPT.
4442 CODE STOP \ stops multitasking, must to be used before downloading app
4443 \ restore default action of primary DEFERred word SLEEP, assembly version
4444 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
4445 ADD #4,X \ X = BODY of SLEEP
4446 MOV X,-2(X) \ restore the default background
4449 \ restore default action of primary DEFERred word WARM, FORTH version
4450 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
4452 COLD \ because we want to reset CPU and interrupt vectors
4457 ; downloading RC5toLCD.4th is done
4458 RST_HERE ; this app is protected against <reset>
4466 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
4468 [DEFINED] ASM [IF] \ security test
4472 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
4474 CODE MAX \ n1 n2 -- n3 signed maximum
4475 CMP @PSP,TOS \ n2-n1
4476 S< ?GOTO FW1 \ n2<n1
4482 CODE MIN \ n1 n2 -- n3 signed minimum
4483 CMP @PSP,TOS \ n2-n1
4484 S< ?GOTO BW1 \ n2<n1
4492 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
4493 : U.R \ u n -- display u unsigned in n width (n >= 2)
4495 R> OVER - 0 MAX SPACES TYPE
4500 \ CODE 20_US \ n -- n * 20 us
4501 \ BEGIN \ 3 cycles loop + 6~
4502 \ \ MOV #5,W \ 3 MCLK = 1 MHz
4503 \ \ MOV #23,W \ 3 MCLK = 4 MHz
4504 \ \ MOV #51,W \ 3 MCLK = 8 MHz
4505 \ MOV #104,W \ 3 MCLK = 16 MHz
4506 \ \ MOV #158,W \ 3 MCLK = 24 MHz
4507 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
4517 CODE 20_US \ n -- n * 20 us
4518 BEGIN \ here we presume that LCD_TIM_IFG = 1...
4520 BIT #1,&LCD_TIM_CTL \ 3
4521 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
4522 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
4524 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
4530 CODE TOP_LCD \ LCD Sample
4531 \ \ if write : %xxxxWWWW --
4532 \ \ if read : -- %0000RRRR
4533 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
4534 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
4535 0= IF \ write LCD bits pattern
4537 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
4538 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
4541 THEN \ read LCD bits pattern
4544 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
4545 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
4551 CODE LCD_W \ byte -- write byte to LCD
4553 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
4554 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
4555 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
4556 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
4557 COLON \ high level word starts here
4558 TOP_LCD 2 20_US \ write high nibble first
4563 CODE LCD_WrC \ char -- Write Char
4564 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
4569 CODE LCD_WrF \ func -- Write Fonction
4570 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
4576 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
4581 $02 LCD_WrF 100 20_us
4587 \ https://forth-standard.org/standard/core/OR
4588 \ C OR x1 x2 -- x3 logical OR
4597 : LCD_Entry_set $04 OR LCD_WrF ;
4599 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
4601 : LCD_DSP_Shift $10 OR LCD_WrF ;
4603 : LCD_Fn_Set $20 OR LCD_WrF ;
4605 : LCD_CGRAM_Set $40 OR LCD_WrF ;
4607 : LCD_Goto $80 OR LCD_WrF ;
4609 CODE LCD_R \ -- byte read byte from LCD
4610 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
4611 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
4612 COLON \ starts a FORTH word
4613 TOP_LCD 2 20_us \ -- %0000HHHH
4614 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
4615 HI2LO \ switch from FORTH to assembler
4616 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
4617 ADD.B @PSP+,TOS \ -- %HHHHLLLL
4618 MOV @RSP+,IP \ restore IP saved by COLON
4623 CODE LCD_RdS \ -- status Read Status
4624 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
4629 CODE LCD_RdC \ -- char Read Char
4630 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
4636 \ ******************************\
4637 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
4638 \ ******************************\
4639 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
4640 BIT.B #SW2,&SW2_IN \ test switch S2
4641 0= IF \ case of switch S2 pressed
4642 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
4644 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
4647 BIT.B #SW1,&SW1_IN \ test switch S1 input
4648 0= IF \ case of Switch S1 pressed
4649 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
4651 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
4655 BW1 \ from quit on truncated RC5 message
4656 BW2 \ from repeated RC5 command
4657 BW3 \ from end of RC5_INT
4658 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
4663 \ ******************************\
4664 ASM RC5_INT \ wake up on Px.RC5 change interrupt
4665 \ ******************************\
4666 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
4667 \ ******************************\
4668 \ \ in : SR(9)=old Toggle bit memory (ADD on)
4669 \ \ SMclock = 8|16|24 MHz
4670 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
4671 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
4672 \ \ SR(9)=new Toggle bit memory (ADD on)
4673 \ ******************************\
4674 \ RC5_FirstStartBitHalfCycle: \
4675 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
4676 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
4677 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
4678 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
4679 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
4680 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
4681 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
4682 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
4683 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
4684 MOV #1778,X \ RC5_Period * 1us
4685 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
4686 MOV #14,W \ count of loop
4688 \ ******************************\
4689 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
4690 \ ******************************\ |
4691 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
4692 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
4693 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
4694 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
4695 \ RC5_Compute_3/4_Period: \ |
4696 RRUM #1,X \ X=1/2 cycle |
4699 ADD X,Y \ Y=3/4 cycle
4700 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
4702 \ ******************************\
4703 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
4704 \ ******************************\
4705 BIT.B #RC5,&IR_IN \ C_flag = IR bit
4706 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
4707 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
4708 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
4709 SUB #1,W \ decrement count loop
4710 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
4711 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
4712 0<> WHILE \ ----> out of loop ----+
4713 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
4715 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
4716 CMP Y,X \ 1 | cycle time out of bound ?
4718 BIC #$30,&RC5_TIM_CTL \ | | stop timer
4719 GOTO BW1 \ | | quit on truncated RC5 message
4721 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
4723 REPEAT \ ----> loop back --+ | with X = new RC5_period value
4724 \ ******************************\ |
4725 \ RC5_SampleEndOf: \ <---------------------+
4726 \ ******************************\
4727 BIC #$30,&RC5_TIM_CTL \ stop timer
4728 \ ******************************\
4729 \ RC5_ComputeNewRC5word \
4730 \ ******************************\
4731 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
4732 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
4733 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
4734 \ ******************************\
4735 \ RC5_ComputeC6bit \
4736 \ ******************************\
4737 BIT #BIT14,T \ test /C6 bit in T
4738 0= IF BIS #BIT6,X \ set C6 bit in X
4739 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
4740 \ ******************************\
4741 \ RC5_CommandByteIsDone \ -- BASE RC5_code
4742 \ ******************************\
4743 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
4744 \ ******************************\
4745 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
4746 XOR @RSP,T \ (new XOR old) Toggle bits
4747 BIT #UF10,T \ repeated RC5_command ?
4748 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
4749 XOR #UF10,0(RSP) \ 5 toggle bit memory
4750 \ ******************************\
4751 \ Display IR_RC5 code \ X = RC5 code
4752 \ ******************************\
4754 MOV &BASE,2(PSP) \ save current base
4755 MOV #$10,&BASE \ set hex base
4756 MOV TOS,0(PSP) \ save TOS
4758 LO2HI \ switch from assembler to FORTH
4759 ['] LCD_CLEAR IS CR \ redirects CR
4760 ['] LCD_WrC IS EMIT \ redirects EMIT
4761 CR ." $" 2 U.R \ print IR_RC5 code
4762 ['] CR >BODY IS CR \ restore CR
4763 ['] EMIT >BODY IS EMIT \ restore EMIT
4764 HI2LO \ switch from FORTH to assembler
4765 MOV TOS,&BASE \ restore current BASE
4767 \ ******************************\
4769 \ ******************************\
4773 \ ------------------------------\
4775 \ ------------------------------\
4776 \ ... \ insert here your background task
4779 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
4780 ADD #4,X \ 1 X = BODY of SLEEP
4783 \ ------------------------------\
4787 \ ------------------------------\
4788 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
4789 \ - - \CNTL Counter lentgh \ 00 = 16 bits
4790 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
4791 \ -- \ID input divider \ 10 = /4
4792 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
4793 \ - \TBCLR TimerB Clear
4796 \ -------------------------------\
4797 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
4798 \ -- \CM Capture Mode
4803 \ --- \OUTMOD \ 011 = set/reset
4809 \ -------------------------------\
4811 \ -------------------------------\
4813 \ ------------------------------\
4814 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
4815 \ ------------------------------\
4816 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
4817 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
4818 \ ------------------------------\
4819 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
4820 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
4821 \ ------------------------------\
4822 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
4823 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
4824 \ ------------------------------\
4825 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
4826 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
4827 \ ------------------------------\
4828 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
4829 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
4830 \ ------------------------------\
4831 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
4832 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
4833 \ ------------------------------\
4834 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
4835 \ ------------------------------\
4836 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
4837 \ ------------------------------\
4838 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
4839 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
4840 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
4841 \ ------------------------------\
4842 BIS.B #LCDVo,&LCDVo_DIR \
4843 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
4844 \ ------------------------------\
4845 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
4846 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
4847 \ ------------------------------\
4848 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
4849 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
4850 \ ******************************\
4852 \ ******************************\
4853 BIS.B #RC5,&IR_IE \ enable RC5_Int
4854 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
4855 MOV #RC5_INT,&IR_Vec \ init interrupt vector
4856 \ ******************************\
4857 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
4858 \ ******************************\
4859 \ %01 0001 0100 \ TAxCTL
4860 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
4861 \ -- \ ID divided by 1
4862 \ -- \ MC MODE = up to TAxCCRn
4863 \ - \ TACLR clear timer count
4866 \ ------------------------------\
4867 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
4868 \ ------------------------------\
4870 \ --- \ TAIDEX pre divisor
4871 \ ------------------------------\
4872 \ %0000 0000 0000 0101 \ TAxCCR0
4873 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
4874 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
4875 \ ------------------------------\
4876 \ %0000 0000 0001 0000 \ TAxCCTL0
4877 \ - \ CAP capture/compare mode = compare
4880 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
4881 \ ------------------------------\
4882 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
4883 \ ------------------------------\
4884 \ define LPM mode for ACCEPT \
4885 \ ------------------------------\
4886 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
4887 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
4888 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
4890 \ ------------------------------\
4891 \ redirects to background task \
4892 \ ------------------------------\
4894 MOV #BACKGROUND,2(X) \
4895 \ ------------------------------\
4897 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
4899 \ ------------------------------\
4901 \ ------------------------------\
4902 $03E8 20_US \ 1- wait 20 ms
4903 $03 TOP_LCD \ 2- send DB5=DB4=1
4904 $CD 20_US \ 3- wait 4,1 ms
4905 $03 TOP_LCD \ 4- send again DB5=DB4=1
4906 $5 20_US \ 5- wait 0,1 ms
4907 $03 TOP_LCD \ 6- send again again DB5=DB4=1
4908 $2 20_US \ wait 40 us = LCD cycle
4909 $02 TOP_LCD \ 7- send DB5=1 DB4=0
4910 $2 20_US \ wait 40 us = LCD cycle
4911 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
4912 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
4913 LCD_Clear \ 10- "LCD_Clear"
4914 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
4915 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
4916 LCD_Clear \ 10- "LCD_Clear"
4917 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
4918 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
4920 ['] CR >BODY IS CR \
4921 ['] EMIT >BODY IS EMIT \
4922 ." RC5toLCD is running. Type STOP to quit"
4923 LIT RECURSE IS WARM \ replace WARM by this START routine
4924 ABORT \ and continue with the next word after WARM...
4925 ; \ ...until interpreter falls in sleep mode within ACCEPT.
4928 CODE STOP \ stops multitasking, must to be used before downloading app
4929 \ restore default action of primary DEFERred word SLEEP, assembly version
4930 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
4931 ADD #4,X \ X = BODY of SLEEP
4932 MOV X,-2(X) \ restore the default background
4935 \ restore default action of primary DEFERred word WARM, FORTH version
4936 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
4938 COLD \ because we want to reset CPU and interrupt vectors
4943 ; downloading RC5toLCD.4th is done
4944 RST_HERE ; this app is protected against <reset>
4952 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
4954 [DEFINED] ASM [IF] \ security test
4958 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
4960 CODE MAX \ n1 n2 -- n3 signed maximum
4961 CMP @PSP,TOS \ n2-n1
4962 S< ?GOTO FW1 \ n2<n1
4968 CODE MIN \ n1 n2 -- n3 signed minimum
4969 CMP @PSP,TOS \ n2-n1
4970 S< ?GOTO BW1 \ n2<n1
4978 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
4979 : U.R \ u n -- display u unsigned in n width (n >= 2)
4981 R> OVER - 0 MAX SPACES TYPE
4986 \ CODE 20_US \ n -- n * 20 us
4987 \ BEGIN \ 3 cycles loop + 6~
4988 \ \ MOV #5,W \ 3 MCLK = 1 MHz
4989 \ \ MOV #23,W \ 3 MCLK = 4 MHz
4990 \ \ MOV #51,W \ 3 MCLK = 8 MHz
4991 \ MOV #104,W \ 3 MCLK = 16 MHz
4992 \ \ MOV #158,W \ 3 MCLK = 24 MHz
4993 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
5003 CODE 20_US \ n -- n * 20 us
5004 BEGIN \ here we presume that LCD_TIM_IFG = 1...
5006 BIT #1,&LCD_TIM_CTL \ 3
5007 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
5008 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
5010 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
5016 CODE TOP_LCD \ LCD Sample
5017 \ \ if write : %xxxxWWWW --
5018 \ \ if read : -- %0000RRRR
5019 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
5020 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
5021 0= IF \ write LCD bits pattern
5023 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
5024 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
5027 THEN \ read LCD bits pattern
5030 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
5031 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
5037 CODE LCD_W \ byte -- write byte to LCD
5039 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
5040 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
5041 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
5042 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
5043 COLON \ high level word starts here
5044 TOP_LCD 2 20_US \ write high nibble first
5049 CODE LCD_WrC \ char -- Write Char
5050 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
5055 CODE LCD_WrF \ func -- Write Fonction
5056 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
5062 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
5067 $02 LCD_WrF 100 20_us
5073 \ https://forth-standard.org/standard/core/OR
5074 \ C OR x1 x2 -- x3 logical OR
5083 : LCD_Entry_set $04 OR LCD_WrF ;
5085 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
5087 : LCD_DSP_Shift $10 OR LCD_WrF ;
5089 : LCD_Fn_Set $20 OR LCD_WrF ;
5091 : LCD_CGRAM_Set $40 OR LCD_WrF ;
5093 : LCD_Goto $80 OR LCD_WrF ;
5095 CODE LCD_R \ -- byte read byte from LCD
5096 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
5097 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
5098 COLON \ starts a FORTH word
5099 TOP_LCD 2 20_us \ -- %0000HHHH
5100 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
5101 HI2LO \ switch from FORTH to assembler
5102 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
5103 ADD.B @PSP+,TOS \ -- %HHHHLLLL
5104 MOV @RSP+,IP \ restore IP saved by COLON
5109 CODE LCD_RdS \ -- status Read Status
5110 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
5115 CODE LCD_RdC \ -- char Read Char
5116 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
5122 \ ******************************\
5123 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
5124 \ ******************************\
5125 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
5126 BIT.B #SW2,&SW2_IN \ test switch S2
5127 0= IF \ case of switch S2 pressed
5128 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
5130 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
5133 BIT.B #SW1,&SW1_IN \ test switch S1 input
5134 0= IF \ case of Switch S1 pressed
5135 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
5137 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
5141 BW1 \ from quit on truncated RC5 message
5142 BW2 \ from repeated RC5 command
5143 BW3 \ from end of RC5_INT
5144 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
5149 \ ******************************\
5150 ASM RC5_INT \ wake up on Px.RC5 change interrupt
5151 \ ******************************\
5152 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
5153 \ ******************************\
5154 \ \ in : SR(9)=old Toggle bit memory (ADD on)
5155 \ \ SMclock = 8|16|24 MHz
5156 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
5157 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
5158 \ \ SR(9)=new Toggle bit memory (ADD on)
5159 \ ******************************\
5160 \ RC5_FirstStartBitHalfCycle: \
5161 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
5162 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
5163 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
5164 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
5165 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
5166 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
5167 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
5168 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
5169 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
5170 MOV #1778,X \ RC5_Period * 1us
5171 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
5172 MOV #14,W \ count of loop
5174 \ ******************************\
5175 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
5176 \ ******************************\ |
5177 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
5178 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
5179 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
5180 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
5181 \ RC5_Compute_3/4_Period: \ |
5182 RRUM #1,X \ X=1/2 cycle |
5185 ADD X,Y \ Y=3/4 cycle
5186 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
5188 \ ******************************\
5189 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
5190 \ ******************************\
5191 BIT.B #RC5,&IR_IN \ C_flag = IR bit
5192 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
5193 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
5194 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
5195 SUB #1,W \ decrement count loop
5196 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
5197 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
5198 0<> WHILE \ ----> out of loop ----+
5199 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
5201 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
5202 CMP Y,X \ 1 | cycle time out of bound ?
5204 BIC #$30,&RC5_TIM_CTL \ | | stop timer
5205 GOTO BW1 \ | | quit on truncated RC5 message
5207 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
5209 REPEAT \ ----> loop back --+ | with X = new RC5_period value
5210 \ ******************************\ |
5211 \ RC5_SampleEndOf: \ <---------------------+
5212 \ ******************************\
5213 BIC #$30,&RC5_TIM_CTL \ stop timer
5214 \ ******************************\
5215 \ RC5_ComputeNewRC5word \
5216 \ ******************************\
5217 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
5218 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
5219 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
5220 \ ******************************\
5221 \ RC5_ComputeC6bit \
5222 \ ******************************\
5223 BIT #BIT14,T \ test /C6 bit in T
5224 0= IF BIS #BIT6,X \ set C6 bit in X
5225 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
5226 \ ******************************\
5227 \ RC5_CommandByteIsDone \ -- BASE RC5_code
5228 \ ******************************\
5229 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
5230 \ ******************************\
5231 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
5232 XOR @RSP,T \ (new XOR old) Toggle bits
5233 BIT #UF10,T \ repeated RC5_command ?
5234 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
5235 XOR #UF10,0(RSP) \ 5 toggle bit memory
5236 \ ******************************\
5237 \ Display IR_RC5 code \ X = RC5 code
5238 \ ******************************\
5240 MOV &BASE,2(PSP) \ save current base
5241 MOV #$10,&BASE \ set hex base
5242 MOV TOS,0(PSP) \ save TOS
5244 LO2HI \ switch from assembler to FORTH
5245 ['] LCD_CLEAR IS CR \ redirects CR
5246 ['] LCD_WrC IS EMIT \ redirects EMIT
5247 CR ." $" 2 U.R \ print IR_RC5 code
5248 ['] CR >BODY IS CR \ restore CR
5249 ['] EMIT >BODY IS EMIT \ restore EMIT
5250 HI2LO \ switch from FORTH to assembler
5251 MOV TOS,&BASE \ restore current BASE
5253 \ ******************************\
5255 \ ******************************\
5259 \ ------------------------------\
5261 \ ------------------------------\
5262 \ ... \ insert here your background task
5265 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
5266 ADD #4,X \ 1 X = BODY of SLEEP
5269 \ ------------------------------\
5273 \ ------------------------------\
5274 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
5275 \ - - \CNTL Counter lentgh \ 00 = 16 bits
5276 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
5277 \ -- \ID input divider \ 10 = /4
5278 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
5279 \ - \TBCLR TimerB Clear
5282 \ -------------------------------\
5283 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
5284 \ -- \CM Capture Mode
5289 \ --- \OUTMOD \ 011 = set/reset
5295 \ -------------------------------\
5297 \ -------------------------------\
5299 \ ------------------------------\
5300 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
5301 \ ------------------------------\
5302 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
5303 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
5304 \ ------------------------------\
5305 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
5306 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
5307 \ ------------------------------\
5308 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
5309 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
5310 \ ------------------------------\
5311 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
5312 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
5313 \ ------------------------------\
5314 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
5315 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
5316 \ ------------------------------\
5317 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
5318 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
5319 \ ------------------------------\
5320 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
5321 \ ------------------------------\
5322 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
5323 \ ------------------------------\
5324 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
5325 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
5326 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
5327 \ ------------------------------\
5328 BIS.B #LCDVo,&LCDVo_DIR \
5329 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
5330 \ ------------------------------\
5331 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
5332 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
5333 \ ------------------------------\
5334 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
5335 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
5336 \ ******************************\
5338 \ ******************************\
5339 BIS.B #RC5,&IR_IE \ enable RC5_Int
5340 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
5341 MOV #RC5_INT,&IR_Vec \ init interrupt vector
5342 \ ******************************\
5343 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
5344 \ ******************************\
5345 \ %01 0001 0100 \ TAxCTL
5346 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
5347 \ -- \ ID divided by 1
5348 \ -- \ MC MODE = up to TAxCCRn
5349 \ - \ TACLR clear timer count
5352 \ ------------------------------\
5353 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
5354 \ ------------------------------\
5356 \ --- \ TAIDEX pre divisor
5357 \ ------------------------------\
5358 \ %0000 0000 0000 0101 \ TAxCCR0
5359 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
5360 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
5361 \ ------------------------------\
5362 \ %0000 0000 0001 0000 \ TAxCCTL0
5363 \ - \ CAP capture/compare mode = compare
5366 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
5367 \ ------------------------------\
5368 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
5369 \ ------------------------------\
5370 \ define LPM mode for ACCEPT \
5371 \ ------------------------------\
5372 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
5373 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
5374 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
5376 \ ------------------------------\
5377 \ redirects to background task \
5378 \ ------------------------------\
5380 MOV #BACKGROUND,2(X) \
5381 \ ------------------------------\
5383 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
5385 \ ------------------------------\
5387 \ ------------------------------\
5388 $03E8 20_US \ 1- wait 20 ms
5389 $03 TOP_LCD \ 2- send DB5=DB4=1
5390 $CD 20_US \ 3- wait 4,1 ms
5391 $03 TOP_LCD \ 4- send again DB5=DB4=1
5392 $5 20_US \ 5- wait 0,1 ms
5393 $03 TOP_LCD \ 6- send again again DB5=DB4=1
5394 $2 20_US \ wait 40 us = LCD cycle
5395 $02 TOP_LCD \ 7- send DB5=1 DB4=0
5396 $2 20_US \ wait 40 us = LCD cycle
5397 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
5398 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
5399 LCD_Clear \ 10- "LCD_Clear"
5400 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
5401 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
5402 LCD_Clear \ 10- "LCD_Clear"
5403 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
5404 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
5406 ['] CR >BODY IS CR \
5407 ['] EMIT >BODY IS EMIT \
5408 ." RC5toLCD is running. Type STOP to quit"
5409 LIT RECURSE IS WARM \ replace WARM by this START routine
5410 ABORT \ and continue with the next word after WARM...
5411 ; \ ...until interpreter falls in sleep mode within ACCEPT.
5414 CODE STOP \ stops multitasking, must to be used before downloading app
5415 \ restore default action of primary DEFERred word SLEEP, assembly version
5416 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
5417 ADD #4,X \ X = BODY of SLEEP
5418 MOV X,-2(X) \ restore the default background
5421 \ restore default action of primary DEFERred word WARM, FORTH version
5422 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
5424 COLD \ because we want to reset CPU and interrupt vectors
5429 ; downloading RC5toLCD.4th is done
5430 RST_HERE ; this app is protected against <reset>
5438 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
5440 [DEFINED] ASM [IF] \ security test
5444 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
5446 CODE MAX \ n1 n2 -- n3 signed maximum
5447 CMP @PSP,TOS \ n2-n1
5448 S< ?GOTO FW1 \ n2<n1
5454 CODE MIN \ n1 n2 -- n3 signed minimum
5455 CMP @PSP,TOS \ n2-n1
5456 S< ?GOTO BW1 \ n2<n1
5464 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
5465 : U.R \ u n -- display u unsigned in n width (n >= 2)
5467 R> OVER - 0 MAX SPACES TYPE
5472 \ CODE 20_US \ n -- n * 20 us
5473 \ BEGIN \ 3 cycles loop + 6~
5474 \ \ MOV #5,W \ 3 MCLK = 1 MHz
5475 \ \ MOV #23,W \ 3 MCLK = 4 MHz
5476 \ \ MOV #51,W \ 3 MCLK = 8 MHz
5477 \ MOV #104,W \ 3 MCLK = 16 MHz
5478 \ \ MOV #158,W \ 3 MCLK = 24 MHz
5479 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
5489 CODE 20_US \ n -- n * 20 us
5490 BEGIN \ here we presume that LCD_TIM_IFG = 1...
5492 BIT #1,&LCD_TIM_CTL \ 3
5493 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
5494 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
5496 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
5502 CODE TOP_LCD \ LCD Sample
5503 \ \ if write : %xxxxWWWW --
5504 \ \ if read : -- %0000RRRR
5505 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
5506 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
5507 0= IF \ write LCD bits pattern
5509 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
5510 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
5513 THEN \ read LCD bits pattern
5516 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
5517 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
5523 CODE LCD_W \ byte -- write byte to LCD
5525 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
5526 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
5527 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
5528 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
5529 COLON \ high level word starts here
5530 TOP_LCD 2 20_US \ write high nibble first
5535 CODE LCD_WrC \ char -- Write Char
5536 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
5541 CODE LCD_WrF \ func -- Write Fonction
5542 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
5548 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
5553 $02 LCD_WrF 100 20_us
5559 \ https://forth-standard.org/standard/core/OR
5560 \ C OR x1 x2 -- x3 logical OR
5569 : LCD_Entry_set $04 OR LCD_WrF ;
5571 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
5573 : LCD_DSP_Shift $10 OR LCD_WrF ;
5575 : LCD_Fn_Set $20 OR LCD_WrF ;
5577 : LCD_CGRAM_Set $40 OR LCD_WrF ;
5579 : LCD_Goto $80 OR LCD_WrF ;
5581 CODE LCD_R \ -- byte read byte from LCD
5582 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
5583 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
5584 COLON \ starts a FORTH word
5585 TOP_LCD 2 20_us \ -- %0000HHHH
5586 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
5587 HI2LO \ switch from FORTH to assembler
5588 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
5589 ADD.B @PSP+,TOS \ -- %HHHHLLLL
5590 MOV @RSP+,IP \ restore IP saved by COLON
5595 CODE LCD_RdS \ -- status Read Status
5596 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
5601 CODE LCD_RdC \ -- char Read Char
5602 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
5608 \ ******************************\
5609 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
5610 \ ******************************\
5611 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
5612 BIT.B #SW2,&SW2_IN \ test switch S2
5613 0= IF \ case of switch S2 pressed
5614 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
5616 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
5619 BIT.B #SW1,&SW1_IN \ test switch S1 input
5620 0= IF \ case of Switch S1 pressed
5621 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
5623 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
5627 BW1 \ from quit on truncated RC5 message
5628 BW2 \ from repeated RC5 command
5629 BW3 \ from end of RC5_INT
5630 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
5635 \ ******************************\
5636 ASM RC5_INT \ wake up on Px.RC5 change interrupt
5637 \ ******************************\
5638 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
5639 \ ******************************\
5640 \ \ in : SR(9)=old Toggle bit memory (ADD on)
5641 \ \ SMclock = 8|16|24 MHz
5642 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
5643 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
5644 \ \ SR(9)=new Toggle bit memory (ADD on)
5645 \ ******************************\
5646 \ RC5_FirstStartBitHalfCycle: \
5647 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
5648 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
5649 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
5650 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
5651 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
5652 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
5653 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
5654 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
5655 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
5656 MOV #1778,X \ RC5_Period * 1us
5657 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
5658 MOV #14,W \ count of loop
5660 \ ******************************\
5661 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
5662 \ ******************************\ |
5663 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
5664 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
5665 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
5666 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
5667 \ RC5_Compute_3/4_Period: \ |
5668 RRUM #1,X \ X=1/2 cycle |
5671 ADD X,Y \ Y=3/4 cycle
5672 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
5674 \ ******************************\
5675 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
5676 \ ******************************\
5677 BIT.B #RC5,&IR_IN \ C_flag = IR bit
5678 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
5679 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
5680 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
5681 SUB #1,W \ decrement count loop
5682 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
5683 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
5684 0<> WHILE \ ----> out of loop ----+
5685 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
5687 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
5688 CMP Y,X \ 1 | cycle time out of bound ?
5690 BIC #$30,&RC5_TIM_CTL \ | | stop timer
5691 GOTO BW1 \ | | quit on truncated RC5 message
5693 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
5695 REPEAT \ ----> loop back --+ | with X = new RC5_period value
5696 \ ******************************\ |
5697 \ RC5_SampleEndOf: \ <---------------------+
5698 \ ******************************\
5699 BIC #$30,&RC5_TIM_CTL \ stop timer
5700 \ ******************************\
5701 \ RC5_ComputeNewRC5word \
5702 \ ******************************\
5703 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
5704 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
5705 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
5706 \ ******************************\
5707 \ RC5_ComputeC6bit \
5708 \ ******************************\
5709 BIT #BIT14,T \ test /C6 bit in T
5710 0= IF BIS #BIT6,X \ set C6 bit in X
5711 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
5712 \ ******************************\
5713 \ RC5_CommandByteIsDone \ -- BASE RC5_code
5714 \ ******************************\
5715 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
5716 \ ******************************\
5717 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
5718 XOR @RSP,T \ (new XOR old) Toggle bits
5719 BIT #UF10,T \ repeated RC5_command ?
5720 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
5721 XOR #UF10,0(RSP) \ 5 toggle bit memory
5722 \ ******************************\
5723 \ Display IR_RC5 code \ X = RC5 code
5724 \ ******************************\
5726 MOV &BASE,2(PSP) \ save current base
5727 MOV #$10,&BASE \ set hex base
5728 MOV TOS,0(PSP) \ save TOS
5730 LO2HI \ switch from assembler to FORTH
5731 ['] LCD_CLEAR IS CR \ redirects CR
5732 ['] LCD_WrC IS EMIT \ redirects EMIT
5733 CR ." $" 2 U.R \ print IR_RC5 code
5734 ['] CR >BODY IS CR \ restore CR
5735 ['] EMIT >BODY IS EMIT \ restore EMIT
5736 HI2LO \ switch from FORTH to assembler
5737 MOV TOS,&BASE \ restore current BASE
5739 \ ******************************\
5741 \ ******************************\
5745 \ ------------------------------\
5747 \ ------------------------------\
5748 \ ... \ insert here your background task
5751 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
5752 ADD #4,X \ 1 X = BODY of SLEEP
5755 \ ------------------------------\
5759 \ ------------------------------\
5760 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
5761 \ - - \CNTL Counter lentgh \ 00 = 16 bits
5762 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
5763 \ -- \ID input divider \ 10 = /4
5764 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
5765 \ - \TBCLR TimerB Clear
5768 \ -------------------------------\
5769 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
5770 \ -- \CM Capture Mode
5775 \ --- \OUTMOD \ 011 = set/reset
5781 \ -------------------------------\
5783 \ -------------------------------\
5785 \ ------------------------------\
5786 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
5787 \ ------------------------------\
5788 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
5789 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
5790 \ ------------------------------\
5791 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
5792 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
5793 \ ------------------------------\
5794 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
5795 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
5796 \ ------------------------------\
5797 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
5798 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
5799 \ ------------------------------\
5800 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
5801 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
5802 \ ------------------------------\
5803 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
5804 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
5805 \ ------------------------------\
5806 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
5807 \ ------------------------------\
5808 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
5809 \ ------------------------------\
5810 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
5811 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
5812 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
5813 \ ------------------------------\
5814 BIS.B #LCDVo,&LCDVo_DIR \
5815 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
5816 \ ------------------------------\
5817 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
5818 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
5819 \ ------------------------------\
5820 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
5821 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
5822 \ ******************************\
5824 \ ******************************\
5825 BIS.B #RC5,&IR_IE \ enable RC5_Int
5826 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
5827 MOV #RC5_INT,&IR_Vec \ init interrupt vector
5828 \ ******************************\
5829 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
5830 \ ******************************\
5831 \ %01 0001 0100 \ TAxCTL
5832 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
5833 \ -- \ ID divided by 1
5834 \ -- \ MC MODE = up to TAxCCRn
5835 \ - \ TACLR clear timer count
5838 \ ------------------------------\
5839 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
5840 \ ------------------------------\
5842 \ --- \ TAIDEX pre divisor
5843 \ ------------------------------\
5844 \ %0000 0000 0000 0101 \ TAxCCR0
5845 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
5846 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
5847 \ ------------------------------\
5848 \ %0000 0000 0001 0000 \ TAxCCTL0
5849 \ - \ CAP capture/compare mode = compare
5852 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
5853 \ ------------------------------\
5854 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
5855 \ ------------------------------\
5856 \ define LPM mode for ACCEPT \
5857 \ ------------------------------\
5858 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
5859 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
5860 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
5862 \ ------------------------------\
5863 \ redirects to background task \
5864 \ ------------------------------\
5866 MOV #BACKGROUND,2(X) \
5867 \ ------------------------------\
5869 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
5871 \ ------------------------------\
5873 \ ------------------------------\
5874 $03E8 20_US \ 1- wait 20 ms
5875 $03 TOP_LCD \ 2- send DB5=DB4=1
5876 $CD 20_US \ 3- wait 4,1 ms
5877 $03 TOP_LCD \ 4- send again DB5=DB4=1
5878 $5 20_US \ 5- wait 0,1 ms
5879 $03 TOP_LCD \ 6- send again again DB5=DB4=1
5880 $2 20_US \ wait 40 us = LCD cycle
5881 $02 TOP_LCD \ 7- send DB5=1 DB4=0
5882 $2 20_US \ wait 40 us = LCD cycle
5883 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
5884 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
5885 LCD_Clear \ 10- "LCD_Clear"
5886 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
5887 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
5888 LCD_Clear \ 10- "LCD_Clear"
5889 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
5890 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
5892 ['] CR >BODY IS CR \
5893 ['] EMIT >BODY IS EMIT \
5894 ." RC5toLCD is running. Type STOP to quit"
5895 LIT RECURSE IS WARM \ replace WARM by this START routine
5896 ABORT \ and continue with the next word after WARM...
5897 ; \ ...until interpreter falls in sleep mode within ACCEPT.
5900 CODE STOP \ stops multitasking, must to be used before downloading app
5901 \ restore default action of primary DEFERred word SLEEP, assembly version
5902 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
5903 ADD #4,X \ X = BODY of SLEEP
5904 MOV X,-2(X) \ restore the default background
5907 \ restore default action of primary DEFERred word WARM, FORTH version
5908 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
5910 COLD \ because we want to reset CPU and interrupt vectors
5915 ; downloading RC5toLCD.4th is done
5916 RST_HERE ; this app is protected against <reset>
5924 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
5926 [DEFINED] ASM [IF] \ security test
5930 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
5932 CODE MAX \ n1 n2 -- n3 signed maximum
5933 CMP @PSP,TOS \ n2-n1
5934 S< ?GOTO FW1 \ n2<n1
5940 CODE MIN \ n1 n2 -- n3 signed minimum
5941 CMP @PSP,TOS \ n2-n1
5942 S< ?GOTO BW1 \ n2<n1
5950 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
5951 : U.R \ u n -- display u unsigned in n width (n >= 2)
5953 R> OVER - 0 MAX SPACES TYPE
5958 \ CODE 20_US \ n -- n * 20 us
5959 \ BEGIN \ 3 cycles loop + 6~
5960 \ \ MOV #5,W \ 3 MCLK = 1 MHz
5961 \ \ MOV #23,W \ 3 MCLK = 4 MHz
5962 \ \ MOV #51,W \ 3 MCLK = 8 MHz
5963 \ MOV #104,W \ 3 MCLK = 16 MHz
5964 \ \ MOV #158,W \ 3 MCLK = 24 MHz
5965 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
5975 CODE 20_US \ n -- n * 20 us
5976 BEGIN \ here we presume that LCD_TIM_IFG = 1...
5978 BIT #1,&LCD_TIM_CTL \ 3
5979 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
5980 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
5982 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
5988 CODE TOP_LCD \ LCD Sample
5989 \ \ if write : %xxxxWWWW --
5990 \ \ if read : -- %0000RRRR
5991 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
5992 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
5993 0= IF \ write LCD bits pattern
5995 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
5996 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
5999 THEN \ read LCD bits pattern
6002 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
6003 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
6009 CODE LCD_W \ byte -- write byte to LCD
6011 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
6012 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
6013 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
6014 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
6015 COLON \ high level word starts here
6016 TOP_LCD 2 20_US \ write high nibble first
6021 CODE LCD_WrC \ char -- Write Char
6022 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
6027 CODE LCD_WrF \ func -- Write Fonction
6028 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
6034 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
6039 $02 LCD_WrF 100 20_us
6045 \ https://forth-standard.org/standard/core/OR
6046 \ C OR x1 x2 -- x3 logical OR
6055 : LCD_Entry_set $04 OR LCD_WrF ;
6057 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
6059 : LCD_DSP_Shift $10 OR LCD_WrF ;
6061 : LCD_Fn_Set $20 OR LCD_WrF ;
6063 : LCD_CGRAM_Set $40 OR LCD_WrF ;
6065 : LCD_Goto $80 OR LCD_WrF ;
6067 CODE LCD_R \ -- byte read byte from LCD
6068 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
6069 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
6070 COLON \ starts a FORTH word
6071 TOP_LCD 2 20_us \ -- %0000HHHH
6072 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
6073 HI2LO \ switch from FORTH to assembler
6074 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
6075 ADD.B @PSP+,TOS \ -- %HHHHLLLL
6076 MOV @RSP+,IP \ restore IP saved by COLON
6081 CODE LCD_RdS \ -- status Read Status
6082 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
6087 CODE LCD_RdC \ -- char Read Char
6088 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
6094 \ ******************************\
6095 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
6096 \ ******************************\
6097 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
6098 BIT.B #SW2,&SW2_IN \ test switch S2
6099 0= IF \ case of switch S2 pressed
6100 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
6102 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
6105 BIT.B #SW1,&SW1_IN \ test switch S1 input
6106 0= IF \ case of Switch S1 pressed
6107 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
6109 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
6113 BW1 \ from quit on truncated RC5 message
6114 BW2 \ from repeated RC5 command
6115 BW3 \ from end of RC5_INT
6116 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
6121 \ ******************************\
6122 ASM RC5_INT \ wake up on Px.RC5 change interrupt
6123 \ ******************************\
6124 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
6125 \ ******************************\
6126 \ \ in : SR(9)=old Toggle bit memory (ADD on)
6127 \ \ SMclock = 8|16|24 MHz
6128 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
6129 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
6130 \ \ SR(9)=new Toggle bit memory (ADD on)
6131 \ ******************************\
6132 \ RC5_FirstStartBitHalfCycle: \
6133 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
6134 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
6135 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
6136 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
6137 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
6138 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
6139 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
6140 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
6141 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
6142 MOV #1778,X \ RC5_Period * 1us
6143 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
6144 MOV #14,W \ count of loop
6146 \ ******************************\
6147 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
6148 \ ******************************\ |
6149 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
6150 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
6151 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
6152 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
6153 \ RC5_Compute_3/4_Period: \ |
6154 RRUM #1,X \ X=1/2 cycle |
6157 ADD X,Y \ Y=3/4 cycle
6158 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
6160 \ ******************************\
6161 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
6162 \ ******************************\
6163 BIT.B #RC5,&IR_IN \ C_flag = IR bit
6164 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
6165 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
6166 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
6167 SUB #1,W \ decrement count loop
6168 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
6169 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
6170 0<> WHILE \ ----> out of loop ----+
6171 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
6173 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
6174 CMP Y,X \ 1 | cycle time out of bound ?
6176 BIC #$30,&RC5_TIM_CTL \ | | stop timer
6177 GOTO BW1 \ | | quit on truncated RC5 message
6179 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
6181 REPEAT \ ----> loop back --+ | with X = new RC5_period value
6182 \ ******************************\ |
6183 \ RC5_SampleEndOf: \ <---------------------+
6184 \ ******************************\
6185 BIC #$30,&RC5_TIM_CTL \ stop timer
6186 \ ******************************\
6187 \ RC5_ComputeNewRC5word \
6188 \ ******************************\
6189 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
6190 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
6191 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
6192 \ ******************************\
6193 \ RC5_ComputeC6bit \
6194 \ ******************************\
6195 BIT #BIT14,T \ test /C6 bit in T
6196 0= IF BIS #BIT6,X \ set C6 bit in X
6197 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
6198 \ ******************************\
6199 \ RC5_CommandByteIsDone \ -- BASE RC5_code
6200 \ ******************************\
6201 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
6202 \ ******************************\
6203 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
6204 XOR @RSP,T \ (new XOR old) Toggle bits
6205 BIT #UF10,T \ repeated RC5_command ?
6206 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
6207 XOR #UF10,0(RSP) \ 5 toggle bit memory
6208 \ ******************************\
6209 \ Display IR_RC5 code \ X = RC5 code
6210 \ ******************************\
6212 MOV &BASE,2(PSP) \ save current base
6213 MOV #$10,&BASE \ set hex base
6214 MOV TOS,0(PSP) \ save TOS
6216 LO2HI \ switch from assembler to FORTH
6217 ['] LCD_CLEAR IS CR \ redirects CR
6218 ['] LCD_WrC IS EMIT \ redirects EMIT
6219 CR ." $" 2 U.R \ print IR_RC5 code
6220 ['] CR >BODY IS CR \ restore CR
6221 ['] EMIT >BODY IS EMIT \ restore EMIT
6222 HI2LO \ switch from FORTH to assembler
6223 MOV TOS,&BASE \ restore current BASE
6225 \ ******************************\
6227 \ ******************************\
6231 \ ------------------------------\
6233 \ ------------------------------\
6234 \ ... \ insert here your background task
6237 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
6238 ADD #4,X \ 1 X = BODY of SLEEP
6241 \ ------------------------------\
6245 \ ------------------------------\
6246 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
6247 \ - - \CNTL Counter lentgh \ 00 = 16 bits
6248 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
6249 \ -- \ID input divider \ 10 = /4
6250 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
6251 \ - \TBCLR TimerB Clear
6254 \ -------------------------------\
6255 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
6256 \ -- \CM Capture Mode
6261 \ --- \OUTMOD \ 011 = set/reset
6267 \ -------------------------------\
6269 \ -------------------------------\
6271 \ ------------------------------\
6272 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
6273 \ ------------------------------\
6274 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
6275 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
6276 \ ------------------------------\
6277 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
6278 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
6279 \ ------------------------------\
6280 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
6281 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
6282 \ ------------------------------\
6283 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
6284 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
6285 \ ------------------------------\
6286 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
6287 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
6288 \ ------------------------------\
6289 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
6290 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
6291 \ ------------------------------\
6292 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
6293 \ ------------------------------\
6294 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
6295 \ ------------------------------\
6296 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
6297 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
6298 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
6299 \ ------------------------------\
6300 BIS.B #LCDVo,&LCDVo_DIR \
6301 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
6302 \ ------------------------------\
6303 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
6304 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
6305 \ ------------------------------\
6306 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
6307 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
6308 \ ******************************\
6310 \ ******************************\
6311 BIS.B #RC5,&IR_IE \ enable RC5_Int
6312 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
6313 MOV #RC5_INT,&IR_Vec \ init interrupt vector
6314 \ ******************************\
6315 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
6316 \ ******************************\
6317 \ %01 0001 0100 \ TAxCTL
6318 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
6319 \ -- \ ID divided by 1
6320 \ -- \ MC MODE = up to TAxCCRn
6321 \ - \ TACLR clear timer count
6324 \ ------------------------------\
6325 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
6326 \ ------------------------------\
6328 \ --- \ TAIDEX pre divisor
6329 \ ------------------------------\
6330 \ %0000 0000 0000 0101 \ TAxCCR0
6331 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
6332 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
6333 \ ------------------------------\
6334 \ %0000 0000 0001 0000 \ TAxCCTL0
6335 \ - \ CAP capture/compare mode = compare
6338 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
6339 \ ------------------------------\
6340 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
6341 \ ------------------------------\
6342 \ define LPM mode for ACCEPT \
6343 \ ------------------------------\
6344 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
6345 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
6346 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
6348 \ ------------------------------\
6349 \ redirects to background task \
6350 \ ------------------------------\
6352 MOV #BACKGROUND,2(X) \
6353 \ ------------------------------\
6355 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
6357 \ ------------------------------\
6359 \ ------------------------------\
6360 $03E8 20_US \ 1- wait 20 ms
6361 $03 TOP_LCD \ 2- send DB5=DB4=1
6362 $CD 20_US \ 3- wait 4,1 ms
6363 $03 TOP_LCD \ 4- send again DB5=DB4=1
6364 $5 20_US \ 5- wait 0,1 ms
6365 $03 TOP_LCD \ 6- send again again DB5=DB4=1
6366 $2 20_US \ wait 40 us = LCD cycle
6367 $02 TOP_LCD \ 7- send DB5=1 DB4=0
6368 $2 20_US \ wait 40 us = LCD cycle
6369 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
6370 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
6371 LCD_Clear \ 10- "LCD_Clear"
6372 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
6373 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
6374 LCD_Clear \ 10- "LCD_Clear"
6375 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
6376 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
6378 ['] CR >BODY IS CR \
6379 ['] EMIT >BODY IS EMIT \
6380 ." RC5toLCD is running. Type STOP to quit"
6381 LIT RECURSE IS WARM \ replace WARM by this START routine
6382 ABORT \ and continue with the next word after WARM...
6383 ; \ ...until interpreter falls in sleep mode within ACCEPT.
6386 CODE STOP \ stops multitasking, must to be used before downloading app
6387 \ restore default action of primary DEFERred word SLEEP, assembly version
6388 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
6389 ADD #4,X \ X = BODY of SLEEP
6390 MOV X,-2(X) \ restore the default background
6393 \ restore default action of primary DEFERred word WARM, FORTH version
6394 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
6396 COLD \ because we want to reset CPU and interrupt vectors
6401 ; downloading RC5toLCD.4th is done
6402 RST_HERE ; this app is protected against <reset>
6410 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
6412 [DEFINED] ASM [IF] \ security test
6416 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
6418 CODE MAX \ n1 n2 -- n3 signed maximum
6419 CMP @PSP,TOS \ n2-n1
6420 S< ?GOTO FW1 \ n2<n1
6426 CODE MIN \ n1 n2 -- n3 signed minimum
6427 CMP @PSP,TOS \ n2-n1
6428 S< ?GOTO BW1 \ n2<n1
6436 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
6437 : U.R \ u n -- display u unsigned in n width (n >= 2)
6439 R> OVER - 0 MAX SPACES TYPE
6444 \ CODE 20_US \ n -- n * 20 us
6445 \ BEGIN \ 3 cycles loop + 6~
6446 \ \ MOV #5,W \ 3 MCLK = 1 MHz
6447 \ \ MOV #23,W \ 3 MCLK = 4 MHz
6448 \ \ MOV #51,W \ 3 MCLK = 8 MHz
6449 \ MOV #104,W \ 3 MCLK = 16 MHz
6450 \ \ MOV #158,W \ 3 MCLK = 24 MHz
6451 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
6461 CODE 20_US \ n -- n * 20 us
6462 BEGIN \ here we presume that LCD_TIM_IFG = 1...
6464 BIT #1,&LCD_TIM_CTL \ 3
6465 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
6466 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
6468 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
6474 CODE TOP_LCD \ LCD Sample
6475 \ \ if write : %xxxxWWWW --
6476 \ \ if read : -- %0000RRRR
6477 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
6478 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
6479 0= IF \ write LCD bits pattern
6481 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
6482 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
6485 THEN \ read LCD bits pattern
6488 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
6489 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
6495 CODE LCD_W \ byte -- write byte to LCD
6497 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
6498 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
6499 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
6500 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
6501 COLON \ high level word starts here
6502 TOP_LCD 2 20_US \ write high nibble first
6507 CODE LCD_WrC \ char -- Write Char
6508 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
6513 CODE LCD_WrF \ func -- Write Fonction
6514 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
6520 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
6525 $02 LCD_WrF 100 20_us
6531 \ https://forth-standard.org/standard/core/OR
6532 \ C OR x1 x2 -- x3 logical OR
6541 : LCD_Entry_set $04 OR LCD_WrF ;
6543 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
6545 : LCD_DSP_Shift $10 OR LCD_WrF ;
6547 : LCD_Fn_Set $20 OR LCD_WrF ;
6549 : LCD_CGRAM_Set $40 OR LCD_WrF ;
6551 : LCD_Goto $80 OR LCD_WrF ;
6553 CODE LCD_R \ -- byte read byte from LCD
6554 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
6555 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
6556 COLON \ starts a FORTH word
6557 TOP_LCD 2 20_us \ -- %0000HHHH
6558 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
6559 HI2LO \ switch from FORTH to assembler
6560 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
6561 ADD.B @PSP+,TOS \ -- %HHHHLLLL
6562 MOV @RSP+,IP \ restore IP saved by COLON
6567 CODE LCD_RdS \ -- status Read Status
6568 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
6573 CODE LCD_RdC \ -- char Read Char
6574 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
6580 \ ******************************\
6581 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
6582 \ ******************************\
6583 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
6584 BIT.B #SW2,&SW2_IN \ test switch S2
6585 0= IF \ case of switch S2 pressed
6586 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
6588 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
6591 BIT.B #SW1,&SW1_IN \ test switch S1 input
6592 0= IF \ case of Switch S1 pressed
6593 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
6595 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
6599 BW1 \ from quit on truncated RC5 message
6600 BW2 \ from repeated RC5 command
6601 BW3 \ from end of RC5_INT
6602 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
6607 \ ******************************\
6608 ASM RC5_INT \ wake up on Px.RC5 change interrupt
6609 \ ******************************\
6610 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
6611 \ ******************************\
6612 \ \ in : SR(9)=old Toggle bit memory (ADD on)
6613 \ \ SMclock = 8|16|24 MHz
6614 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
6615 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
6616 \ \ SR(9)=new Toggle bit memory (ADD on)
6617 \ ******************************\
6618 \ RC5_FirstStartBitHalfCycle: \
6619 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
6620 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
6621 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
6622 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
6623 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
6624 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
6625 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
6626 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
6627 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
6628 MOV #1778,X \ RC5_Period * 1us
6629 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
6630 MOV #14,W \ count of loop
6632 \ ******************************\
6633 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
6634 \ ******************************\ |
6635 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
6636 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
6637 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
6638 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
6639 \ RC5_Compute_3/4_Period: \ |
6640 RRUM #1,X \ X=1/2 cycle |
6643 ADD X,Y \ Y=3/4 cycle
6644 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
6646 \ ******************************\
6647 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
6648 \ ******************************\
6649 BIT.B #RC5,&IR_IN \ C_flag = IR bit
6650 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
6651 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
6652 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
6653 SUB #1,W \ decrement count loop
6654 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
6655 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
6656 0<> WHILE \ ----> out of loop ----+
6657 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
6659 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
6660 CMP Y,X \ 1 | cycle time out of bound ?
6662 BIC #$30,&RC5_TIM_CTL \ | | stop timer
6663 GOTO BW1 \ | | quit on truncated RC5 message
6665 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
6667 REPEAT \ ----> loop back --+ | with X = new RC5_period value
6668 \ ******************************\ |
6669 \ RC5_SampleEndOf: \ <---------------------+
6670 \ ******************************\
6671 BIC #$30,&RC5_TIM_CTL \ stop timer
6672 \ ******************************\
6673 \ RC5_ComputeNewRC5word \
6674 \ ******************************\
6675 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
6676 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
6677 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
6678 \ ******************************\
6679 \ RC5_ComputeC6bit \
6680 \ ******************************\
6681 BIT #BIT14,T \ test /C6 bit in T
6682 0= IF BIS #BIT6,X \ set C6 bit in X
6683 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
6684 \ ******************************\
6685 \ RC5_CommandByteIsDone \ -- BASE RC5_code
6686 \ ******************************\
6687 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
6688 \ ******************************\
6689 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
6690 XOR @RSP,T \ (new XOR old) Toggle bits
6691 BIT #UF10,T \ repeated RC5_command ?
6692 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
6693 XOR #UF10,0(RSP) \ 5 toggle bit memory
6694 \ ******************************\
6695 \ Display IR_RC5 code \ X = RC5 code
6696 \ ******************************\
6698 MOV &BASE,2(PSP) \ save current base
6699 MOV #$10,&BASE \ set hex base
6700 MOV TOS,0(PSP) \ save TOS
6702 LO2HI \ switch from assembler to FORTH
6703 ['] LCD_CLEAR IS CR \ redirects CR
6704 ['] LCD_WrC IS EMIT \ redirects EMIT
6705 CR ." $" 2 U.R \ print IR_RC5 code
6706 ['] CR >BODY IS CR \ restore CR
6707 ['] EMIT >BODY IS EMIT \ restore EMIT
6708 HI2LO \ switch from FORTH to assembler
6709 MOV TOS,&BASE \ restore current BASE
6711 \ ******************************\
6713 \ ******************************\
6717 \ ------------------------------\
6719 \ ------------------------------\
6720 \ ... \ insert here your background task
6723 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
6724 ADD #4,X \ 1 X = BODY of SLEEP
6727 \ ------------------------------\
6731 \ ------------------------------\
6732 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
6733 \ - - \CNTL Counter lentgh \ 00 = 16 bits
6734 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
6735 \ -- \ID input divider \ 10 = /4
6736 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
6737 \ - \TBCLR TimerB Clear
6740 \ -------------------------------\
6741 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
6742 \ -- \CM Capture Mode
6747 \ --- \OUTMOD \ 011 = set/reset
6753 \ -------------------------------\
6755 \ -------------------------------\
6757 \ ------------------------------\
6758 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
6759 \ ------------------------------\
6760 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
6761 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
6762 \ ------------------------------\
6763 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
6764 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
6765 \ ------------------------------\
6766 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
6767 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
6768 \ ------------------------------\
6769 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
6770 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
6771 \ ------------------------------\
6772 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
6773 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
6774 \ ------------------------------\
6775 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
6776 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
6777 \ ------------------------------\
6778 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
6779 \ ------------------------------\
6780 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
6781 \ ------------------------------\
6782 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
6783 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
6784 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
6785 \ ------------------------------\
6786 BIS.B #LCDVo,&LCDVo_DIR \
6787 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
6788 \ ------------------------------\
6789 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
6790 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
6791 \ ------------------------------\
6792 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
6793 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
6794 \ ******************************\
6796 \ ******************************\
6797 BIS.B #RC5,&IR_IE \ enable RC5_Int
6798 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
6799 MOV #RC5_INT,&IR_Vec \ init interrupt vector
6800 \ ******************************\
6801 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
6802 \ ******************************\
6803 \ %01 0001 0100 \ TAxCTL
6804 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
6805 \ -- \ ID divided by 1
6806 \ -- \ MC MODE = up to TAxCCRn
6807 \ - \ TACLR clear timer count
6810 \ ------------------------------\
6811 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
6812 \ ------------------------------\
6814 \ --- \ TAIDEX pre divisor
6815 \ ------------------------------\
6816 \ %0000 0000 0000 0101 \ TAxCCR0
6817 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
6818 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
6819 \ ------------------------------\
6820 \ %0000 0000 0001 0000 \ TAxCCTL0
6821 \ - \ CAP capture/compare mode = compare
6824 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
6825 \ ------------------------------\
6826 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
6827 \ ------------------------------\
6828 \ define LPM mode for ACCEPT \
6829 \ ------------------------------\
6830 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
6831 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
6832 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
6834 \ ------------------------------\
6835 \ redirects to background task \
6836 \ ------------------------------\
6838 MOV #BACKGROUND,2(X) \
6839 \ ------------------------------\
6841 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
6843 \ ------------------------------\
6845 \ ------------------------------\
6846 $03E8 20_US \ 1- wait 20 ms
6847 $03 TOP_LCD \ 2- send DB5=DB4=1
6848 $CD 20_US \ 3- wait 4,1 ms
6849 $03 TOP_LCD \ 4- send again DB5=DB4=1
6850 $5 20_US \ 5- wait 0,1 ms
6851 $03 TOP_LCD \ 6- send again again DB5=DB4=1
6852 $2 20_US \ wait 40 us = LCD cycle
6853 $02 TOP_LCD \ 7- send DB5=1 DB4=0
6854 $2 20_US \ wait 40 us = LCD cycle
6855 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
6856 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
6857 LCD_Clear \ 10- "LCD_Clear"
6858 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
6859 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
6860 LCD_Clear \ 10- "LCD_Clear"
6861 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
6862 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
6864 ['] CR >BODY IS CR \
6865 ['] EMIT >BODY IS EMIT \
6866 ." RC5toLCD is running. Type STOP to quit"
6867 LIT RECURSE IS WARM \ replace WARM by this START routine
6868 ABORT \ and continue with the next word after WARM...
6869 ; \ ...until interpreter falls in sleep mode within ACCEPT.
6872 CODE STOP \ stops multitasking, must to be used before downloading app
6873 \ restore default action of primary DEFERred word SLEEP, assembly version
6874 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
6875 ADD #4,X \ X = BODY of SLEEP
6876 MOV X,-2(X) \ restore the default background
6879 \ restore default action of primary DEFERred word WARM, FORTH version
6880 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
6882 COLD \ because we want to reset CPU and interrupt vectors
6887 ; downloading RC5toLCD.4th is done
6888 RST_HERE ; this app is protected against <reset>
6896 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
6898 [DEFINED] ASM [IF] \ security test
6902 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
6904 CODE MAX \ n1 n2 -- n3 signed maximum
6905 CMP @PSP,TOS \ n2-n1
6906 S< ?GOTO FW1 \ n2<n1
6912 CODE MIN \ n1 n2 -- n3 signed minimum
6913 CMP @PSP,TOS \ n2-n1
6914 S< ?GOTO BW1 \ n2<n1
6922 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
6923 : U.R \ u n -- display u unsigned in n width (n >= 2)
6925 R> OVER - 0 MAX SPACES TYPE
6930 \ CODE 20_US \ n -- n * 20 us
6931 \ BEGIN \ 3 cycles loop + 6~
6932 \ \ MOV #5,W \ 3 MCLK = 1 MHz
6933 \ \ MOV #23,W \ 3 MCLK = 4 MHz
6934 \ \ MOV #51,W \ 3 MCLK = 8 MHz
6935 \ MOV #104,W \ 3 MCLK = 16 MHz
6936 \ \ MOV #158,W \ 3 MCLK = 24 MHz
6937 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
6947 CODE 20_US \ n -- n * 20 us
6948 BEGIN \ here we presume that LCD_TIM_IFG = 1...
6950 BIT #1,&LCD_TIM_CTL \ 3
6951 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
6952 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
6954 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
6960 CODE TOP_LCD \ LCD Sample
6961 \ \ if write : %xxxxWWWW --
6962 \ \ if read : -- %0000RRRR
6963 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
6964 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
6965 0= IF \ write LCD bits pattern
6967 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
6968 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
6971 THEN \ read LCD bits pattern
6974 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
6975 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
6981 CODE LCD_W \ byte -- write byte to LCD
6983 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
6984 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
6985 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
6986 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
6987 COLON \ high level word starts here
6988 TOP_LCD 2 20_US \ write high nibble first
6993 CODE LCD_WrC \ char -- Write Char
6994 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
6999 CODE LCD_WrF \ func -- Write Fonction
7000 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
7006 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
7011 $02 LCD_WrF 100 20_us
7017 \ https://forth-standard.org/standard/core/OR
7018 \ C OR x1 x2 -- x3 logical OR
7027 : LCD_Entry_set $04 OR LCD_WrF ;
7029 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
7031 : LCD_DSP_Shift $10 OR LCD_WrF ;
7033 : LCD_Fn_Set $20 OR LCD_WrF ;
7035 : LCD_CGRAM_Set $40 OR LCD_WrF ;
7037 : LCD_Goto $80 OR LCD_WrF ;
7039 CODE LCD_R \ -- byte read byte from LCD
7040 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
7041 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
7042 COLON \ starts a FORTH word
7043 TOP_LCD 2 20_us \ -- %0000HHHH
7044 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
7045 HI2LO \ switch from FORTH to assembler
7046 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
7047 ADD.B @PSP+,TOS \ -- %HHHHLLLL
7048 MOV @RSP+,IP \ restore IP saved by COLON
7053 CODE LCD_RdS \ -- status Read Status
7054 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
7059 CODE LCD_RdC \ -- char Read Char
7060 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
7066 \ ******************************\
7067 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
7068 \ ******************************\
7069 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
7070 BIT.B #SW2,&SW2_IN \ test switch S2
7071 0= IF \ case of switch S2 pressed
7072 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
7074 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
7077 BIT.B #SW1,&SW1_IN \ test switch S1 input
7078 0= IF \ case of Switch S1 pressed
7079 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
7081 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
7085 BW1 \ from quit on truncated RC5 message
7086 BW2 \ from repeated RC5 command
7087 BW3 \ from end of RC5_INT
7088 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
7093 \ ******************************\
7094 ASM RC5_INT \ wake up on Px.RC5 change interrupt
7095 \ ******************************\
7096 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
7097 \ ******************************\
7098 \ \ in : SR(9)=old Toggle bit memory (ADD on)
7099 \ \ SMclock = 8|16|24 MHz
7100 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
7101 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
7102 \ \ SR(9)=new Toggle bit memory (ADD on)
7103 \ ******************************\
7104 \ RC5_FirstStartBitHalfCycle: \
7105 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
7106 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
7107 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
7108 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
7109 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
7110 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
7111 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
7112 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
7113 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
7114 MOV #1778,X \ RC5_Period * 1us
7115 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
7116 MOV #14,W \ count of loop
7118 \ ******************************\
7119 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
7120 \ ******************************\ |
7121 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
7122 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
7123 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
7124 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
7125 \ RC5_Compute_3/4_Period: \ |
7126 RRUM #1,X \ X=1/2 cycle |
7129 ADD X,Y \ Y=3/4 cycle
7130 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
7132 \ ******************************\
7133 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
7134 \ ******************************\
7135 BIT.B #RC5,&IR_IN \ C_flag = IR bit
7136 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
7137 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
7138 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
7139 SUB #1,W \ decrement count loop
7140 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
7141 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
7142 0<> WHILE \ ----> out of loop ----+
7143 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
7145 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
7146 CMP Y,X \ 1 | cycle time out of bound ?
7148 BIC #$30,&RC5_TIM_CTL \ | | stop timer
7149 GOTO BW1 \ | | quit on truncated RC5 message
7151 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
7153 REPEAT \ ----> loop back --+ | with X = new RC5_period value
7154 \ ******************************\ |
7155 \ RC5_SampleEndOf: \ <---------------------+
7156 \ ******************************\
7157 BIC #$30,&RC5_TIM_CTL \ stop timer
7158 \ ******************************\
7159 \ RC5_ComputeNewRC5word \
7160 \ ******************************\
7161 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
7162 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
7163 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
7164 \ ******************************\
7165 \ RC5_ComputeC6bit \
7166 \ ******************************\
7167 BIT #BIT14,T \ test /C6 bit in T
7168 0= IF BIS #BIT6,X \ set C6 bit in X
7169 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
7170 \ ******************************\
7171 \ RC5_CommandByteIsDone \ -- BASE RC5_code
7172 \ ******************************\
7173 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
7174 \ ******************************\
7175 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
7176 XOR @RSP,T \ (new XOR old) Toggle bits
7177 BIT #UF10,T \ repeated RC5_command ?
7178 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
7179 XOR #UF10,0(RSP) \ 5 toggle bit memory
7180 \ ******************************\
7181 \ Display IR_RC5 code \ X = RC5 code
7182 \ ******************************\
7184 MOV &BASE,2(PSP) \ save current base
7185 MOV #$10,&BASE \ set hex base
7186 MOV TOS,0(PSP) \ save TOS
7188 LO2HI \ switch from assembler to FORTH
7189 ['] LCD_CLEAR IS CR \ redirects CR
7190 ['] LCD_WrC IS EMIT \ redirects EMIT
7191 CR ." $" 2 U.R \ print IR_RC5 code
7192 ['] CR >BODY IS CR \ restore CR
7193 ['] EMIT >BODY IS EMIT \ restore EMIT
7194 HI2LO \ switch from FORTH to assembler
7195 MOV TOS,&BASE \ restore current BASE
7197 \ ******************************\
7199 \ ******************************\
7203 \ ------------------------------\
7205 \ ------------------------------\
7206 \ ... \ insert here your background task
7209 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
7210 ADD #4,X \ 1 X = BODY of SLEEP
7213 \ ------------------------------\
7217 \ ------------------------------\
7218 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
7219 \ - - \CNTL Counter lentgh \ 00 = 16 bits
7220 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
7221 \ -- \ID input divider \ 10 = /4
7222 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
7223 \ - \TBCLR TimerB Clear
7226 \ -------------------------------\
7227 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
7228 \ -- \CM Capture Mode
7233 \ --- \OUTMOD \ 011 = set/reset
7239 \ -------------------------------\
7241 \ -------------------------------\
7243 \ ------------------------------\
7244 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
7245 \ ------------------------------\
7246 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
7247 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
7248 \ ------------------------------\
7249 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
7250 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
7251 \ ------------------------------\
7252 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
7253 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
7254 \ ------------------------------\
7255 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
7256 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
7257 \ ------------------------------\
7258 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
7259 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
7260 \ ------------------------------\
7261 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
7262 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
7263 \ ------------------------------\
7264 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
7265 \ ------------------------------\
7266 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
7267 \ ------------------------------\
7268 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
7269 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
7270 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
7271 \ ------------------------------\
7272 BIS.B #LCDVo,&LCDVo_DIR \
7273 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
7274 \ ------------------------------\
7275 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
7276 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
7277 \ ------------------------------\
7278 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
7279 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
7280 \ ******************************\
7282 \ ******************************\
7283 BIS.B #RC5,&IR_IE \ enable RC5_Int
7284 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
7285 MOV #RC5_INT,&IR_Vec \ init interrupt vector
7286 \ ******************************\
7287 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
7288 \ ******************************\
7289 \ %01 0001 0100 \ TAxCTL
7290 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
7291 \ -- \ ID divided by 1
7292 \ -- \ MC MODE = up to TAxCCRn
7293 \ - \ TACLR clear timer count
7296 \ ------------------------------\
7297 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
7298 \ ------------------------------\
7300 \ --- \ TAIDEX pre divisor
7301 \ ------------------------------\
7302 \ %0000 0000 0000 0101 \ TAxCCR0
7303 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
7304 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
7305 \ ------------------------------\
7306 \ %0000 0000 0001 0000 \ TAxCCTL0
7307 \ - \ CAP capture/compare mode = compare
7310 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
7311 \ ------------------------------\
7312 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
7313 \ ------------------------------\
7314 \ define LPM mode for ACCEPT \
7315 \ ------------------------------\
7316 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
7317 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
7318 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
7320 \ ------------------------------\
7321 \ redirects to background task \
7322 \ ------------------------------\
7324 MOV #BACKGROUND,2(X) \
7325 \ ------------------------------\
7327 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
7329 \ ------------------------------\
7331 \ ------------------------------\
7332 $03E8 20_US \ 1- wait 20 ms
7333 $03 TOP_LCD \ 2- send DB5=DB4=1
7334 $CD 20_US \ 3- wait 4,1 ms
7335 $03 TOP_LCD \ 4- send again DB5=DB4=1
7336 $5 20_US \ 5- wait 0,1 ms
7337 $03 TOP_LCD \ 6- send again again DB5=DB4=1
7338 $2 20_US \ wait 40 us = LCD cycle
7339 $02 TOP_LCD \ 7- send DB5=1 DB4=0
7340 $2 20_US \ wait 40 us = LCD cycle
7341 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
7342 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
7343 LCD_Clear \ 10- "LCD_Clear"
7344 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
7345 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
7346 LCD_Clear \ 10- "LCD_Clear"
7347 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
7348 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
7350 ['] CR >BODY IS CR \
7351 ['] EMIT >BODY IS EMIT \
7352 ." RC5toLCD is running. Type STOP to quit"
7353 LIT RECURSE IS WARM \ replace WARM by this START routine
7354 ABORT \ and continue with the next word after WARM...
7355 ; \ ...until interpreter falls in sleep mode within ACCEPT.
7358 CODE STOP \ stops multitasking, must to be used before downloading app
7359 \ restore default action of primary DEFERred word SLEEP, assembly version
7360 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
7361 ADD #4,X \ X = BODY of SLEEP
7362 MOV X,-2(X) \ restore the default background
7365 \ restore default action of primary DEFERred word WARM, FORTH version
7366 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
7368 COLD \ because we want to reset CPU and interrupt vectors
7373 ; downloading RC5toLCD.4th is done
7374 RST_HERE ; this app is protected against <reset>
7382 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
7384 [DEFINED] ASM [IF] \ security test
7388 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
7390 CODE MAX \ n1 n2 -- n3 signed maximum
7391 CMP @PSP,TOS \ n2-n1
7392 S< ?GOTO FW1 \ n2<n1
7398 CODE MIN \ n1 n2 -- n3 signed minimum
7399 CMP @PSP,TOS \ n2-n1
7400 S< ?GOTO BW1 \ n2<n1
7408 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
7409 : U.R \ u n -- display u unsigned in n width (n >= 2)
7411 R> OVER - 0 MAX SPACES TYPE
7416 \ CODE 20_US \ n -- n * 20 us
7417 \ BEGIN \ 3 cycles loop + 6~
7418 \ \ MOV #5,W \ 3 MCLK = 1 MHz
7419 \ \ MOV #23,W \ 3 MCLK = 4 MHz
7420 \ \ MOV #51,W \ 3 MCLK = 8 MHz
7421 \ MOV #104,W \ 3 MCLK = 16 MHz
7422 \ \ MOV #158,W \ 3 MCLK = 24 MHz
7423 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
7433 CODE 20_US \ n -- n * 20 us
7434 BEGIN \ here we presume that LCD_TIM_IFG = 1...
7436 BIT #1,&LCD_TIM_CTL \ 3
7437 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
7438 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
7440 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
7446 CODE TOP_LCD \ LCD Sample
7447 \ \ if write : %xxxxWWWW --
7448 \ \ if read : -- %0000RRRR
7449 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
7450 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
7451 0= IF \ write LCD bits pattern
7453 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
7454 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
7457 THEN \ read LCD bits pattern
7460 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
7461 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
7467 CODE LCD_W \ byte -- write byte to LCD
7469 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
7470 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
7471 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
7472 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
7473 COLON \ high level word starts here
7474 TOP_LCD 2 20_US \ write high nibble first
7479 CODE LCD_WrC \ char -- Write Char
7480 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
7485 CODE LCD_WrF \ func -- Write Fonction
7486 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
7492 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
7497 $02 LCD_WrF 100 20_us
7503 \ https://forth-standard.org/standard/core/OR
7504 \ C OR x1 x2 -- x3 logical OR
7513 : LCD_Entry_set $04 OR LCD_WrF ;
7515 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
7517 : LCD_DSP_Shift $10 OR LCD_WrF ;
7519 : LCD_Fn_Set $20 OR LCD_WrF ;
7521 : LCD_CGRAM_Set $40 OR LCD_WrF ;
7523 : LCD_Goto $80 OR LCD_WrF ;
7525 CODE LCD_R \ -- byte read byte from LCD
7526 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
7527 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
7528 COLON \ starts a FORTH word
7529 TOP_LCD 2 20_us \ -- %0000HHHH
7530 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
7531 HI2LO \ switch from FORTH to assembler
7532 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
7533 ADD.B @PSP+,TOS \ -- %HHHHLLLL
7534 MOV @RSP+,IP \ restore IP saved by COLON
7539 CODE LCD_RdS \ -- status Read Status
7540 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
7545 CODE LCD_RdC \ -- char Read Char
7546 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
7552 \ ******************************\
7553 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
7554 \ ******************************\
7555 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
7556 BIT.B #SW2,&SW2_IN \ test switch S2
7557 0= IF \ case of switch S2 pressed
7558 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
7560 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
7563 BIT.B #SW1,&SW1_IN \ test switch S1 input
7564 0= IF \ case of Switch S1 pressed
7565 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
7567 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
7571 BW1 \ from quit on truncated RC5 message
7572 BW2 \ from repeated RC5 command
7573 BW3 \ from end of RC5_INT
7574 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
7579 \ ******************************\
7580 ASM RC5_INT \ wake up on Px.RC5 change interrupt
7581 \ ******************************\
7582 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
7583 \ ******************************\
7584 \ \ in : SR(9)=old Toggle bit memory (ADD on)
7585 \ \ SMclock = 8|16|24 MHz
7586 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
7587 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
7588 \ \ SR(9)=new Toggle bit memory (ADD on)
7589 \ ******************************\
7590 \ RC5_FirstStartBitHalfCycle: \
7591 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
7592 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
7593 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
7594 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
7595 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
7596 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
7597 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
7598 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
7599 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
7600 MOV #1778,X \ RC5_Period * 1us
7601 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
7602 MOV #14,W \ count of loop
7604 \ ******************************\
7605 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
7606 \ ******************************\ |
7607 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
7608 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
7609 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
7610 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
7611 \ RC5_Compute_3/4_Period: \ |
7612 RRUM #1,X \ X=1/2 cycle |
7615 ADD X,Y \ Y=3/4 cycle
7616 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
7618 \ ******************************\
7619 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
7620 \ ******************************\
7621 BIT.B #RC5,&IR_IN \ C_flag = IR bit
7622 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
7623 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
7624 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
7625 SUB #1,W \ decrement count loop
7626 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
7627 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
7628 0<> WHILE \ ----> out of loop ----+
7629 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
7631 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
7632 CMP Y,X \ 1 | cycle time out of bound ?
7634 BIC #$30,&RC5_TIM_CTL \ | | stop timer
7635 GOTO BW1 \ | | quit on truncated RC5 message
7637 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
7639 REPEAT \ ----> loop back --+ | with X = new RC5_period value
7640 \ ******************************\ |
7641 \ RC5_SampleEndOf: \ <---------------------+
7642 \ ******************************\
7643 BIC #$30,&RC5_TIM_CTL \ stop timer
7644 \ ******************************\
7645 \ RC5_ComputeNewRC5word \
7646 \ ******************************\
7647 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
7648 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
7649 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
7650 \ ******************************\
7651 \ RC5_ComputeC6bit \
7652 \ ******************************\
7653 BIT #BIT14,T \ test /C6 bit in T
7654 0= IF BIS #BIT6,X \ set C6 bit in X
7655 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
7656 \ ******************************\
7657 \ RC5_CommandByteIsDone \ -- BASE RC5_code
7658 \ ******************************\
7659 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
7660 \ ******************************\
7661 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
7662 XOR @RSP,T \ (new XOR old) Toggle bits
7663 BIT #UF10,T \ repeated RC5_command ?
7664 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
7665 XOR #UF10,0(RSP) \ 5 toggle bit memory
7666 \ ******************************\
7667 \ Display IR_RC5 code \ X = RC5 code
7668 \ ******************************\
7670 MOV &BASE,2(PSP) \ save current base
7671 MOV #$10,&BASE \ set hex base
7672 MOV TOS,0(PSP) \ save TOS
7674 LO2HI \ switch from assembler to FORTH
7675 ['] LCD_CLEAR IS CR \ redirects CR
7676 ['] LCD_WrC IS EMIT \ redirects EMIT
7677 CR ." $" 2 U.R \ print IR_RC5 code
7678 ['] CR >BODY IS CR \ restore CR
7679 ['] EMIT >BODY IS EMIT \ restore EMIT
7680 HI2LO \ switch from FORTH to assembler
7681 MOV TOS,&BASE \ restore current BASE
7683 \ ******************************\
7685 \ ******************************\
7689 \ ------------------------------\
7691 \ ------------------------------\
7692 \ ... \ insert here your background task
7695 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
7696 ADD #4,X \ 1 X = BODY of SLEEP
7699 \ ------------------------------\
7703 \ ------------------------------\
7704 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
7705 \ - - \CNTL Counter lentgh \ 00 = 16 bits
7706 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
7707 \ -- \ID input divider \ 10 = /4
7708 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
7709 \ - \TBCLR TimerB Clear
7712 \ -------------------------------\
7713 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
7714 \ -- \CM Capture Mode
7719 \ --- \OUTMOD \ 011 = set/reset
7725 \ -------------------------------\
7727 \ -------------------------------\
7729 \ ------------------------------\
7730 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
7731 \ ------------------------------\
7732 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
7733 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
7734 \ ------------------------------\
7735 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
7736 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
7737 \ ------------------------------\
7738 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
7739 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
7740 \ ------------------------------\
7741 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
7742 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
7743 \ ------------------------------\
7744 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
7745 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
7746 \ ------------------------------\
7747 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
7748 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
7749 \ ------------------------------\
7750 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
7751 \ ------------------------------\
7752 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
7753 \ ------------------------------\
7754 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
7755 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
7756 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
7757 \ ------------------------------\
7758 BIS.B #LCDVo,&LCDVo_DIR \
7759 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
7760 \ ------------------------------\
7761 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
7762 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
7763 \ ------------------------------\
7764 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
7765 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
7766 \ ******************************\
7768 \ ******************************\
7769 BIS.B #RC5,&IR_IE \ enable RC5_Int
7770 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
7771 MOV #RC5_INT,&IR_Vec \ init interrupt vector
7772 \ ******************************\
7773 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
7774 \ ******************************\
7775 \ %01 0001 0100 \ TAxCTL
7776 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
7777 \ -- \ ID divided by 1
7778 \ -- \ MC MODE = up to TAxCCRn
7779 \ - \ TACLR clear timer count
7782 \ ------------------------------\
7783 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
7784 \ ------------------------------\
7786 \ --- \ TAIDEX pre divisor
7787 \ ------------------------------\
7788 \ %0000 0000 0000 0101 \ TAxCCR0
7789 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
7790 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
7791 \ ------------------------------\
7792 \ %0000 0000 0001 0000 \ TAxCCTL0
7793 \ - \ CAP capture/compare mode = compare
7796 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
7797 \ ------------------------------\
7798 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
7799 \ ------------------------------\
7800 \ define LPM mode for ACCEPT \
7801 \ ------------------------------\
7802 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
7803 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
7804 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
7806 \ ------------------------------\
7807 \ redirects to background task \
7808 \ ------------------------------\
7810 MOV #BACKGROUND,2(X) \
7811 \ ------------------------------\
7813 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
7815 \ ------------------------------\
7817 \ ------------------------------\
7818 $03E8 20_US \ 1- wait 20 ms
7819 $03 TOP_LCD \ 2- send DB5=DB4=1
7820 $CD 20_US \ 3- wait 4,1 ms
7821 $03 TOP_LCD \ 4- send again DB5=DB4=1
7822 $5 20_US \ 5- wait 0,1 ms
7823 $03 TOP_LCD \ 6- send again again DB5=DB4=1
7824 $2 20_US \ wait 40 us = LCD cycle
7825 $02 TOP_LCD \ 7- send DB5=1 DB4=0
7826 $2 20_US \ wait 40 us = LCD cycle
7827 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
7828 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
7829 LCD_Clear \ 10- "LCD_Clear"
7830 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
7831 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
7832 LCD_Clear \ 10- "LCD_Clear"
7833 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
7834 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
7836 ['] CR >BODY IS CR \
7837 ['] EMIT >BODY IS EMIT \
7838 ." RC5toLCD is running. Type STOP to quit"
7839 LIT RECURSE IS WARM \ replace WARM by this START routine
7840 ABORT \ and continue with the next word after WARM...
7841 ; \ ...until interpreter falls in sleep mode within ACCEPT.
7844 CODE STOP \ stops multitasking, must to be used before downloading app
7845 \ restore default action of primary DEFERred word SLEEP, assembly version
7846 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
7847 ADD #4,X \ X = BODY of SLEEP
7848 MOV X,-2(X) \ restore the default background
7851 \ restore default action of primary DEFERred word WARM, FORTH version
7852 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
7854 COLD \ because we want to reset CPU and interrupt vectors
7859 ; downloading RC5toLCD.4th is done
7860 RST_HERE ; this app is protected against <reset>
7868 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
7870 [DEFINED] ASM [IF] \ security test
7874 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
7876 CODE MAX \ n1 n2 -- n3 signed maximum
7877 CMP @PSP,TOS \ n2-n1
7878 S< ?GOTO FW1 \ n2<n1
7884 CODE MIN \ n1 n2 -- n3 signed minimum
7885 CMP @PSP,TOS \ n2-n1
7886 S< ?GOTO BW1 \ n2<n1
7894 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
7895 : U.R \ u n -- display u unsigned in n width (n >= 2)
7897 R> OVER - 0 MAX SPACES TYPE
7902 \ CODE 20_US \ n -- n * 20 us
7903 \ BEGIN \ 3 cycles loop + 6~
7904 \ \ MOV #5,W \ 3 MCLK = 1 MHz
7905 \ \ MOV #23,W \ 3 MCLK = 4 MHz
7906 \ \ MOV #51,W \ 3 MCLK = 8 MHz
7907 \ MOV #104,W \ 3 MCLK = 16 MHz
7908 \ \ MOV #158,W \ 3 MCLK = 24 MHz
7909 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
7919 CODE 20_US \ n -- n * 20 us
7920 BEGIN \ here we presume that LCD_TIM_IFG = 1...
7922 BIT #1,&LCD_TIM_CTL \ 3
7923 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
7924 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
7926 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
7932 CODE TOP_LCD \ LCD Sample
7933 \ \ if write : %xxxxWWWW --
7934 \ \ if read : -- %0000RRRR
7935 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
7936 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
7937 0= IF \ write LCD bits pattern
7939 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
7940 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
7943 THEN \ read LCD bits pattern
7946 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
7947 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
7953 CODE LCD_W \ byte -- write byte to LCD
7955 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
7956 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
7957 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
7958 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
7959 COLON \ high level word starts here
7960 TOP_LCD 2 20_US \ write high nibble first
7965 CODE LCD_WrC \ char -- Write Char
7966 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
7971 CODE LCD_WrF \ func -- Write Fonction
7972 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
7978 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
7983 $02 LCD_WrF 100 20_us
7989 \ https://forth-standard.org/standard/core/OR
7990 \ C OR x1 x2 -- x3 logical OR
7999 : LCD_Entry_set $04 OR LCD_WrF ;
8001 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
8003 : LCD_DSP_Shift $10 OR LCD_WrF ;
8005 : LCD_Fn_Set $20 OR LCD_WrF ;
8007 : LCD_CGRAM_Set $40 OR LCD_WrF ;
8009 : LCD_Goto $80 OR LCD_WrF ;
8011 CODE LCD_R \ -- byte read byte from LCD
8012 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
8013 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
8014 COLON \ starts a FORTH word
8015 TOP_LCD 2 20_us \ -- %0000HHHH
8016 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
8017 HI2LO \ switch from FORTH to assembler
8018 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
8019 ADD.B @PSP+,TOS \ -- %HHHHLLLL
8020 MOV @RSP+,IP \ restore IP saved by COLON
8025 CODE LCD_RdS \ -- status Read Status
8026 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
8031 CODE LCD_RdC \ -- char Read Char
8032 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
8038 \ ******************************\
8039 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
8040 \ ******************************\
8041 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
8042 BIT.B #SW2,&SW2_IN \ test switch S2
8043 0= IF \ case of switch S2 pressed
8044 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
8046 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
8049 BIT.B #SW1,&SW1_IN \ test switch S1 input
8050 0= IF \ case of Switch S1 pressed
8051 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
8053 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
8057 BW1 \ from quit on truncated RC5 message
8058 BW2 \ from repeated RC5 command
8059 BW3 \ from end of RC5_INT
8060 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
8065 \ ******************************\
8066 ASM RC5_INT \ wake up on Px.RC5 change interrupt
8067 \ ******************************\
8068 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
8069 \ ******************************\
8070 \ \ in : SR(9)=old Toggle bit memory (ADD on)
8071 \ \ SMclock = 8|16|24 MHz
8072 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
8073 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
8074 \ \ SR(9)=new Toggle bit memory (ADD on)
8075 \ ******************************\
8076 \ RC5_FirstStartBitHalfCycle: \
8077 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
8078 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
8079 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
8080 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
8081 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
8082 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
8083 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
8084 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
8085 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
8086 MOV #1778,X \ RC5_Period * 1us
8087 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
8088 MOV #14,W \ count of loop
8090 \ ******************************\
8091 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
8092 \ ******************************\ |
8093 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
8094 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
8095 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
8096 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
8097 \ RC5_Compute_3/4_Period: \ |
8098 RRUM #1,X \ X=1/2 cycle |
8101 ADD X,Y \ Y=3/4 cycle
8102 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
8104 \ ******************************\
8105 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
8106 \ ******************************\
8107 BIT.B #RC5,&IR_IN \ C_flag = IR bit
8108 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
8109 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
8110 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
8111 SUB #1,W \ decrement count loop
8112 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
8113 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
8114 0<> WHILE \ ----> out of loop ----+
8115 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
8117 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
8118 CMP Y,X \ 1 | cycle time out of bound ?
8120 BIC #$30,&RC5_TIM_CTL \ | | stop timer
8121 GOTO BW1 \ | | quit on truncated RC5 message
8123 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
8125 REPEAT \ ----> loop back --+ | with X = new RC5_period value
8126 \ ******************************\ |
8127 \ RC5_SampleEndOf: \ <---------------------+
8128 \ ******************************\
8129 BIC #$30,&RC5_TIM_CTL \ stop timer
8130 \ ******************************\
8131 \ RC5_ComputeNewRC5word \
8132 \ ******************************\
8133 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
8134 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
8135 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
8136 \ ******************************\
8137 \ RC5_ComputeC6bit \
8138 \ ******************************\
8139 BIT #BIT14,T \ test /C6 bit in T
8140 0= IF BIS #BIT6,X \ set C6 bit in X
8141 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
8142 \ ******************************\
8143 \ RC5_CommandByteIsDone \ -- BASE RC5_code
8144 \ ******************************\
8145 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
8146 \ ******************************\
8147 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
8148 XOR @RSP,T \ (new XOR old) Toggle bits
8149 BIT #UF10,T \ repeated RC5_command ?
8150 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
8151 XOR #UF10,0(RSP) \ 5 toggle bit memory
8152 \ ******************************\
8153 \ Display IR_RC5 code \ X = RC5 code
8154 \ ******************************\
8156 MOV &BASE,2(PSP) \ save current base
8157 MOV #$10,&BASE \ set hex base
8158 MOV TOS,0(PSP) \ save TOS
8160 LO2HI \ switch from assembler to FORTH
8161 ['] LCD_CLEAR IS CR \ redirects CR
8162 ['] LCD_WrC IS EMIT \ redirects EMIT
8163 CR ." $" 2 U.R \ print IR_RC5 code
8164 ['] CR >BODY IS CR \ restore CR
8165 ['] EMIT >BODY IS EMIT \ restore EMIT
8166 HI2LO \ switch from FORTH to assembler
8167 MOV TOS,&BASE \ restore current BASE
8169 \ ******************************\
8171 \ ******************************\
8175 \ ------------------------------\
8177 \ ------------------------------\
8178 \ ... \ insert here your background task
8181 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
8182 ADD #4,X \ 1 X = BODY of SLEEP
8185 \ ------------------------------\
8189 \ ------------------------------\
8190 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
8191 \ - - \CNTL Counter lentgh \ 00 = 16 bits
8192 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
8193 \ -- \ID input divider \ 10 = /4
8194 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
8195 \ - \TBCLR TimerB Clear
8198 \ -------------------------------\
8199 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
8200 \ -- \CM Capture Mode
8205 \ --- \OUTMOD \ 011 = set/reset
8211 \ -------------------------------\
8213 \ -------------------------------\
8215 \ ------------------------------\
8216 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
8217 \ ------------------------------\
8218 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
8219 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
8220 \ ------------------------------\
8221 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
8222 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
8223 \ ------------------------------\
8224 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
8225 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
8226 \ ------------------------------\
8227 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
8228 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
8229 \ ------------------------------\
8230 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
8231 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
8232 \ ------------------------------\
8233 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
8234 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
8235 \ ------------------------------\
8236 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
8237 \ ------------------------------\
8238 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
8239 \ ------------------------------\
8240 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
8241 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
8242 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
8243 \ ------------------------------\
8244 BIS.B #LCDVo,&LCDVo_DIR \
8245 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
8246 \ ------------------------------\
8247 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
8248 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
8249 \ ------------------------------\
8250 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
8251 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
8252 \ ******************************\
8254 \ ******************************\
8255 BIS.B #RC5,&IR_IE \ enable RC5_Int
8256 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
8257 MOV #RC5_INT,&IR_Vec \ init interrupt vector
8258 \ ******************************\
8259 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
8260 \ ******************************\
8261 \ %01 0001 0100 \ TAxCTL
8262 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
8263 \ -- \ ID divided by 1
8264 \ -- \ MC MODE = up to TAxCCRn
8265 \ - \ TACLR clear timer count
8268 \ ------------------------------\
8269 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
8270 \ ------------------------------\
8272 \ --- \ TAIDEX pre divisor
8273 \ ------------------------------\
8274 \ %0000 0000 0000 0101 \ TAxCCR0
8275 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
8276 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
8277 \ ------------------------------\
8278 \ %0000 0000 0001 0000 \ TAxCCTL0
8279 \ - \ CAP capture/compare mode = compare
8282 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
8283 \ ------------------------------\
8284 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
8285 \ ------------------------------\
8286 \ define LPM mode for ACCEPT \
8287 \ ------------------------------\
8288 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
8289 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
8290 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
8292 \ ------------------------------\
8293 \ redirects to background task \
8294 \ ------------------------------\
8296 MOV #BACKGROUND,2(X) \
8297 \ ------------------------------\
8299 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
8301 \ ------------------------------\
8303 \ ------------------------------\
8304 $03E8 20_US \ 1- wait 20 ms
8305 $03 TOP_LCD \ 2- send DB5=DB4=1
8306 $CD 20_US \ 3- wait 4,1 ms
8307 $03 TOP_LCD \ 4- send again DB5=DB4=1
8308 $5 20_US \ 5- wait 0,1 ms
8309 $03 TOP_LCD \ 6- send again again DB5=DB4=1
8310 $2 20_US \ wait 40 us = LCD cycle
8311 $02 TOP_LCD \ 7- send DB5=1 DB4=0
8312 $2 20_US \ wait 40 us = LCD cycle
8313 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
8314 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
8315 LCD_Clear \ 10- "LCD_Clear"
8316 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
8317 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
8318 LCD_Clear \ 10- "LCD_Clear"
8319 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
8320 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
8322 ['] CR >BODY IS CR \
8323 ['] EMIT >BODY IS EMIT \
8324 ." RC5toLCD is running. Type STOP to quit"
8325 LIT RECURSE IS WARM \ replace WARM by this START routine
8326 ABORT \ and continue with the next word after WARM...
8327 ; \ ...until interpreter falls in sleep mode within ACCEPT.
8330 CODE STOP \ stops multitasking, must to be used before downloading app
8331 \ restore default action of primary DEFERred word SLEEP, assembly version
8332 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
8333 ADD #4,X \ X = BODY of SLEEP
8334 MOV X,-2(X) \ restore the default background
8337 \ restore default action of primary DEFERred word WARM, FORTH version
8338 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
8340 COLD \ because we want to reset CPU and interrupt vectors
8345 ; downloading RC5toLCD.4th is done
8346 RST_HERE ; this app is protected against <reset>
8354 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
8356 [DEFINED] ASM [IF] \ security test
8360 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
8362 CODE MAX \ n1 n2 -- n3 signed maximum
8363 CMP @PSP,TOS \ n2-n1
8364 S< ?GOTO FW1 \ n2<n1
8370 CODE MIN \ n1 n2 -- n3 signed minimum
8371 CMP @PSP,TOS \ n2-n1
8372 S< ?GOTO BW1 \ n2<n1
8380 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
8381 : U.R \ u n -- display u unsigned in n width (n >= 2)
8383 R> OVER - 0 MAX SPACES TYPE
8388 \ CODE 20_US \ n -- n * 20 us
8389 \ BEGIN \ 3 cycles loop + 6~
8390 \ \ MOV #5,W \ 3 MCLK = 1 MHz
8391 \ \ MOV #23,W \ 3 MCLK = 4 MHz
8392 \ \ MOV #51,W \ 3 MCLK = 8 MHz
8393 \ MOV #104,W \ 3 MCLK = 16 MHz
8394 \ \ MOV #158,W \ 3 MCLK = 24 MHz
8395 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
8405 CODE 20_US \ n -- n * 20 us
8406 BEGIN \ here we presume that LCD_TIM_IFG = 1...
8408 BIT #1,&LCD_TIM_CTL \ 3
8409 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
8410 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
8412 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
8418 CODE TOP_LCD \ LCD Sample
8419 \ \ if write : %xxxxWWWW --
8420 \ \ if read : -- %0000RRRR
8421 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
8422 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
8423 0= IF \ write LCD bits pattern
8425 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
8426 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
8429 THEN \ read LCD bits pattern
8432 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
8433 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
8439 CODE LCD_W \ byte -- write byte to LCD
8441 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
8442 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
8443 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
8444 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
8445 COLON \ high level word starts here
8446 TOP_LCD 2 20_US \ write high nibble first
8451 CODE LCD_WrC \ char -- Write Char
8452 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
8457 CODE LCD_WrF \ func -- Write Fonction
8458 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
8464 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
8469 $02 LCD_WrF 100 20_us
8475 \ https://forth-standard.org/standard/core/OR
8476 \ C OR x1 x2 -- x3 logical OR
8485 : LCD_Entry_set $04 OR LCD_WrF ;
8487 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
8489 : LCD_DSP_Shift $10 OR LCD_WrF ;
8491 : LCD_Fn_Set $20 OR LCD_WrF ;
8493 : LCD_CGRAM_Set $40 OR LCD_WrF ;
8495 : LCD_Goto $80 OR LCD_WrF ;
8497 CODE LCD_R \ -- byte read byte from LCD
8498 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
8499 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
8500 COLON \ starts a FORTH word
8501 TOP_LCD 2 20_us \ -- %0000HHHH
8502 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
8503 HI2LO \ switch from FORTH to assembler
8504 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
8505 ADD.B @PSP+,TOS \ -- %HHHHLLLL
8506 MOV @RSP+,IP \ restore IP saved by COLON
8511 CODE LCD_RdS \ -- status Read Status
8512 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
8517 CODE LCD_RdC \ -- char Read Char
8518 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
8524 \ ******************************\
8525 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
8526 \ ******************************\
8527 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
8528 BIT.B #SW2,&SW2_IN \ test switch S2
8529 0= IF \ case of switch S2 pressed
8530 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
8532 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
8535 BIT.B #SW1,&SW1_IN \ test switch S1 input
8536 0= IF \ case of Switch S1 pressed
8537 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
8539 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
8543 BW1 \ from quit on truncated RC5 message
8544 BW2 \ from repeated RC5 command
8545 BW3 \ from end of RC5_INT
8546 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
8551 \ ******************************\
8552 ASM RC5_INT \ wake up on Px.RC5 change interrupt
8553 \ ******************************\
8554 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
8555 \ ******************************\
8556 \ \ in : SR(9)=old Toggle bit memory (ADD on)
8557 \ \ SMclock = 8|16|24 MHz
8558 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
8559 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
8560 \ \ SR(9)=new Toggle bit memory (ADD on)
8561 \ ******************************\
8562 \ RC5_FirstStartBitHalfCycle: \
8563 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
8564 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
8565 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
8566 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
8567 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
8568 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
8569 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
8570 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
8571 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
8572 MOV #1778,X \ RC5_Period * 1us
8573 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
8574 MOV #14,W \ count of loop
8576 \ ******************************\
8577 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
8578 \ ******************************\ |
8579 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
8580 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
8581 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
8582 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
8583 \ RC5_Compute_3/4_Period: \ |
8584 RRUM #1,X \ X=1/2 cycle |
8587 ADD X,Y \ Y=3/4 cycle
8588 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
8590 \ ******************************\
8591 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
8592 \ ******************************\
8593 BIT.B #RC5,&IR_IN \ C_flag = IR bit
8594 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
8595 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
8596 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
8597 SUB #1,W \ decrement count loop
8598 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
8599 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
8600 0<> WHILE \ ----> out of loop ----+
8601 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
8603 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
8604 CMP Y,X \ 1 | cycle time out of bound ?
8606 BIC #$30,&RC5_TIM_CTL \ | | stop timer
8607 GOTO BW1 \ | | quit on truncated RC5 message
8609 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
8611 REPEAT \ ----> loop back --+ | with X = new RC5_period value
8612 \ ******************************\ |
8613 \ RC5_SampleEndOf: \ <---------------------+
8614 \ ******************************\
8615 BIC #$30,&RC5_TIM_CTL \ stop timer
8616 \ ******************************\
8617 \ RC5_ComputeNewRC5word \
8618 \ ******************************\
8619 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
8620 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
8621 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
8622 \ ******************************\
8623 \ RC5_ComputeC6bit \
8624 \ ******************************\
8625 BIT #BIT14,T \ test /C6 bit in T
8626 0= IF BIS #BIT6,X \ set C6 bit in X
8627 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
8628 \ ******************************\
8629 \ RC5_CommandByteIsDone \ -- BASE RC5_code
8630 \ ******************************\
8631 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
8632 \ ******************************\
8633 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
8634 XOR @RSP,T \ (new XOR old) Toggle bits
8635 BIT #UF10,T \ repeated RC5_command ?
8636 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
8637 XOR #UF10,0(RSP) \ 5 toggle bit memory
8638 \ ******************************\
8639 \ Display IR_RC5 code \ X = RC5 code
8640 \ ******************************\
8642 MOV &BASE,2(PSP) \ save current base
8643 MOV #$10,&BASE \ set hex base
8644 MOV TOS,0(PSP) \ save TOS
8646 LO2HI \ switch from assembler to FORTH
8647 ['] LCD_CLEAR IS CR \ redirects CR
8648 ['] LCD_WrC IS EMIT \ redirects EMIT
8649 CR ." $" 2 U.R \ print IR_RC5 code
8650 ['] CR >BODY IS CR \ restore CR
8651 ['] EMIT >BODY IS EMIT \ restore EMIT
8652 HI2LO \ switch from FORTH to assembler
8653 MOV TOS,&BASE \ restore current BASE
8655 \ ******************************\
8657 \ ******************************\
8661 \ ------------------------------\
8663 \ ------------------------------\
8664 \ ... \ insert here your background task
8667 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
8668 ADD #4,X \ 1 X = BODY of SLEEP
8671 \ ------------------------------\
8675 \ ------------------------------\
8676 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
8677 \ - - \CNTL Counter lentgh \ 00 = 16 bits
8678 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
8679 \ -- \ID input divider \ 10 = /4
8680 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
8681 \ - \TBCLR TimerB Clear
8684 \ -------------------------------\
8685 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
8686 \ -- \CM Capture Mode
8691 \ --- \OUTMOD \ 011 = set/reset
8697 \ -------------------------------\
8699 \ -------------------------------\
8701 \ ------------------------------\
8702 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
8703 \ ------------------------------\
8704 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
8705 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
8706 \ ------------------------------\
8707 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
8708 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
8709 \ ------------------------------\
8710 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
8711 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
8712 \ ------------------------------\
8713 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
8714 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
8715 \ ------------------------------\
8716 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
8717 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
8718 \ ------------------------------\
8719 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
8720 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
8721 \ ------------------------------\
8722 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
8723 \ ------------------------------\
8724 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
8725 \ ------------------------------\
8726 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
8727 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
8728 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
8729 \ ------------------------------\
8730 BIS.B #LCDVo,&LCDVo_DIR \
8731 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
8732 \ ------------------------------\
8733 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
8734 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
8735 \ ------------------------------\
8736 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
8737 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
8738 \ ******************************\
8740 \ ******************************\
8741 BIS.B #RC5,&IR_IE \ enable RC5_Int
8742 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
8743 MOV #RC5_INT,&IR_Vec \ init interrupt vector
8744 \ ******************************\
8745 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
8746 \ ******************************\
8747 \ %01 0001 0100 \ TAxCTL
8748 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
8749 \ -- \ ID divided by 1
8750 \ -- \ MC MODE = up to TAxCCRn
8751 \ - \ TACLR clear timer count
8754 \ ------------------------------\
8755 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
8756 \ ------------------------------\
8758 \ --- \ TAIDEX pre divisor
8759 \ ------------------------------\
8760 \ %0000 0000 0000 0101 \ TAxCCR0
8761 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
8762 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
8763 \ ------------------------------\
8764 \ %0000 0000 0001 0000 \ TAxCCTL0
8765 \ - \ CAP capture/compare mode = compare
8768 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
8769 \ ------------------------------\
8770 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
8771 \ ------------------------------\
8772 \ define LPM mode for ACCEPT \
8773 \ ------------------------------\
8774 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
8775 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
8776 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
8778 \ ------------------------------\
8779 \ redirects to background task \
8780 \ ------------------------------\
8782 MOV #BACKGROUND,2(X) \
8783 \ ------------------------------\
8785 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
8787 \ ------------------------------\
8789 \ ------------------------------\
8790 $03E8 20_US \ 1- wait 20 ms
8791 $03 TOP_LCD \ 2- send DB5=DB4=1
8792 $CD 20_US \ 3- wait 4,1 ms
8793 $03 TOP_LCD \ 4- send again DB5=DB4=1
8794 $5 20_US \ 5- wait 0,1 ms
8795 $03 TOP_LCD \ 6- send again again DB5=DB4=1
8796 $2 20_US \ wait 40 us = LCD cycle
8797 $02 TOP_LCD \ 7- send DB5=1 DB4=0
8798 $2 20_US \ wait 40 us = LCD cycle
8799 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
8800 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
8801 LCD_Clear \ 10- "LCD_Clear"
8802 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
8803 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
8804 LCD_Clear \ 10- "LCD_Clear"
8805 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
8806 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
8808 ['] CR >BODY IS CR \
8809 ['] EMIT >BODY IS EMIT \
8810 ." RC5toLCD is running. Type STOP to quit"
8811 LIT RECURSE IS WARM \ replace WARM by this START routine
8812 ABORT \ and continue with the next word after WARM...
8813 ; \ ...until interpreter falls in sleep mode within ACCEPT.
8816 CODE STOP \ stops multitasking, must to be used before downloading app
8817 \ restore default action of primary DEFERred word SLEEP, assembly version
8818 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
8819 ADD #4,X \ X = BODY of SLEEP
8820 MOV X,-2(X) \ restore the default background
8823 \ restore default action of primary DEFERred word WARM, FORTH version
8824 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
8826 COLD \ because we want to reset CPU and interrupt vectors
8831 ; downloading RC5toLCD.4th is done
8832 RST_HERE ; this app is protected against <reset>
8840 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
8842 [DEFINED] ASM [IF] \ security test
8846 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
8848 CODE MAX \ n1 n2 -- n3 signed maximum
8849 CMP @PSP,TOS \ n2-n1
8850 S< ?GOTO FW1 \ n2<n1
8856 CODE MIN \ n1 n2 -- n3 signed minimum
8857 CMP @PSP,TOS \ n2-n1
8858 S< ?GOTO BW1 \ n2<n1
8866 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
8867 : U.R \ u n -- display u unsigned in n width (n >= 2)
8869 R> OVER - 0 MAX SPACES TYPE
8874 \ CODE 20_US \ n -- n * 20 us
8875 \ BEGIN \ 3 cycles loop + 6~
8876 \ \ MOV #5,W \ 3 MCLK = 1 MHz
8877 \ \ MOV #23,W \ 3 MCLK = 4 MHz
8878 \ \ MOV #51,W \ 3 MCLK = 8 MHz
8879 \ MOV #104,W \ 3 MCLK = 16 MHz
8880 \ \ MOV #158,W \ 3 MCLK = 24 MHz
8881 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
8891 CODE 20_US \ n -- n * 20 us
8892 BEGIN \ here we presume that LCD_TIM_IFG = 1...
8894 BIT #1,&LCD_TIM_CTL \ 3
8895 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
8896 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
8898 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
8904 CODE TOP_LCD \ LCD Sample
8905 \ \ if write : %xxxxWWWW --
8906 \ \ if read : -- %0000RRRR
8907 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
8908 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
8909 0= IF \ write LCD bits pattern
8911 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
8912 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
8915 THEN \ read LCD bits pattern
8918 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
8919 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
8925 CODE LCD_W \ byte -- write byte to LCD
8927 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
8928 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
8929 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
8930 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
8931 COLON \ high level word starts here
8932 TOP_LCD 2 20_US \ write high nibble first
8937 CODE LCD_WrC \ char -- Write Char
8938 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
8943 CODE LCD_WrF \ func -- Write Fonction
8944 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
8950 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
8955 $02 LCD_WrF 100 20_us
8961 \ https://forth-standard.org/standard/core/OR
8962 \ C OR x1 x2 -- x3 logical OR
8971 : LCD_Entry_set $04 OR LCD_WrF ;
8973 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
8975 : LCD_DSP_Shift $10 OR LCD_WrF ;
8977 : LCD_Fn_Set $20 OR LCD_WrF ;
8979 : LCD_CGRAM_Set $40 OR LCD_WrF ;
8981 : LCD_Goto $80 OR LCD_WrF ;
8983 CODE LCD_R \ -- byte read byte from LCD
8984 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
8985 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
8986 COLON \ starts a FORTH word
8987 TOP_LCD 2 20_us \ -- %0000HHHH
8988 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
8989 HI2LO \ switch from FORTH to assembler
8990 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
8991 ADD.B @PSP+,TOS \ -- %HHHHLLLL
8992 MOV @RSP+,IP \ restore IP saved by COLON
8997 CODE LCD_RdS \ -- status Read Status
8998 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
9003 CODE LCD_RdC \ -- char Read Char
9004 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
9010 \ ******************************\
9011 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
9012 \ ******************************\
9013 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
9014 BIT.B #SW2,&SW2_IN \ test switch S2
9015 0= IF \ case of switch S2 pressed
9016 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
9018 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
9021 BIT.B #SW1,&SW1_IN \ test switch S1 input
9022 0= IF \ case of Switch S1 pressed
9023 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
9025 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
9029 BW1 \ from quit on truncated RC5 message
9030 BW2 \ from repeated RC5 command
9031 BW3 \ from end of RC5_INT
9032 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
9037 \ ******************************\
9038 ASM RC5_INT \ wake up on Px.RC5 change interrupt
9039 \ ******************************\
9040 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
9041 \ ******************************\
9042 \ \ in : SR(9)=old Toggle bit memory (ADD on)
9043 \ \ SMclock = 8|16|24 MHz
9044 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
9045 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
9046 \ \ SR(9)=new Toggle bit memory (ADD on)
9047 \ ******************************\
9048 \ RC5_FirstStartBitHalfCycle: \
9049 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
9050 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
9051 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
9052 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
9053 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
9054 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
9055 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
9056 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
9057 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
9058 MOV #1778,X \ RC5_Period * 1us
9059 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
9060 MOV #14,W \ count of loop
9062 \ ******************************\
9063 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
9064 \ ******************************\ |
9065 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
9066 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
9067 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
9068 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
9069 \ RC5_Compute_3/4_Period: \ |
9070 RRUM #1,X \ X=1/2 cycle |
9073 ADD X,Y \ Y=3/4 cycle
9074 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
9076 \ ******************************\
9077 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
9078 \ ******************************\
9079 BIT.B #RC5,&IR_IN \ C_flag = IR bit
9080 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
9081 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
9082 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
9083 SUB #1,W \ decrement count loop
9084 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
9085 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
9086 0<> WHILE \ ----> out of loop ----+
9087 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
9089 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
9090 CMP Y,X \ 1 | cycle time out of bound ?
9092 BIC #$30,&RC5_TIM_CTL \ | | stop timer
9093 GOTO BW1 \ | | quit on truncated RC5 message
9095 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
9097 REPEAT \ ----> loop back --+ | with X = new RC5_period value
9098 \ ******************************\ |
9099 \ RC5_SampleEndOf: \ <---------------------+
9100 \ ******************************\
9101 BIC #$30,&RC5_TIM_CTL \ stop timer
9102 \ ******************************\
9103 \ RC5_ComputeNewRC5word \
9104 \ ******************************\
9105 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
9106 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
9107 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
9108 \ ******************************\
9109 \ RC5_ComputeC6bit \
9110 \ ******************************\
9111 BIT #BIT14,T \ test /C6 bit in T
9112 0= IF BIS #BIT6,X \ set C6 bit in X
9113 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
9114 \ ******************************\
9115 \ RC5_CommandByteIsDone \ -- BASE RC5_code
9116 \ ******************************\
9117 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
9118 \ ******************************\
9119 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
9120 XOR @RSP,T \ (new XOR old) Toggle bits
9121 BIT #UF10,T \ repeated RC5_command ?
9122 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
9123 XOR #UF10,0(RSP) \ 5 toggle bit memory
9124 \ ******************************\
9125 \ Display IR_RC5 code \ X = RC5 code
9126 \ ******************************\
9128 MOV &BASE,2(PSP) \ save current base
9129 MOV #$10,&BASE \ set hex base
9130 MOV TOS,0(PSP) \ save TOS
9132 LO2HI \ switch from assembler to FORTH
9133 ['] LCD_CLEAR IS CR \ redirects CR
9134 ['] LCD_WrC IS EMIT \ redirects EMIT
9135 CR ." $" 2 U.R \ print IR_RC5 code
9136 ['] CR >BODY IS CR \ restore CR
9137 ['] EMIT >BODY IS EMIT \ restore EMIT
9138 HI2LO \ switch from FORTH to assembler
9139 MOV TOS,&BASE \ restore current BASE
9141 \ ******************************\
9143 \ ******************************\
9147 \ ------------------------------\
9149 \ ------------------------------\
9150 \ ... \ insert here your background task
9153 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
9154 ADD #4,X \ 1 X = BODY of SLEEP
9157 \ ------------------------------\
9161 \ ------------------------------\
9162 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
9163 \ - - \CNTL Counter lentgh \ 00 = 16 bits
9164 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
9165 \ -- \ID input divider \ 10 = /4
9166 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
9167 \ - \TBCLR TimerB Clear
9170 \ -------------------------------\
9171 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
9172 \ -- \CM Capture Mode
9177 \ --- \OUTMOD \ 011 = set/reset
9183 \ -------------------------------\
9185 \ -------------------------------\
9187 \ ------------------------------\
9188 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
9189 \ ------------------------------\
9190 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
9191 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
9192 \ ------------------------------\
9193 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
9194 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
9195 \ ------------------------------\
9196 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
9197 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
9198 \ ------------------------------\
9199 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
9200 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
9201 \ ------------------------------\
9202 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
9203 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
9204 \ ------------------------------\
9205 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
9206 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
9207 \ ------------------------------\
9208 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
9209 \ ------------------------------\
9210 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
9211 \ ------------------------------\
9212 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
9213 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
9214 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
9215 \ ------------------------------\
9216 BIS.B #LCDVo,&LCDVo_DIR \
9217 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
9218 \ ------------------------------\
9219 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
9220 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
9221 \ ------------------------------\
9222 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
9223 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
9224 \ ******************************\
9226 \ ******************************\
9227 BIS.B #RC5,&IR_IE \ enable RC5_Int
9228 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
9229 MOV #RC5_INT,&IR_Vec \ init interrupt vector
9230 \ ******************************\
9231 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
9232 \ ******************************\
9233 \ %01 0001 0100 \ TAxCTL
9234 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
9235 \ -- \ ID divided by 1
9236 \ -- \ MC MODE = up to TAxCCRn
9237 \ - \ TACLR clear timer count
9240 \ ------------------------------\
9241 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
9242 \ ------------------------------\
9244 \ --- \ TAIDEX pre divisor
9245 \ ------------------------------\
9246 \ %0000 0000 0000 0101 \ TAxCCR0
9247 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
9248 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
9249 \ ------------------------------\
9250 \ %0000 0000 0001 0000 \ TAxCCTL0
9251 \ - \ CAP capture/compare mode = compare
9254 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
9255 \ ------------------------------\
9256 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
9257 \ ------------------------------\
9258 \ define LPM mode for ACCEPT \
9259 \ ------------------------------\
9260 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
9261 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
9262 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
9264 \ ------------------------------\
9265 \ redirects to background task \
9266 \ ------------------------------\
9268 MOV #BACKGROUND,2(X) \
9269 \ ------------------------------\
9271 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
9273 \ ------------------------------\
9275 \ ------------------------------\
9276 $03E8 20_US \ 1- wait 20 ms
9277 $03 TOP_LCD \ 2- send DB5=DB4=1
9278 $CD 20_US \ 3- wait 4,1 ms
9279 $03 TOP_LCD \ 4- send again DB5=DB4=1
9280 $5 20_US \ 5- wait 0,1 ms
9281 $03 TOP_LCD \ 6- send again again DB5=DB4=1
9282 $2 20_US \ wait 40 us = LCD cycle
9283 $02 TOP_LCD \ 7- send DB5=1 DB4=0
9284 $2 20_US \ wait 40 us = LCD cycle
9285 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
9286 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
9287 LCD_Clear \ 10- "LCD_Clear"
9288 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
9289 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
9290 LCD_Clear \ 10- "LCD_Clear"
9291 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
9292 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
9294 ['] CR >BODY IS CR \
9295 ['] EMIT >BODY IS EMIT \
9296 ." RC5toLCD is running. Type STOP to quit"
9297 LIT RECURSE IS WARM \ replace WARM by this START routine
9298 ABORT \ and continue with the next word after WARM...
9299 ; \ ...until interpreter falls in sleep mode within ACCEPT.
9302 CODE STOP \ stops multitasking, must to be used before downloading app
9303 \ restore default action of primary DEFERred word SLEEP, assembly version
9304 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
9305 ADD #4,X \ X = BODY of SLEEP
9306 MOV X,-2(X) \ restore the default background
9309 \ restore default action of primary DEFERred word WARM, FORTH version
9310 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
9312 COLD \ because we want to reset CPU and interrupt vectors
9317 ; downloading RC5toLCD.4th is done
9318 RST_HERE ; this app is protected against <reset>
9326 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
9328 [DEFINED] ASM [IF] \ security test
9332 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
9334 CODE MAX \ n1 n2 -- n3 signed maximum
9335 CMP @PSP,TOS \ n2-n1
9336 S< ?GOTO FW1 \ n2<n1
9342 CODE MIN \ n1 n2 -- n3 signed minimum
9343 CMP @PSP,TOS \ n2-n1
9344 S< ?GOTO BW1 \ n2<n1
9352 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
9353 : U.R \ u n -- display u unsigned in n width (n >= 2)
9355 R> OVER - 0 MAX SPACES TYPE
9360 \ CODE 20_US \ n -- n * 20 us
9361 \ BEGIN \ 3 cycles loop + 6~
9362 \ \ MOV #5,W \ 3 MCLK = 1 MHz
9363 \ \ MOV #23,W \ 3 MCLK = 4 MHz
9364 \ \ MOV #51,W \ 3 MCLK = 8 MHz
9365 \ MOV #104,W \ 3 MCLK = 16 MHz
9366 \ \ MOV #158,W \ 3 MCLK = 24 MHz
9367 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
9377 CODE 20_US \ n -- n * 20 us
9378 BEGIN \ here we presume that LCD_TIM_IFG = 1...
9380 BIT #1,&LCD_TIM_CTL \ 3
9381 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
9382 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
9384 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
9390 CODE TOP_LCD \ LCD Sample
9391 \ \ if write : %xxxxWWWW --
9392 \ \ if read : -- %0000RRRR
9393 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
9394 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
9395 0= IF \ write LCD bits pattern
9397 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
9398 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
9401 THEN \ read LCD bits pattern
9404 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
9405 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
9411 CODE LCD_W \ byte -- write byte to LCD
9413 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
9414 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
9415 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
9416 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
9417 COLON \ high level word starts here
9418 TOP_LCD 2 20_US \ write high nibble first
9423 CODE LCD_WrC \ char -- Write Char
9424 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
9429 CODE LCD_WrF \ func -- Write Fonction
9430 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
9436 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
9441 $02 LCD_WrF 100 20_us
9447 \ https://forth-standard.org/standard/core/OR
9448 \ C OR x1 x2 -- x3 logical OR
9457 : LCD_Entry_set $04 OR LCD_WrF ;
9459 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
9461 : LCD_DSP_Shift $10 OR LCD_WrF ;
9463 : LCD_Fn_Set $20 OR LCD_WrF ;
9465 : LCD_CGRAM_Set $40 OR LCD_WrF ;
9467 : LCD_Goto $80 OR LCD_WrF ;
9469 CODE LCD_R \ -- byte read byte from LCD
9470 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
9471 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
9472 COLON \ starts a FORTH word
9473 TOP_LCD 2 20_us \ -- %0000HHHH
9474 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
9475 HI2LO \ switch from FORTH to assembler
9476 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
9477 ADD.B @PSP+,TOS \ -- %HHHHLLLL
9478 MOV @RSP+,IP \ restore IP saved by COLON
9483 CODE LCD_RdS \ -- status Read Status
9484 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
9489 CODE LCD_RdC \ -- char Read Char
9490 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
9496 \ ******************************\
9497 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
9498 \ ******************************\
9499 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
9500 BIT.B #SW2,&SW2_IN \ test switch S2
9501 0= IF \ case of switch S2 pressed
9502 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
9504 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
9507 BIT.B #SW1,&SW1_IN \ test switch S1 input
9508 0= IF \ case of Switch S1 pressed
9509 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
9511 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
9515 BW1 \ from quit on truncated RC5 message
9516 BW2 \ from repeated RC5 command
9517 BW3 \ from end of RC5_INT
9518 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
9523 \ ******************************\
9524 ASM RC5_INT \ wake up on Px.RC5 change interrupt
9525 \ ******************************\
9526 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
9527 \ ******************************\
9528 \ \ in : SR(9)=old Toggle bit memory (ADD on)
9529 \ \ SMclock = 8|16|24 MHz
9530 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
9531 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
9532 \ \ SR(9)=new Toggle bit memory (ADD on)
9533 \ ******************************\
9534 \ RC5_FirstStartBitHalfCycle: \
9535 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
9536 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
9537 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
9538 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
9539 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
9540 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
9541 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
9542 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
9543 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
9544 MOV #1778,X \ RC5_Period * 1us
9545 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
9546 MOV #14,W \ count of loop
9548 \ ******************************\
9549 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
9550 \ ******************************\ |
9551 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
9552 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
9553 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
9554 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
9555 \ RC5_Compute_3/4_Period: \ |
9556 RRUM #1,X \ X=1/2 cycle |
9559 ADD X,Y \ Y=3/4 cycle
9560 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
9562 \ ******************************\
9563 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
9564 \ ******************************\
9565 BIT.B #RC5,&IR_IN \ C_flag = IR bit
9566 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
9567 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
9568 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
9569 SUB #1,W \ decrement count loop
9570 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
9571 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
9572 0<> WHILE \ ----> out of loop ----+
9573 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
9575 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
9576 CMP Y,X \ 1 | cycle time out of bound ?
9578 BIC #$30,&RC5_TIM_CTL \ | | stop timer
9579 GOTO BW1 \ | | quit on truncated RC5 message
9581 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
9583 REPEAT \ ----> loop back --+ | with X = new RC5_period value
9584 \ ******************************\ |
9585 \ RC5_SampleEndOf: \ <---------------------+
9586 \ ******************************\
9587 BIC #$30,&RC5_TIM_CTL \ stop timer
9588 \ ******************************\
9589 \ RC5_ComputeNewRC5word \
9590 \ ******************************\
9591 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
9592 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
9593 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
9594 \ ******************************\
9595 \ RC5_ComputeC6bit \
9596 \ ******************************\
9597 BIT #BIT14,T \ test /C6 bit in T
9598 0= IF BIS #BIT6,X \ set C6 bit in X
9599 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
9600 \ ******************************\
9601 \ RC5_CommandByteIsDone \ -- BASE RC5_code
9602 \ ******************************\
9603 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
9604 \ ******************************\
9605 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
9606 XOR @RSP,T \ (new XOR old) Toggle bits
9607 BIT #UF10,T \ repeated RC5_command ?
9608 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
9609 XOR #UF10,0(RSP) \ 5 toggle bit memory
9610 \ ******************************\
9611 \ Display IR_RC5 code \ X = RC5 code
9612 \ ******************************\
9614 MOV &BASE,2(PSP) \ save current base
9615 MOV #$10,&BASE \ set hex base
9616 MOV TOS,0(PSP) \ save TOS
9618 LO2HI \ switch from assembler to FORTH
9619 ['] LCD_CLEAR IS CR \ redirects CR
9620 ['] LCD_WrC IS EMIT \ redirects EMIT
9621 CR ." $" 2 U.R \ print IR_RC5 code
9622 ['] CR >BODY IS CR \ restore CR
9623 ['] EMIT >BODY IS EMIT \ restore EMIT
9624 HI2LO \ switch from FORTH to assembler
9625 MOV TOS,&BASE \ restore current BASE
9627 \ ******************************\
9629 \ ******************************\
9633 \ ------------------------------\
9635 \ ------------------------------\
9636 \ ... \ insert here your background task
9639 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
9640 ADD #4,X \ 1 X = BODY of SLEEP
9643 \ ------------------------------\
9647 \ ------------------------------\
9648 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
9649 \ - - \CNTL Counter lentgh \ 00 = 16 bits
9650 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
9651 \ -- \ID input divider \ 10 = /4
9652 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
9653 \ - \TBCLR TimerB Clear
9656 \ -------------------------------\
9657 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
9658 \ -- \CM Capture Mode
9663 \ --- \OUTMOD \ 011 = set/reset
9669 \ -------------------------------\
9671 \ -------------------------------\
9673 \ ------------------------------\
9674 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
9675 \ ------------------------------\
9676 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
9677 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
9678 \ ------------------------------\
9679 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
9680 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
9681 \ ------------------------------\
9682 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
9683 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
9684 \ ------------------------------\
9685 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
9686 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
9687 \ ------------------------------\
9688 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
9689 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
9690 \ ------------------------------\
9691 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
9692 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
9693 \ ------------------------------\
9694 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
9695 \ ------------------------------\
9696 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
9697 \ ------------------------------\
9698 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
9699 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
9700 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
9701 \ ------------------------------\
9702 BIS.B #LCDVo,&LCDVo_DIR \
9703 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
9704 \ ------------------------------\
9705 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
9706 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
9707 \ ------------------------------\
9708 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
9709 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
9710 \ ******************************\
9712 \ ******************************\
9713 BIS.B #RC5,&IR_IE \ enable RC5_Int
9714 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
9715 MOV #RC5_INT,&IR_Vec \ init interrupt vector
9716 \ ******************************\
9717 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
9718 \ ******************************\
9719 \ %01 0001 0100 \ TAxCTL
9720 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
9721 \ -- \ ID divided by 1
9722 \ -- \ MC MODE = up to TAxCCRn
9723 \ - \ TACLR clear timer count
9726 \ ------------------------------\
9727 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
9728 \ ------------------------------\
9730 \ --- \ TAIDEX pre divisor
9731 \ ------------------------------\
9732 \ %0000 0000 0000 0101 \ TAxCCR0
9733 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
9734 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
9735 \ ------------------------------\
9736 \ %0000 0000 0001 0000 \ TAxCCTL0
9737 \ - \ CAP capture/compare mode = compare
9740 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
9741 \ ------------------------------\
9742 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
9743 \ ------------------------------\
9744 \ define LPM mode for ACCEPT \
9745 \ ------------------------------\
9746 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
9747 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
9748 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
9750 \ ------------------------------\
9751 \ redirects to background task \
9752 \ ------------------------------\
9754 MOV #BACKGROUND,2(X) \
9755 \ ------------------------------\
9757 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
9759 \ ------------------------------\
9761 \ ------------------------------\
9762 $03E8 20_US \ 1- wait 20 ms
9763 $03 TOP_LCD \ 2- send DB5=DB4=1
9764 $CD 20_US \ 3- wait 4,1 ms
9765 $03 TOP_LCD \ 4- send again DB5=DB4=1
9766 $5 20_US \ 5- wait 0,1 ms
9767 $03 TOP_LCD \ 6- send again again DB5=DB4=1
9768 $2 20_US \ wait 40 us = LCD cycle
9769 $02 TOP_LCD \ 7- send DB5=1 DB4=0
9770 $2 20_US \ wait 40 us = LCD cycle
9771 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
9772 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
9773 LCD_Clear \ 10- "LCD_Clear"
9774 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
9775 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
9776 LCD_Clear \ 10- "LCD_Clear"
9777 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
9778 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
9780 ['] CR >BODY IS CR \
9781 ['] EMIT >BODY IS EMIT \
9782 ." RC5toLCD is running. Type STOP to quit"
9783 LIT RECURSE IS WARM \ replace WARM by this START routine
9784 ABORT \ and continue with the next word after WARM...
9785 ; \ ...until interpreter falls in sleep mode within ACCEPT.
9788 CODE STOP \ stops multitasking, must to be used before downloading app
9789 \ restore default action of primary DEFERred word SLEEP, assembly version
9790 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
9791 ADD #4,X \ X = BODY of SLEEP
9792 MOV X,-2(X) \ restore the default background
9795 \ restore default action of primary DEFERred word WARM, FORTH version
9796 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
9798 COLD \ because we want to reset CPU and interrupt vectors
9803 ; downloading RC5toLCD.4th is done
9804 RST_HERE ; this app is protected against <reset>
9812 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
9814 [DEFINED] ASM [IF] \ security test
9818 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
9820 CODE MAX \ n1 n2 -- n3 signed maximum
9821 CMP @PSP,TOS \ n2-n1
9822 S< ?GOTO FW1 \ n2<n1
9828 CODE MIN \ n1 n2 -- n3 signed minimum
9829 CMP @PSP,TOS \ n2-n1
9830 S< ?GOTO BW1 \ n2<n1
9838 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
9839 : U.R \ u n -- display u unsigned in n width (n >= 2)
9841 R> OVER - 0 MAX SPACES TYPE
9846 \ CODE 20_US \ n -- n * 20 us
9847 \ BEGIN \ 3 cycles loop + 6~
9848 \ \ MOV #5,W \ 3 MCLK = 1 MHz
9849 \ \ MOV #23,W \ 3 MCLK = 4 MHz
9850 \ \ MOV #51,W \ 3 MCLK = 8 MHz
9851 \ MOV #104,W \ 3 MCLK = 16 MHz
9852 \ \ MOV #158,W \ 3 MCLK = 24 MHz
9853 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
9863 CODE 20_US \ n -- n * 20 us
9864 BEGIN \ here we presume that LCD_TIM_IFG = 1...
9866 BIT #1,&LCD_TIM_CTL \ 3
9867 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
9868 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
9870 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
9876 CODE TOP_LCD \ LCD Sample
9877 \ \ if write : %xxxxWWWW --
9878 \ \ if read : -- %0000RRRR
9879 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
9880 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
9881 0= IF \ write LCD bits pattern
9883 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
9884 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
9887 THEN \ read LCD bits pattern
9890 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
9891 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
9897 CODE LCD_W \ byte -- write byte to LCD
9899 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
9900 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
9901 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
9902 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
9903 COLON \ high level word starts here
9904 TOP_LCD 2 20_US \ write high nibble first
9909 CODE LCD_WrC \ char -- Write Char
9910 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
9915 CODE LCD_WrF \ func -- Write Fonction
9916 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
9922 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
9927 $02 LCD_WrF 100 20_us
9933 \ https://forth-standard.org/standard/core/OR
9934 \ C OR x1 x2 -- x3 logical OR
9943 : LCD_Entry_set $04 OR LCD_WrF ;
9945 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
9947 : LCD_DSP_Shift $10 OR LCD_WrF ;
9949 : LCD_Fn_Set $20 OR LCD_WrF ;
9951 : LCD_CGRAM_Set $40 OR LCD_WrF ;
9953 : LCD_Goto $80 OR LCD_WrF ;
9955 CODE LCD_R \ -- byte read byte from LCD
9956 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
9957 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
9958 COLON \ starts a FORTH word
9959 TOP_LCD 2 20_us \ -- %0000HHHH
9960 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
9961 HI2LO \ switch from FORTH to assembler
9962 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
9963 ADD.B @PSP+,TOS \ -- %HHHHLLLL
9964 MOV @RSP+,IP \ restore IP saved by COLON
9969 CODE LCD_RdS \ -- status Read Status
9970 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
9975 CODE LCD_RdC \ -- char Read Char
9976 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
9982 \ ******************************\
9983 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
9984 \ ******************************\
9985 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
9986 BIT.B #SW2,&SW2_IN \ test switch S2
9987 0= IF \ case of switch S2 pressed
9988 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
9990 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
9993 BIT.B #SW1,&SW1_IN \ test switch S1 input
9994 0= IF \ case of Switch S1 pressed
9995 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
9997 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
10001 BW1 \ from quit on truncated RC5 message
10002 BW2 \ from repeated RC5 command
10003 BW3 \ from end of RC5_INT
10004 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
10009 \ ******************************\
10010 ASM RC5_INT \ wake up on Px.RC5 change interrupt
10011 \ ******************************\
10012 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
10013 \ ******************************\
10014 \ \ in : SR(9)=old Toggle bit memory (ADD on)
10015 \ \ SMclock = 8|16|24 MHz
10016 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
10017 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
10018 \ \ SR(9)=new Toggle bit memory (ADD on)
10019 \ ******************************\
10020 \ RC5_FirstStartBitHalfCycle: \
10021 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
10022 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
10023 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
10024 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
10025 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
10026 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
10027 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
10028 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
10029 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
10030 MOV #1778,X \ RC5_Period * 1us
10031 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
10032 MOV #14,W \ count of loop
10034 \ ******************************\
10035 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
10036 \ ******************************\ |
10037 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
10038 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
10039 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
10040 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
10041 \ RC5_Compute_3/4_Period: \ |
10042 RRUM #1,X \ X=1/2 cycle |
10045 ADD X,Y \ Y=3/4 cycle
10046 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
10048 \ ******************************\
10049 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
10050 \ ******************************\
10051 BIT.B #RC5,&IR_IN \ C_flag = IR bit
10052 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
10053 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
10054 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
10055 SUB #1,W \ decrement count loop
10056 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
10057 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
10058 0<> WHILE \ ----> out of loop ----+
10059 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
10061 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
10062 CMP Y,X \ 1 | cycle time out of bound ?
10063 U>= IF \ 2 ^ | yes:
10064 BIC #$30,&RC5_TIM_CTL \ | | stop timer
10065 GOTO BW1 \ | | quit on truncated RC5 message
10067 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
10069 REPEAT \ ----> loop back --+ | with X = new RC5_period value
10070 \ ******************************\ |
10071 \ RC5_SampleEndOf: \ <---------------------+
10072 \ ******************************\
10073 BIC #$30,&RC5_TIM_CTL \ stop timer
10074 \ ******************************\
10075 \ RC5_ComputeNewRC5word \
10076 \ ******************************\
10077 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
10078 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
10079 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
10080 \ ******************************\
10081 \ RC5_ComputeC6bit \
10082 \ ******************************\
10083 BIT #BIT14,T \ test /C6 bit in T
10084 0= IF BIS #BIT6,X \ set C6 bit in X
10085 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
10086 \ ******************************\
10087 \ RC5_CommandByteIsDone \ -- BASE RC5_code
10088 \ ******************************\
10089 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
10090 \ ******************************\
10091 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
10092 XOR @RSP,T \ (new XOR old) Toggle bits
10093 BIT #UF10,T \ repeated RC5_command ?
10094 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
10095 XOR #UF10,0(RSP) \ 5 toggle bit memory
10096 \ ******************************\
10097 \ Display IR_RC5 code \ X = RC5 code
10098 \ ******************************\
10100 MOV &BASE,2(PSP) \ save current base
10101 MOV #$10,&BASE \ set hex base
10102 MOV TOS,0(PSP) \ save TOS
10104 LO2HI \ switch from assembler to FORTH
10105 ['] LCD_CLEAR IS CR \ redirects CR
10106 ['] LCD_WrC IS EMIT \ redirects EMIT
10107 CR ." $" 2 U.R \ print IR_RC5 code
10108 ['] CR >BODY IS CR \ restore CR
10109 ['] EMIT >BODY IS EMIT \ restore EMIT
10110 HI2LO \ switch from FORTH to assembler
10111 MOV TOS,&BASE \ restore current BASE
10113 \ ******************************\
10115 \ ******************************\
10119 \ ------------------------------\
10121 \ ------------------------------\
10122 \ ... \ insert here your background task
10125 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
10126 ADD #4,X \ 1 X = BODY of SLEEP
10129 \ ------------------------------\
10133 \ ------------------------------\
10134 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
10135 \ - - \CNTL Counter lentgh \ 00 = 16 bits
10136 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
10137 \ -- \ID input divider \ 10 = /4
10138 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
10139 \ - \TBCLR TimerB Clear
10142 \ -------------------------------\
10143 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
10144 \ -- \CM Capture Mode
10149 \ --- \OUTMOD \ 011 = set/reset
10155 \ -------------------------------\
10157 \ -------------------------------\
10159 \ ------------------------------\
10160 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
10161 \ ------------------------------\
10162 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
10163 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
10164 \ ------------------------------\
10165 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
10166 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
10167 \ ------------------------------\
10168 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
10169 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
10170 \ ------------------------------\
10171 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
10172 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
10173 \ ------------------------------\
10174 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
10175 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
10176 \ ------------------------------\
10177 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
10178 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
10179 \ ------------------------------\
10180 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
10181 \ ------------------------------\
10182 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
10183 \ ------------------------------\
10184 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
10185 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
10186 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
10187 \ ------------------------------\
10188 BIS.B #LCDVo,&LCDVo_DIR \
10189 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
10190 \ ------------------------------\
10191 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
10192 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
10193 \ ------------------------------\
10194 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
10195 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
10196 \ ******************************\
10198 \ ******************************\
10199 BIS.B #RC5,&IR_IE \ enable RC5_Int
10200 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
10201 MOV #RC5_INT,&IR_Vec \ init interrupt vector
10202 \ ******************************\
10203 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
10204 \ ******************************\
10205 \ %01 0001 0100 \ TAxCTL
10206 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
10207 \ -- \ ID divided by 1
10208 \ -- \ MC MODE = up to TAxCCRn
10209 \ - \ TACLR clear timer count
10212 \ ------------------------------\
10213 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
10214 \ ------------------------------\
10216 \ --- \ TAIDEX pre divisor
10217 \ ------------------------------\
10218 \ %0000 0000 0000 0101 \ TAxCCR0
10219 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
10220 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
10221 \ ------------------------------\
10222 \ %0000 0000 0001 0000 \ TAxCCTL0
10223 \ - \ CAP capture/compare mode = compare
10226 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
10227 \ ------------------------------\
10228 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
10229 \ ------------------------------\
10230 \ define LPM mode for ACCEPT \
10231 \ ------------------------------\
10232 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
10233 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
10234 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
10236 \ ------------------------------\
10237 \ redirects to background task \
10238 \ ------------------------------\
10240 MOV #BACKGROUND,2(X) \
10241 \ ------------------------------\
10243 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
10245 \ ------------------------------\
10247 \ ------------------------------\
10248 $03E8 20_US \ 1- wait 20 ms
10249 $03 TOP_LCD \ 2- send DB5=DB4=1
10250 $CD 20_US \ 3- wait 4,1 ms
10251 $03 TOP_LCD \ 4- send again DB5=DB4=1
10252 $5 20_US \ 5- wait 0,1 ms
10253 $03 TOP_LCD \ 6- send again again DB5=DB4=1
10254 $2 20_US \ wait 40 us = LCD cycle
10255 $02 TOP_LCD \ 7- send DB5=1 DB4=0
10256 $2 20_US \ wait 40 us = LCD cycle
10257 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
10258 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
10259 LCD_Clear \ 10- "LCD_Clear"
10260 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
10261 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
10262 LCD_Clear \ 10- "LCD_Clear"
10263 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
10264 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
10266 ['] CR >BODY IS CR \
10267 ['] EMIT >BODY IS EMIT \
10268 ." RC5toLCD is running. Type STOP to quit"
10269 LIT RECURSE IS WARM \ replace WARM by this START routine
10270 ABORT \ and continue with the next word after WARM...
10271 ; \ ...until interpreter falls in sleep mode within ACCEPT.
10274 CODE STOP \ stops multitasking, must to be used before downloading app
10275 \ restore default action of primary DEFERred word SLEEP, assembly version
10276 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
10277 ADD #4,X \ X = BODY of SLEEP
10278 MOV X,-2(X) \ restore the default background
10281 \ restore default action of primary DEFERred word WARM, FORTH version
10282 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
10284 COLD \ because we want to reset CPU and interrupt vectors
10289 ; downloading RC5toLCD.4th is done
10290 RST_HERE ; this app is protected against <reset>
10298 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
10300 [DEFINED] ASM [IF] \ security test
10304 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
10306 CODE MAX \ n1 n2 -- n3 signed maximum
10307 CMP @PSP,TOS \ n2-n1
10308 S< ?GOTO FW1 \ n2<n1
10314 CODE MIN \ n1 n2 -- n3 signed minimum
10315 CMP @PSP,TOS \ n2-n1
10316 S< ?GOTO BW1 \ n2<n1
10324 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
10325 : U.R \ u n -- display u unsigned in n width (n >= 2)
10327 R> OVER - 0 MAX SPACES TYPE
10332 \ CODE 20_US \ n -- n * 20 us
10333 \ BEGIN \ 3 cycles loop + 6~
10334 \ \ MOV #5,W \ 3 MCLK = 1 MHz
10335 \ \ MOV #23,W \ 3 MCLK = 4 MHz
10336 \ \ MOV #51,W \ 3 MCLK = 8 MHz
10337 \ MOV #104,W \ 3 MCLK = 16 MHz
10338 \ \ MOV #158,W \ 3 MCLK = 24 MHz
10339 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
10344 \ MOV @PSP+,TOS \ 2
10349 CODE 20_US \ n -- n * 20 us
10350 BEGIN \ here we presume that LCD_TIM_IFG = 1...
10352 BIT #1,&LCD_TIM_CTL \ 3
10353 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
10354 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
10356 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
10362 CODE TOP_LCD \ LCD Sample
10363 \ \ if write : %xxxxWWWW --
10364 \ \ if read : -- %0000RRRR
10365 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
10366 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
10367 0= IF \ write LCD bits pattern
10368 AND.B #LCD_DB,TOS \
10369 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
10370 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
10373 THEN \ read LCD bits pattern
10376 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
10377 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
10378 AND.B #LCD_DB,TOS \
10383 CODE LCD_W \ byte -- write byte to LCD
10385 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
10386 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
10387 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
10388 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
10389 COLON \ high level word starts here
10390 TOP_LCD 2 20_US \ write high nibble first
10395 CODE LCD_WrC \ char -- Write Char
10396 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
10401 CODE LCD_WrF \ func -- Write Fonction
10402 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
10408 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
10413 $02 LCD_WrF 100 20_us
10417 [UNDEFINED] OR [IF]
10419 \ https://forth-standard.org/standard/core/OR
10420 \ C OR x1 x2 -- x3 logical OR
10429 : LCD_Entry_set $04 OR LCD_WrF ;
10431 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
10433 : LCD_DSP_Shift $10 OR LCD_WrF ;
10435 : LCD_Fn_Set $20 OR LCD_WrF ;
10437 : LCD_CGRAM_Set $40 OR LCD_WrF ;
10439 : LCD_Goto $80 OR LCD_WrF ;
10441 CODE LCD_R \ -- byte read byte from LCD
10442 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
10443 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
10444 COLON \ starts a FORTH word
10445 TOP_LCD 2 20_us \ -- %0000HHHH
10446 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
10447 HI2LO \ switch from FORTH to assembler
10448 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
10449 ADD.B @PSP+,TOS \ -- %HHHHLLLL
10450 MOV @RSP+,IP \ restore IP saved by COLON
10455 CODE LCD_RdS \ -- status Read Status
10456 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
10461 CODE LCD_RdC \ -- char Read Char
10462 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
10468 \ ******************************\
10469 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
10470 \ ******************************\
10471 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
10472 BIT.B #SW2,&SW2_IN \ test switch S2
10473 0= IF \ case of switch S2 pressed
10474 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
10476 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
10479 BIT.B #SW1,&SW1_IN \ test switch S1 input
10480 0= IF \ case of Switch S1 pressed
10481 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
10483 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
10487 BW1 \ from quit on truncated RC5 message
10488 BW2 \ from repeated RC5 command
10489 BW3 \ from end of RC5_INT
10490 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
10495 \ ******************************\
10496 ASM RC5_INT \ wake up on Px.RC5 change interrupt
10497 \ ******************************\
10498 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
10499 \ ******************************\
10500 \ \ in : SR(9)=old Toggle bit memory (ADD on)
10501 \ \ SMclock = 8|16|24 MHz
10502 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
10503 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
10504 \ \ SR(9)=new Toggle bit memory (ADD on)
10505 \ ******************************\
10506 \ RC5_FirstStartBitHalfCycle: \
10507 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
10508 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
10509 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
10510 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
10511 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
10512 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
10513 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
10514 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
10515 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
10516 MOV #1778,X \ RC5_Period * 1us
10517 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
10518 MOV #14,W \ count of loop
10520 \ ******************************\
10521 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
10522 \ ******************************\ |
10523 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
10524 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
10525 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
10526 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
10527 \ RC5_Compute_3/4_Period: \ |
10528 RRUM #1,X \ X=1/2 cycle |
10531 ADD X,Y \ Y=3/4 cycle
10532 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
10534 \ ******************************\
10535 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
10536 \ ******************************\
10537 BIT.B #RC5,&IR_IN \ C_flag = IR bit
10538 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
10539 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
10540 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
10541 SUB #1,W \ decrement count loop
10542 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
10543 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
10544 0<> WHILE \ ----> out of loop ----+
10545 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
10547 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
10548 CMP Y,X \ 1 | cycle time out of bound ?
10549 U>= IF \ 2 ^ | yes:
10550 BIC #$30,&RC5_TIM_CTL \ | | stop timer
10551 GOTO BW1 \ | | quit on truncated RC5 message
10553 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
10555 REPEAT \ ----> loop back --+ | with X = new RC5_period value
10556 \ ******************************\ |
10557 \ RC5_SampleEndOf: \ <---------------------+
10558 \ ******************************\
10559 BIC #$30,&RC5_TIM_CTL \ stop timer
10560 \ ******************************\
10561 \ RC5_ComputeNewRC5word \
10562 \ ******************************\
10563 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
10564 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
10565 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
10566 \ ******************************\
10567 \ RC5_ComputeC6bit \
10568 \ ******************************\
10569 BIT #BIT14,T \ test /C6 bit in T
10570 0= IF BIS #BIT6,X \ set C6 bit in X
10571 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
10572 \ ******************************\
10573 \ RC5_CommandByteIsDone \ -- BASE RC5_code
10574 \ ******************************\
10575 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
10576 \ ******************************\
10577 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
10578 XOR @RSP,T \ (new XOR old) Toggle bits
10579 BIT #UF10,T \ repeated RC5_command ?
10580 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
10581 XOR #UF10,0(RSP) \ 5 toggle bit memory
10582 \ ******************************\
10583 \ Display IR_RC5 code \ X = RC5 code
10584 \ ******************************\
10586 MOV &BASE,2(PSP) \ save current base
10587 MOV #$10,&BASE \ set hex base
10588 MOV TOS,0(PSP) \ save TOS
10590 LO2HI \ switch from assembler to FORTH
10591 ['] LCD_CLEAR IS CR \ redirects CR
10592 ['] LCD_WrC IS EMIT \ redirects EMIT
10593 CR ." $" 2 U.R \ print IR_RC5 code
10594 ['] CR >BODY IS CR \ restore CR
10595 ['] EMIT >BODY IS EMIT \ restore EMIT
10596 HI2LO \ switch from FORTH to assembler
10597 MOV TOS,&BASE \ restore current BASE
10599 \ ******************************\
10601 \ ******************************\
10605 \ ------------------------------\
10607 \ ------------------------------\
10608 \ ... \ insert here your background task
10611 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
10612 ADD #4,X \ 1 X = BODY of SLEEP
10615 \ ------------------------------\
10619 \ ------------------------------\
10620 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
10621 \ - - \CNTL Counter lentgh \ 00 = 16 bits
10622 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
10623 \ -- \ID input divider \ 10 = /4
10624 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
10625 \ - \TBCLR TimerB Clear
10628 \ -------------------------------\
10629 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
10630 \ -- \CM Capture Mode
10635 \ --- \OUTMOD \ 011 = set/reset
10641 \ -------------------------------\
10643 \ -------------------------------\
10645 \ ------------------------------\
10646 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
10647 \ ------------------------------\
10648 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
10649 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
10650 \ ------------------------------\
10651 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
10652 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
10653 \ ------------------------------\
10654 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
10655 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
10656 \ ------------------------------\
10657 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
10658 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
10659 \ ------------------------------\
10660 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
10661 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
10662 \ ------------------------------\
10663 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
10664 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
10665 \ ------------------------------\
10666 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
10667 \ ------------------------------\
10668 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
10669 \ ------------------------------\
10670 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
10671 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
10672 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
10673 \ ------------------------------\
10674 BIS.B #LCDVo,&LCDVo_DIR \
10675 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
10676 \ ------------------------------\
10677 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
10678 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
10679 \ ------------------------------\
10680 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
10681 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
10682 \ ******************************\
10684 \ ******************************\
10685 BIS.B #RC5,&IR_IE \ enable RC5_Int
10686 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
10687 MOV #RC5_INT,&IR_Vec \ init interrupt vector
10688 \ ******************************\
10689 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
10690 \ ******************************\
10691 \ %01 0001 0100 \ TAxCTL
10692 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
10693 \ -- \ ID divided by 1
10694 \ -- \ MC MODE = up to TAxCCRn
10695 \ - \ TACLR clear timer count
10698 \ ------------------------------\
10699 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
10700 \ ------------------------------\
10702 \ --- \ TAIDEX pre divisor
10703 \ ------------------------------\
10704 \ %0000 0000 0000 0101 \ TAxCCR0
10705 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
10706 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
10707 \ ------------------------------\
10708 \ %0000 0000 0001 0000 \ TAxCCTL0
10709 \ - \ CAP capture/compare mode = compare
10712 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
10713 \ ------------------------------\
10714 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
10715 \ ------------------------------\
10716 \ define LPM mode for ACCEPT \
10717 \ ------------------------------\
10718 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
10719 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
10720 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
10722 \ ------------------------------\
10723 \ redirects to background task \
10724 \ ------------------------------\
10726 MOV #BACKGROUND,2(X) \
10727 \ ------------------------------\
10729 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
10731 \ ------------------------------\
10733 \ ------------------------------\
10734 $03E8 20_US \ 1- wait 20 ms
10735 $03 TOP_LCD \ 2- send DB5=DB4=1
10736 $CD 20_US \ 3- wait 4,1 ms
10737 $03 TOP_LCD \ 4- send again DB5=DB4=1
10738 $5 20_US \ 5- wait 0,1 ms
10739 $03 TOP_LCD \ 6- send again again DB5=DB4=1
10740 $2 20_US \ wait 40 us = LCD cycle
10741 $02 TOP_LCD \ 7- send DB5=1 DB4=0
10742 $2 20_US \ wait 40 us = LCD cycle
10743 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
10744 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
10745 LCD_Clear \ 10- "LCD_Clear"
10746 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
10747 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
10748 LCD_Clear \ 10- "LCD_Clear"
10749 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
10750 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
10752 ['] CR >BODY IS CR \
10753 ['] EMIT >BODY IS EMIT \
10754 ." RC5toLCD is running. Type STOP to quit"
10755 LIT RECURSE IS WARM \ replace WARM by this START routine
10756 ABORT \ and continue with the next word after WARM...
10757 ; \ ...until interpreter falls in sleep mode within ACCEPT.
10760 CODE STOP \ stops multitasking, must to be used before downloading app
10761 \ restore default action of primary DEFERred word SLEEP, assembly version
10762 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
10763 ADD #4,X \ X = BODY of SLEEP
10764 MOV X,-2(X) \ restore the default background
10767 \ restore default action of primary DEFERred word WARM, FORTH version
10768 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
10770 COLD \ because we want to reset CPU and interrupt vectors
10775 ; downloading RC5toLCD.4th is done
10776 RST_HERE ; this app is protected against <reset>
10784 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
10786 [DEFINED] ASM [IF] \ security test
10790 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
10792 CODE MAX \ n1 n2 -- n3 signed maximum
10793 CMP @PSP,TOS \ n2-n1
10794 S< ?GOTO FW1 \ n2<n1
10800 CODE MIN \ n1 n2 -- n3 signed minimum
10801 CMP @PSP,TOS \ n2-n1
10802 S< ?GOTO BW1 \ n2<n1
10810 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
10811 : U.R \ u n -- display u unsigned in n width (n >= 2)
10813 R> OVER - 0 MAX SPACES TYPE
10818 \ CODE 20_US \ n -- n * 20 us
10819 \ BEGIN \ 3 cycles loop + 6~
10820 \ \ MOV #5,W \ 3 MCLK = 1 MHz
10821 \ \ MOV #23,W \ 3 MCLK = 4 MHz
10822 \ \ MOV #51,W \ 3 MCLK = 8 MHz
10823 \ MOV #104,W \ 3 MCLK = 16 MHz
10824 \ \ MOV #158,W \ 3 MCLK = 24 MHz
10825 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
10830 \ MOV @PSP+,TOS \ 2
10835 CODE 20_US \ n -- n * 20 us
10836 BEGIN \ here we presume that LCD_TIM_IFG = 1...
10838 BIT #1,&LCD_TIM_CTL \ 3
10839 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
10840 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
10842 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
10848 CODE TOP_LCD \ LCD Sample
10849 \ \ if write : %xxxxWWWW --
10850 \ \ if read : -- %0000RRRR
10851 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
10852 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
10853 0= IF \ write LCD bits pattern
10854 AND.B #LCD_DB,TOS \
10855 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
10856 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
10859 THEN \ read LCD bits pattern
10862 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
10863 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
10864 AND.B #LCD_DB,TOS \
10869 CODE LCD_W \ byte -- write byte to LCD
10871 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
10872 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
10873 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
10874 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
10875 COLON \ high level word starts here
10876 TOP_LCD 2 20_US \ write high nibble first
10881 CODE LCD_WrC \ char -- Write Char
10882 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
10887 CODE LCD_WrF \ func -- Write Fonction
10888 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
10894 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
10899 $02 LCD_WrF 100 20_us
10903 [UNDEFINED] OR [IF]
10905 \ https://forth-standard.org/standard/core/OR
10906 \ C OR x1 x2 -- x3 logical OR
10915 : LCD_Entry_set $04 OR LCD_WrF ;
10917 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
10919 : LCD_DSP_Shift $10 OR LCD_WrF ;
10921 : LCD_Fn_Set $20 OR LCD_WrF ;
10923 : LCD_CGRAM_Set $40 OR LCD_WrF ;
10925 : LCD_Goto $80 OR LCD_WrF ;
10927 CODE LCD_R \ -- byte read byte from LCD
10928 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
10929 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
10930 COLON \ starts a FORTH word
10931 TOP_LCD 2 20_us \ -- %0000HHHH
10932 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
10933 HI2LO \ switch from FORTH to assembler
10934 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
10935 ADD.B @PSP+,TOS \ -- %HHHHLLLL
10936 MOV @RSP+,IP \ restore IP saved by COLON
10941 CODE LCD_RdS \ -- status Read Status
10942 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
10947 CODE LCD_RdC \ -- char Read Char
10948 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
10954 \ ******************************\
10955 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
10956 \ ******************************\
10957 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
10958 BIT.B #SW2,&SW2_IN \ test switch S2
10959 0= IF \ case of switch S2 pressed
10960 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
10962 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
10965 BIT.B #SW1,&SW1_IN \ test switch S1 input
10966 0= IF \ case of Switch S1 pressed
10967 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
10969 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
10973 BW1 \ from quit on truncated RC5 message
10974 BW2 \ from repeated RC5 command
10975 BW3 \ from end of RC5_INT
10976 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
10981 \ ******************************\
10982 ASM RC5_INT \ wake up on Px.RC5 change interrupt
10983 \ ******************************\
10984 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
10985 \ ******************************\
10986 \ \ in : SR(9)=old Toggle bit memory (ADD on)
10987 \ \ SMclock = 8|16|24 MHz
10988 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
10989 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
10990 \ \ SR(9)=new Toggle bit memory (ADD on)
10991 \ ******************************\
10992 \ RC5_FirstStartBitHalfCycle: \
10993 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
10994 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
10995 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
10996 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
10997 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
10998 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
10999 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
11000 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
11001 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
11002 MOV #1778,X \ RC5_Period * 1us
11003 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
11004 MOV #14,W \ count of loop
11006 \ ******************************\
11007 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
11008 \ ******************************\ |
11009 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
11010 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
11011 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
11012 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
11013 \ RC5_Compute_3/4_Period: \ |
11014 RRUM #1,X \ X=1/2 cycle |
11017 ADD X,Y \ Y=3/4 cycle
11018 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
11020 \ ******************************\
11021 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
11022 \ ******************************\
11023 BIT.B #RC5,&IR_IN \ C_flag = IR bit
11024 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
11025 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
11026 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
11027 SUB #1,W \ decrement count loop
11028 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
11029 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
11030 0<> WHILE \ ----> out of loop ----+
11031 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
11033 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
11034 CMP Y,X \ 1 | cycle time out of bound ?
11035 U>= IF \ 2 ^ | yes:
11036 BIC #$30,&RC5_TIM_CTL \ | | stop timer
11037 GOTO BW1 \ | | quit on truncated RC5 message
11039 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
11041 REPEAT \ ----> loop back --+ | with X = new RC5_period value
11042 \ ******************************\ |
11043 \ RC5_SampleEndOf: \ <---------------------+
11044 \ ******************************\
11045 BIC #$30,&RC5_TIM_CTL \ stop timer
11046 \ ******************************\
11047 \ RC5_ComputeNewRC5word \
11048 \ ******************************\
11049 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
11050 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
11051 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
11052 \ ******************************\
11053 \ RC5_ComputeC6bit \
11054 \ ******************************\
11055 BIT #BIT14,T \ test /C6 bit in T
11056 0= IF BIS #BIT6,X \ set C6 bit in X
11057 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
11058 \ ******************************\
11059 \ RC5_CommandByteIsDone \ -- BASE RC5_code
11060 \ ******************************\
11061 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
11062 \ ******************************\
11063 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
11064 XOR @RSP,T \ (new XOR old) Toggle bits
11065 BIT #UF10,T \ repeated RC5_command ?
11066 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
11067 XOR #UF10,0(RSP) \ 5 toggle bit memory
11068 \ ******************************\
11069 \ Display IR_RC5 code \ X = RC5 code
11070 \ ******************************\
11072 MOV &BASE,2(PSP) \ save current base
11073 MOV #$10,&BASE \ set hex base
11074 MOV TOS,0(PSP) \ save TOS
11076 LO2HI \ switch from assembler to FORTH
11077 ['] LCD_CLEAR IS CR \ redirects CR
11078 ['] LCD_WrC IS EMIT \ redirects EMIT
11079 CR ." $" 2 U.R \ print IR_RC5 code
11080 ['] CR >BODY IS CR \ restore CR
11081 ['] EMIT >BODY IS EMIT \ restore EMIT
11082 HI2LO \ switch from FORTH to assembler
11083 MOV TOS,&BASE \ restore current BASE
11085 \ ******************************\
11087 \ ******************************\
11091 \ ------------------------------\
11093 \ ------------------------------\
11094 \ ... \ insert here your background task
11097 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
11098 ADD #4,X \ 1 X = BODY of SLEEP
11101 \ ------------------------------\
11105 \ ------------------------------\
11106 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
11107 \ - - \CNTL Counter lentgh \ 00 = 16 bits
11108 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
11109 \ -- \ID input divider \ 10 = /4
11110 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
11111 \ - \TBCLR TimerB Clear
11114 \ -------------------------------\
11115 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
11116 \ -- \CM Capture Mode
11121 \ --- \OUTMOD \ 011 = set/reset
11127 \ -------------------------------\
11129 \ -------------------------------\
11131 \ ------------------------------\
11132 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
11133 \ ------------------------------\
11134 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
11135 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
11136 \ ------------------------------\
11137 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
11138 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
11139 \ ------------------------------\
11140 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
11141 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
11142 \ ------------------------------\
11143 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
11144 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
11145 \ ------------------------------\
11146 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
11147 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
11148 \ ------------------------------\
11149 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
11150 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
11151 \ ------------------------------\
11152 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
11153 \ ------------------------------\
11154 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
11155 \ ------------------------------\
11156 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
11157 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
11158 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
11159 \ ------------------------------\
11160 BIS.B #LCDVo,&LCDVo_DIR \
11161 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
11162 \ ------------------------------\
11163 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
11164 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
11165 \ ------------------------------\
11166 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
11167 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
11168 \ ******************************\
11170 \ ******************************\
11171 BIS.B #RC5,&IR_IE \ enable RC5_Int
11172 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
11173 MOV #RC5_INT,&IR_Vec \ init interrupt vector
11174 \ ******************************\
11175 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
11176 \ ******************************\
11177 \ %01 0001 0100 \ TAxCTL
11178 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
11179 \ -- \ ID divided by 1
11180 \ -- \ MC MODE = up to TAxCCRn
11181 \ - \ TACLR clear timer count
11184 \ ------------------------------\
11185 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
11186 \ ------------------------------\
11188 \ --- \ TAIDEX pre divisor
11189 \ ------------------------------\
11190 \ %0000 0000 0000 0101 \ TAxCCR0
11191 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
11192 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
11193 \ ------------------------------\
11194 \ %0000 0000 0001 0000 \ TAxCCTL0
11195 \ - \ CAP capture/compare mode = compare
11198 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
11199 \ ------------------------------\
11200 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
11201 \ ------------------------------\
11202 \ define LPM mode for ACCEPT \
11203 \ ------------------------------\
11204 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
11205 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
11206 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
11208 \ ------------------------------\
11209 \ redirects to background task \
11210 \ ------------------------------\
11212 MOV #BACKGROUND,2(X) \
11213 \ ------------------------------\
11215 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
11217 \ ------------------------------\
11219 \ ------------------------------\
11220 $03E8 20_US \ 1- wait 20 ms
11221 $03 TOP_LCD \ 2- send DB5=DB4=1
11222 $CD 20_US \ 3- wait 4,1 ms
11223 $03 TOP_LCD \ 4- send again DB5=DB4=1
11224 $5 20_US \ 5- wait 0,1 ms
11225 $03 TOP_LCD \ 6- send again again DB5=DB4=1
11226 $2 20_US \ wait 40 us = LCD cycle
11227 $02 TOP_LCD \ 7- send DB5=1 DB4=0
11228 $2 20_US \ wait 40 us = LCD cycle
11229 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
11230 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
11231 LCD_Clear \ 10- "LCD_Clear"
11232 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
11233 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
11234 LCD_Clear \ 10- "LCD_Clear"
11235 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
11236 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
11238 ['] CR >BODY IS CR \
11239 ['] EMIT >BODY IS EMIT \
11240 ." RC5toLCD is running. Type STOP to quit"
11241 LIT RECURSE IS WARM \ replace WARM by this START routine
11242 ABORT \ and continue with the next word after WARM...
11243 ; \ ...until interpreter falls in sleep mode within ACCEPT.
11246 CODE STOP \ stops multitasking, must to be used before downloading app
11247 \ restore default action of primary DEFERred word SLEEP, assembly version
11248 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
11249 ADD #4,X \ X = BODY of SLEEP
11250 MOV X,-2(X) \ restore the default background
11253 \ restore default action of primary DEFERred word WARM, FORTH version
11254 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
11256 COLD \ because we want to reset CPU and interrupt vectors
11261 ; downloading RC5toLCD.4th is done
11262 RST_HERE ; this app is protected against <reset>
11270 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
11272 [DEFINED] ASM [IF] \ security test
11276 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
11278 CODE MAX \ n1 n2 -- n3 signed maximum
11279 CMP @PSP,TOS \ n2-n1
11280 S< ?GOTO FW1 \ n2<n1
11286 CODE MIN \ n1 n2 -- n3 signed minimum
11287 CMP @PSP,TOS \ n2-n1
11288 S< ?GOTO BW1 \ n2<n1
11296 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
11297 : U.R \ u n -- display u unsigned in n width (n >= 2)
11299 R> OVER - 0 MAX SPACES TYPE
11304 \ CODE 20_US \ n -- n * 20 us
11305 \ BEGIN \ 3 cycles loop + 6~
11306 \ \ MOV #5,W \ 3 MCLK = 1 MHz
11307 \ \ MOV #23,W \ 3 MCLK = 4 MHz
11308 \ \ MOV #51,W \ 3 MCLK = 8 MHz
11309 \ MOV #104,W \ 3 MCLK = 16 MHz
11310 \ \ MOV #158,W \ 3 MCLK = 24 MHz
11311 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
11316 \ MOV @PSP+,TOS \ 2
11321 CODE 20_US \ n -- n * 20 us
11322 BEGIN \ here we presume that LCD_TIM_IFG = 1...
11324 BIT #1,&LCD_TIM_CTL \ 3
11325 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
11326 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
11328 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
11334 CODE TOP_LCD \ LCD Sample
11335 \ \ if write : %xxxxWWWW --
11336 \ \ if read : -- %0000RRRR
11337 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
11338 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
11339 0= IF \ write LCD bits pattern
11340 AND.B #LCD_DB,TOS \
11341 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
11342 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
11345 THEN \ read LCD bits pattern
11348 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
11349 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
11350 AND.B #LCD_DB,TOS \
11355 CODE LCD_W \ byte -- write byte to LCD
11357 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
11358 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
11359 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
11360 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
11361 COLON \ high level word starts here
11362 TOP_LCD 2 20_US \ write high nibble first
11367 CODE LCD_WrC \ char -- Write Char
11368 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
11373 CODE LCD_WrF \ func -- Write Fonction
11374 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
11380 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
11385 $02 LCD_WrF 100 20_us
11389 [UNDEFINED] OR [IF]
11391 \ https://forth-standard.org/standard/core/OR
11392 \ C OR x1 x2 -- x3 logical OR
11401 : LCD_Entry_set $04 OR LCD_WrF ;
11403 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
11405 : LCD_DSP_Shift $10 OR LCD_WrF ;
11407 : LCD_Fn_Set $20 OR LCD_WrF ;
11409 : LCD_CGRAM_Set $40 OR LCD_WrF ;
11411 : LCD_Goto $80 OR LCD_WrF ;
11413 CODE LCD_R \ -- byte read byte from LCD
11414 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
11415 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
11416 COLON \ starts a FORTH word
11417 TOP_LCD 2 20_us \ -- %0000HHHH
11418 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
11419 HI2LO \ switch from FORTH to assembler
11420 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
11421 ADD.B @PSP+,TOS \ -- %HHHHLLLL
11422 MOV @RSP+,IP \ restore IP saved by COLON
11427 CODE LCD_RdS \ -- status Read Status
11428 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
11433 CODE LCD_RdC \ -- char Read Char
11434 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
11440 \ ******************************\
11441 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
11442 \ ******************************\
11443 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
11444 BIT.B #SW2,&SW2_IN \ test switch S2
11445 0= IF \ case of switch S2 pressed
11446 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
11448 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
11451 BIT.B #SW1,&SW1_IN \ test switch S1 input
11452 0= IF \ case of Switch S1 pressed
11453 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
11455 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
11459 BW1 \ from quit on truncated RC5 message
11460 BW2 \ from repeated RC5 command
11461 BW3 \ from end of RC5_INT
11462 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
11467 \ ******************************\
11468 ASM RC5_INT \ wake up on Px.RC5 change interrupt
11469 \ ******************************\
11470 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
11471 \ ******************************\
11472 \ \ in : SR(9)=old Toggle bit memory (ADD on)
11473 \ \ SMclock = 8|16|24 MHz
11474 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
11475 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
11476 \ \ SR(9)=new Toggle bit memory (ADD on)
11477 \ ******************************\
11478 \ RC5_FirstStartBitHalfCycle: \
11479 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
11480 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
11481 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
11482 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
11483 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
11484 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
11485 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
11486 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
11487 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
11488 MOV #1778,X \ RC5_Period * 1us
11489 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
11490 MOV #14,W \ count of loop
11492 \ ******************************\
11493 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
11494 \ ******************************\ |
11495 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
11496 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
11497 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
11498 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
11499 \ RC5_Compute_3/4_Period: \ |
11500 RRUM #1,X \ X=1/2 cycle |
11503 ADD X,Y \ Y=3/4 cycle
11504 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
11506 \ ******************************\
11507 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
11508 \ ******************************\
11509 BIT.B #RC5,&IR_IN \ C_flag = IR bit
11510 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
11511 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
11512 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
11513 SUB #1,W \ decrement count loop
11514 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
11515 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
11516 0<> WHILE \ ----> out of loop ----+
11517 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
11519 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
11520 CMP Y,X \ 1 | cycle time out of bound ?
11521 U>= IF \ 2 ^ | yes:
11522 BIC #$30,&RC5_TIM_CTL \ | | stop timer
11523 GOTO BW1 \ | | quit on truncated RC5 message
11525 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
11527 REPEAT \ ----> loop back --+ | with X = new RC5_period value
11528 \ ******************************\ |
11529 \ RC5_SampleEndOf: \ <---------------------+
11530 \ ******************************\
11531 BIC #$30,&RC5_TIM_CTL \ stop timer
11532 \ ******************************\
11533 \ RC5_ComputeNewRC5word \
11534 \ ******************************\
11535 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
11536 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
11537 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
11538 \ ******************************\
11539 \ RC5_ComputeC6bit \
11540 \ ******************************\
11541 BIT #BIT14,T \ test /C6 bit in T
11542 0= IF BIS #BIT6,X \ set C6 bit in X
11543 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
11544 \ ******************************\
11545 \ RC5_CommandByteIsDone \ -- BASE RC5_code
11546 \ ******************************\
11547 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
11548 \ ******************************\
11549 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
11550 XOR @RSP,T \ (new XOR old) Toggle bits
11551 BIT #UF10,T \ repeated RC5_command ?
11552 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
11553 XOR #UF10,0(RSP) \ 5 toggle bit memory
11554 \ ******************************\
11555 \ Display IR_RC5 code \ X = RC5 code
11556 \ ******************************\
11558 MOV &BASE,2(PSP) \ save current base
11559 MOV #$10,&BASE \ set hex base
11560 MOV TOS,0(PSP) \ save TOS
11562 LO2HI \ switch from assembler to FORTH
11563 ['] LCD_CLEAR IS CR \ redirects CR
11564 ['] LCD_WrC IS EMIT \ redirects EMIT
11565 CR ." $" 2 U.R \ print IR_RC5 code
11566 ['] CR >BODY IS CR \ restore CR
11567 ['] EMIT >BODY IS EMIT \ restore EMIT
11568 HI2LO \ switch from FORTH to assembler
11569 MOV TOS,&BASE \ restore current BASE
11571 \ ******************************\
11573 \ ******************************\
11577 \ ------------------------------\
11579 \ ------------------------------\
11580 \ ... \ insert here your background task
11583 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
11584 ADD #4,X \ 1 X = BODY of SLEEP
11587 \ ------------------------------\
11591 \ ------------------------------\
11592 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
11593 \ - - \CNTL Counter lentgh \ 00 = 16 bits
11594 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
11595 \ -- \ID input divider \ 10 = /4
11596 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
11597 \ - \TBCLR TimerB Clear
11600 \ -------------------------------\
11601 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
11602 \ -- \CM Capture Mode
11607 \ --- \OUTMOD \ 011 = set/reset
11613 \ -------------------------------\
11615 \ -------------------------------\
11617 \ ------------------------------\
11618 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
11619 \ ------------------------------\
11620 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
11621 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
11622 \ ------------------------------\
11623 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
11624 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
11625 \ ------------------------------\
11626 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
11627 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
11628 \ ------------------------------\
11629 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
11630 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
11631 \ ------------------------------\
11632 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
11633 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
11634 \ ------------------------------\
11635 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
11636 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
11637 \ ------------------------------\
11638 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
11639 \ ------------------------------\
11640 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
11641 \ ------------------------------\
11642 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
11643 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
11644 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
11645 \ ------------------------------\
11646 BIS.B #LCDVo,&LCDVo_DIR \
11647 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
11648 \ ------------------------------\
11649 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
11650 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
11651 \ ------------------------------\
11652 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
11653 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
11654 \ ******************************\
11656 \ ******************************\
11657 BIS.B #RC5,&IR_IE \ enable RC5_Int
11658 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
11659 MOV #RC5_INT,&IR_Vec \ init interrupt vector
11660 \ ******************************\
11661 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
11662 \ ******************************\
11663 \ %01 0001 0100 \ TAxCTL
11664 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
11665 \ -- \ ID divided by 1
11666 \ -- \ MC MODE = up to TAxCCRn
11667 \ - \ TACLR clear timer count
11670 \ ------------------------------\
11671 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
11672 \ ------------------------------\
11674 \ --- \ TAIDEX pre divisor
11675 \ ------------------------------\
11676 \ %0000 0000 0000 0101 \ TAxCCR0
11677 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
11678 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
11679 \ ------------------------------\
11680 \ %0000 0000 0001 0000 \ TAxCCTL0
11681 \ - \ CAP capture/compare mode = compare
11684 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
11685 \ ------------------------------\
11686 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
11687 \ ------------------------------\
11688 \ define LPM mode for ACCEPT \
11689 \ ------------------------------\
11690 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
11691 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
11692 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
11694 \ ------------------------------\
11695 \ redirects to background task \
11696 \ ------------------------------\
11698 MOV #BACKGROUND,2(X) \
11699 \ ------------------------------\
11701 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
11703 \ ------------------------------\
11705 \ ------------------------------\
11706 $03E8 20_US \ 1- wait 20 ms
11707 $03 TOP_LCD \ 2- send DB5=DB4=1
11708 $CD 20_US \ 3- wait 4,1 ms
11709 $03 TOP_LCD \ 4- send again DB5=DB4=1
11710 $5 20_US \ 5- wait 0,1 ms
11711 $03 TOP_LCD \ 6- send again again DB5=DB4=1
11712 $2 20_US \ wait 40 us = LCD cycle
11713 $02 TOP_LCD \ 7- send DB5=1 DB4=0
11714 $2 20_US \ wait 40 us = LCD cycle
11715 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
11716 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
11717 LCD_Clear \ 10- "LCD_Clear"
11718 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
11719 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
11720 LCD_Clear \ 10- "LCD_Clear"
11721 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
11722 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
11724 ['] CR >BODY IS CR \
11725 ['] EMIT >BODY IS EMIT \
11726 ." RC5toLCD is running. Type STOP to quit"
11727 LIT RECURSE IS WARM \ replace WARM by this START routine
11728 ABORT \ and continue with the next word after WARM...
11729 ; \ ...until interpreter falls in sleep mode within ACCEPT.
11732 CODE STOP \ stops multitasking, must to be used before downloading app
11733 \ restore default action of primary DEFERred word SLEEP, assembly version
11734 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
11735 ADD #4,X \ X = BODY of SLEEP
11736 MOV X,-2(X) \ restore the default background
11739 \ restore default action of primary DEFERred word WARM, FORTH version
11740 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
11742 COLD \ because we want to reset CPU and interrupt vectors
11747 ; downloading RC5toLCD.4th is done
11748 RST_HERE ; this app is protected against <reset>
11756 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
11758 [DEFINED] ASM [IF] \ security test
11762 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
11764 CODE MAX \ n1 n2 -- n3 signed maximum
11765 CMP @PSP,TOS \ n2-n1
11766 S< ?GOTO FW1 \ n2<n1
11772 CODE MIN \ n1 n2 -- n3 signed minimum
11773 CMP @PSP,TOS \ n2-n1
11774 S< ?GOTO BW1 \ n2<n1
11782 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
11783 : U.R \ u n -- display u unsigned in n width (n >= 2)
11785 R> OVER - 0 MAX SPACES TYPE
11790 \ CODE 20_US \ n -- n * 20 us
11791 \ BEGIN \ 3 cycles loop + 6~
11792 \ \ MOV #5,W \ 3 MCLK = 1 MHz
11793 \ \ MOV #23,W \ 3 MCLK = 4 MHz
11794 \ \ MOV #51,W \ 3 MCLK = 8 MHz
11795 \ MOV #104,W \ 3 MCLK = 16 MHz
11796 \ \ MOV #158,W \ 3 MCLK = 24 MHz
11797 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
11802 \ MOV @PSP+,TOS \ 2
11807 CODE 20_US \ n -- n * 20 us
11808 BEGIN \ here we presume that LCD_TIM_IFG = 1...
11810 BIT #1,&LCD_TIM_CTL \ 3
11811 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
11812 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
11814 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
11820 CODE TOP_LCD \ LCD Sample
11821 \ \ if write : %xxxxWWWW --
11822 \ \ if read : -- %0000RRRR
11823 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
11824 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
11825 0= IF \ write LCD bits pattern
11826 AND.B #LCD_DB,TOS \
11827 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
11828 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
11831 THEN \ read LCD bits pattern
11834 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
11835 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
11836 AND.B #LCD_DB,TOS \
11841 CODE LCD_W \ byte -- write byte to LCD
11843 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
11844 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
11845 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
11846 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
11847 COLON \ high level word starts here
11848 TOP_LCD 2 20_US \ write high nibble first
11853 CODE LCD_WrC \ char -- Write Char
11854 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
11859 CODE LCD_WrF \ func -- Write Fonction
11860 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
11866 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
11871 $02 LCD_WrF 100 20_us
11875 [UNDEFINED] OR [IF]
11877 \ https://forth-standard.org/standard/core/OR
11878 \ C OR x1 x2 -- x3 logical OR
11887 : LCD_Entry_set $04 OR LCD_WrF ;
11889 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
11891 : LCD_DSP_Shift $10 OR LCD_WrF ;
11893 : LCD_Fn_Set $20 OR LCD_WrF ;
11895 : LCD_CGRAM_Set $40 OR LCD_WrF ;
11897 : LCD_Goto $80 OR LCD_WrF ;
11899 CODE LCD_R \ -- byte read byte from LCD
11900 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
11901 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
11902 COLON \ starts a FORTH word
11903 TOP_LCD 2 20_us \ -- %0000HHHH
11904 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
11905 HI2LO \ switch from FORTH to assembler
11906 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
11907 ADD.B @PSP+,TOS \ -- %HHHHLLLL
11908 MOV @RSP+,IP \ restore IP saved by COLON
11913 CODE LCD_RdS \ -- status Read Status
11914 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
11919 CODE LCD_RdC \ -- char Read Char
11920 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
11926 \ ******************************\
11927 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
11928 \ ******************************\
11929 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
11930 BIT.B #SW2,&SW2_IN \ test switch S2
11931 0= IF \ case of switch S2 pressed
11932 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
11934 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
11937 BIT.B #SW1,&SW1_IN \ test switch S1 input
11938 0= IF \ case of Switch S1 pressed
11939 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
11941 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
11945 BW1 \ from quit on truncated RC5 message
11946 BW2 \ from repeated RC5 command
11947 BW3 \ from end of RC5_INT
11948 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
11953 \ ******************************\
11954 ASM RC5_INT \ wake up on Px.RC5 change interrupt
11955 \ ******************************\
11956 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
11957 \ ******************************\
11958 \ \ in : SR(9)=old Toggle bit memory (ADD on)
11959 \ \ SMclock = 8|16|24 MHz
11960 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
11961 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
11962 \ \ SR(9)=new Toggle bit memory (ADD on)
11963 \ ******************************\
11964 \ RC5_FirstStartBitHalfCycle: \
11965 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
11966 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
11967 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
11968 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
11969 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
11970 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
11971 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
11972 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
11973 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
11974 MOV #1778,X \ RC5_Period * 1us
11975 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
11976 MOV #14,W \ count of loop
11978 \ ******************************\
11979 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
11980 \ ******************************\ |
11981 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
11982 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
11983 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
11984 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
11985 \ RC5_Compute_3/4_Period: \ |
11986 RRUM #1,X \ X=1/2 cycle |
11989 ADD X,Y \ Y=3/4 cycle
11990 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
11992 \ ******************************\
11993 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
11994 \ ******************************\
11995 BIT.B #RC5,&IR_IN \ C_flag = IR bit
11996 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
11997 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
11998 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
11999 SUB #1,W \ decrement count loop
12000 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
12001 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
12002 0<> WHILE \ ----> out of loop ----+
12003 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
12005 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
12006 CMP Y,X \ 1 | cycle time out of bound ?
12007 U>= IF \ 2 ^ | yes:
12008 BIC #$30,&RC5_TIM_CTL \ | | stop timer
12009 GOTO BW1 \ | | quit on truncated RC5 message
12011 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
12013 REPEAT \ ----> loop back --+ | with X = new RC5_period value
12014 \ ******************************\ |
12015 \ RC5_SampleEndOf: \ <---------------------+
12016 \ ******************************\
12017 BIC #$30,&RC5_TIM_CTL \ stop timer
12018 \ ******************************\
12019 \ RC5_ComputeNewRC5word \
12020 \ ******************************\
12021 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
12022 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
12023 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
12024 \ ******************************\
12025 \ RC5_ComputeC6bit \
12026 \ ******************************\
12027 BIT #BIT14,T \ test /C6 bit in T
12028 0= IF BIS #BIT6,X \ set C6 bit in X
12029 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
12030 \ ******************************\
12031 \ RC5_CommandByteIsDone \ -- BASE RC5_code
12032 \ ******************************\
12033 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
12034 \ ******************************\
12035 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
12036 XOR @RSP,T \ (new XOR old) Toggle bits
12037 BIT #UF10,T \ repeated RC5_command ?
12038 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
12039 XOR #UF10,0(RSP) \ 5 toggle bit memory
12040 \ ******************************\
12041 \ Display IR_RC5 code \ X = RC5 code
12042 \ ******************************\
12044 MOV &BASE,2(PSP) \ save current base
12045 MOV #$10,&BASE \ set hex base
12046 MOV TOS,0(PSP) \ save TOS
12048 LO2HI \ switch from assembler to FORTH
12049 ['] LCD_CLEAR IS CR \ redirects CR
12050 ['] LCD_WrC IS EMIT \ redirects EMIT
12051 CR ." $" 2 U.R \ print IR_RC5 code
12052 ['] CR >BODY IS CR \ restore CR
12053 ['] EMIT >BODY IS EMIT \ restore EMIT
12054 HI2LO \ switch from FORTH to assembler
12055 MOV TOS,&BASE \ restore current BASE
12057 \ ******************************\
12059 \ ******************************\
12063 \ ------------------------------\
12065 \ ------------------------------\
12066 \ ... \ insert here your background task
12069 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
12070 ADD #4,X \ 1 X = BODY of SLEEP
12073 \ ------------------------------\
12077 \ ------------------------------\
12078 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
12079 \ - - \CNTL Counter lentgh \ 00 = 16 bits
12080 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
12081 \ -- \ID input divider \ 10 = /4
12082 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
12083 \ - \TBCLR TimerB Clear
12086 \ -------------------------------\
12087 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
12088 \ -- \CM Capture Mode
12093 \ --- \OUTMOD \ 011 = set/reset
12099 \ -------------------------------\
12101 \ -------------------------------\
12103 \ ------------------------------\
12104 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
12105 \ ------------------------------\
12106 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
12107 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
12108 \ ------------------------------\
12109 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
12110 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
12111 \ ------------------------------\
12112 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
12113 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
12114 \ ------------------------------\
12115 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
12116 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
12117 \ ------------------------------\
12118 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
12119 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
12120 \ ------------------------------\
12121 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
12122 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
12123 \ ------------------------------\
12124 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
12125 \ ------------------------------\
12126 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
12127 \ ------------------------------\
12128 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
12129 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
12130 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
12131 \ ------------------------------\
12132 BIS.B #LCDVo,&LCDVo_DIR \
12133 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
12134 \ ------------------------------\
12135 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
12136 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
12137 \ ------------------------------\
12138 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
12139 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
12140 \ ******************************\
12142 \ ******************************\
12143 BIS.B #RC5,&IR_IE \ enable RC5_Int
12144 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
12145 MOV #RC5_INT,&IR_Vec \ init interrupt vector
12146 \ ******************************\
12147 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
12148 \ ******************************\
12149 \ %01 0001 0100 \ TAxCTL
12150 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
12151 \ -- \ ID divided by 1
12152 \ -- \ MC MODE = up to TAxCCRn
12153 \ - \ TACLR clear timer count
12156 \ ------------------------------\
12157 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
12158 \ ------------------------------\
12160 \ --- \ TAIDEX pre divisor
12161 \ ------------------------------\
12162 \ %0000 0000 0000 0101 \ TAxCCR0
12163 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
12164 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
12165 \ ------------------------------\
12166 \ %0000 0000 0001 0000 \ TAxCCTL0
12167 \ - \ CAP capture/compare mode = compare
12170 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
12171 \ ------------------------------\
12172 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
12173 \ ------------------------------\
12174 \ define LPM mode for ACCEPT \
12175 \ ------------------------------\
12176 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
12177 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
12178 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
12180 \ ------------------------------\
12181 \ redirects to background task \
12182 \ ------------------------------\
12184 MOV #BACKGROUND,2(X) \
12185 \ ------------------------------\
12187 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
12189 \ ------------------------------\
12191 \ ------------------------------\
12192 $03E8 20_US \ 1- wait 20 ms
12193 $03 TOP_LCD \ 2- send DB5=DB4=1
12194 $CD 20_US \ 3- wait 4,1 ms
12195 $03 TOP_LCD \ 4- send again DB5=DB4=1
12196 $5 20_US \ 5- wait 0,1 ms
12197 $03 TOP_LCD \ 6- send again again DB5=DB4=1
12198 $2 20_US \ wait 40 us = LCD cycle
12199 $02 TOP_LCD \ 7- send DB5=1 DB4=0
12200 $2 20_US \ wait 40 us = LCD cycle
12201 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
12202 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
12203 LCD_Clear \ 10- "LCD_Clear"
12204 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
12205 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
12206 LCD_Clear \ 10- "LCD_Clear"
12207 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
12208 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
12210 ['] CR >BODY IS CR \
12211 ['] EMIT >BODY IS EMIT \
12212 ." RC5toLCD is running. Type STOP to quit"
12213 LIT RECURSE IS WARM \ replace WARM by this START routine
12214 ABORT \ and continue with the next word after WARM...
12215 ; \ ...until interpreter falls in sleep mode within ACCEPT.
12218 CODE STOP \ stops multitasking, must to be used before downloading app
12219 \ restore default action of primary DEFERred word SLEEP, assembly version
12220 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
12221 ADD #4,X \ X = BODY of SLEEP
12222 MOV X,-2(X) \ restore the default background
12225 \ restore default action of primary DEFERred word WARM, FORTH version
12226 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
12228 COLD \ because we want to reset CPU and interrupt vectors
12233 ; downloading RC5toLCD.4th is done
12234 RST_HERE ; this app is protected against <reset>
12242 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
12244 [DEFINED] ASM [IF] \ security test
12248 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
12250 CODE MAX \ n1 n2 -- n3 signed maximum
12251 CMP @PSP,TOS \ n2-n1
12252 S< ?GOTO FW1 \ n2<n1
12258 CODE MIN \ n1 n2 -- n3 signed minimum
12259 CMP @PSP,TOS \ n2-n1
12260 S< ?GOTO BW1 \ n2<n1
12268 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
12269 : U.R \ u n -- display u unsigned in n width (n >= 2)
12271 R> OVER - 0 MAX SPACES TYPE
12276 \ CODE 20_US \ n -- n * 20 us
12277 \ BEGIN \ 3 cycles loop + 6~
12278 \ \ MOV #5,W \ 3 MCLK = 1 MHz
12279 \ \ MOV #23,W \ 3 MCLK = 4 MHz
12280 \ \ MOV #51,W \ 3 MCLK = 8 MHz
12281 \ MOV #104,W \ 3 MCLK = 16 MHz
12282 \ \ MOV #158,W \ 3 MCLK = 24 MHz
12283 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
12288 \ MOV @PSP+,TOS \ 2
12293 CODE 20_US \ n -- n * 20 us
12294 BEGIN \ here we presume that LCD_TIM_IFG = 1...
12296 BIT #1,&LCD_TIM_CTL \ 3
12297 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
12298 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
12300 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
12306 CODE TOP_LCD \ LCD Sample
12307 \ \ if write : %xxxxWWWW --
12308 \ \ if read : -- %0000RRRR
12309 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
12310 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
12311 0= IF \ write LCD bits pattern
12312 AND.B #LCD_DB,TOS \
12313 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
12314 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
12317 THEN \ read LCD bits pattern
12320 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
12321 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
12322 AND.B #LCD_DB,TOS \
12327 CODE LCD_W \ byte -- write byte to LCD
12329 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
12330 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
12331 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
12332 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
12333 COLON \ high level word starts here
12334 TOP_LCD 2 20_US \ write high nibble first
12339 CODE LCD_WrC \ char -- Write Char
12340 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
12345 CODE LCD_WrF \ func -- Write Fonction
12346 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
12352 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
12357 $02 LCD_WrF 100 20_us
12361 [UNDEFINED] OR [IF]
12363 \ https://forth-standard.org/standard/core/OR
12364 \ C OR x1 x2 -- x3 logical OR
12373 : LCD_Entry_set $04 OR LCD_WrF ;
12375 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
12377 : LCD_DSP_Shift $10 OR LCD_WrF ;
12379 : LCD_Fn_Set $20 OR LCD_WrF ;
12381 : LCD_CGRAM_Set $40 OR LCD_WrF ;
12383 : LCD_Goto $80 OR LCD_WrF ;
12385 CODE LCD_R \ -- byte read byte from LCD
12386 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
12387 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
12388 COLON \ starts a FORTH word
12389 TOP_LCD 2 20_us \ -- %0000HHHH
12390 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
12391 HI2LO \ switch from FORTH to assembler
12392 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
12393 ADD.B @PSP+,TOS \ -- %HHHHLLLL
12394 MOV @RSP+,IP \ restore IP saved by COLON
12399 CODE LCD_RdS \ -- status Read Status
12400 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
12405 CODE LCD_RdC \ -- char Read Char
12406 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
12412 \ ******************************\
12413 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
12414 \ ******************************\
12415 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
12416 BIT.B #SW2,&SW2_IN \ test switch S2
12417 0= IF \ case of switch S2 pressed
12418 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
12420 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
12423 BIT.B #SW1,&SW1_IN \ test switch S1 input
12424 0= IF \ case of Switch S1 pressed
12425 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
12427 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
12431 BW1 \ from quit on truncated RC5 message
12432 BW2 \ from repeated RC5 command
12433 BW3 \ from end of RC5_INT
12434 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
12439 \ ******************************\
12440 ASM RC5_INT \ wake up on Px.RC5 change interrupt
12441 \ ******************************\
12442 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
12443 \ ******************************\
12444 \ \ in : SR(9)=old Toggle bit memory (ADD on)
12445 \ \ SMclock = 8|16|24 MHz
12446 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
12447 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
12448 \ \ SR(9)=new Toggle bit memory (ADD on)
12449 \ ******************************\
12450 \ RC5_FirstStartBitHalfCycle: \
12451 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
12452 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
12453 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
12454 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
12455 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
12456 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
12457 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
12458 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
12459 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
12460 MOV #1778,X \ RC5_Period * 1us
12461 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
12462 MOV #14,W \ count of loop
12464 \ ******************************\
12465 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
12466 \ ******************************\ |
12467 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
12468 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
12469 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
12470 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
12471 \ RC5_Compute_3/4_Period: \ |
12472 RRUM #1,X \ X=1/2 cycle |
12475 ADD X,Y \ Y=3/4 cycle
12476 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
12478 \ ******************************\
12479 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
12480 \ ******************************\
12481 BIT.B #RC5,&IR_IN \ C_flag = IR bit
12482 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
12483 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
12484 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
12485 SUB #1,W \ decrement count loop
12486 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
12487 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
12488 0<> WHILE \ ----> out of loop ----+
12489 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
12491 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
12492 CMP Y,X \ 1 | cycle time out of bound ?
12493 U>= IF \ 2 ^ | yes:
12494 BIC #$30,&RC5_TIM_CTL \ | | stop timer
12495 GOTO BW1 \ | | quit on truncated RC5 message
12497 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
12499 REPEAT \ ----> loop back --+ | with X = new RC5_period value
12500 \ ******************************\ |
12501 \ RC5_SampleEndOf: \ <---------------------+
12502 \ ******************************\
12503 BIC #$30,&RC5_TIM_CTL \ stop timer
12504 \ ******************************\
12505 \ RC5_ComputeNewRC5word \
12506 \ ******************************\
12507 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
12508 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
12509 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
12510 \ ******************************\
12511 \ RC5_ComputeC6bit \
12512 \ ******************************\
12513 BIT #BIT14,T \ test /C6 bit in T
12514 0= IF BIS #BIT6,X \ set C6 bit in X
12515 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
12516 \ ******************************\
12517 \ RC5_CommandByteIsDone \ -- BASE RC5_code
12518 \ ******************************\
12519 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
12520 \ ******************************\
12521 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
12522 XOR @RSP,T \ (new XOR old) Toggle bits
12523 BIT #UF10,T \ repeated RC5_command ?
12524 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
12525 XOR #UF10,0(RSP) \ 5 toggle bit memory
12526 \ ******************************\
12527 \ Display IR_RC5 code \ X = RC5 code
12528 \ ******************************\
12530 MOV &BASE,2(PSP) \ save current base
12531 MOV #$10,&BASE \ set hex base
12532 MOV TOS,0(PSP) \ save TOS
12534 LO2HI \ switch from assembler to FORTH
12535 ['] LCD_CLEAR IS CR \ redirects CR
12536 ['] LCD_WrC IS EMIT \ redirects EMIT
12537 CR ." $" 2 U.R \ print IR_RC5 code
12538 ['] CR >BODY IS CR \ restore CR
12539 ['] EMIT >BODY IS EMIT \ restore EMIT
12540 HI2LO \ switch from FORTH to assembler
12541 MOV TOS,&BASE \ restore current BASE
12543 \ ******************************\
12545 \ ******************************\
12549 \ ------------------------------\
12551 \ ------------------------------\
12552 \ ... \ insert here your background task
12555 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
12556 ADD #4,X \ 1 X = BODY of SLEEP
12559 \ ------------------------------\
12563 \ ------------------------------\
12564 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
12565 \ - - \CNTL Counter lentgh \ 00 = 16 bits
12566 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
12567 \ -- \ID input divider \ 10 = /4
12568 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
12569 \ - \TBCLR TimerB Clear
12572 \ -------------------------------\
12573 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
12574 \ -- \CM Capture Mode
12579 \ --- \OUTMOD \ 011 = set/reset
12585 \ -------------------------------\
12587 \ -------------------------------\
12589 \ ------------------------------\
12590 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
12591 \ ------------------------------\
12592 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
12593 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
12594 \ ------------------------------\
12595 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
12596 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
12597 \ ------------------------------\
12598 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
12599 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
12600 \ ------------------------------\
12601 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
12602 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
12603 \ ------------------------------\
12604 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
12605 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
12606 \ ------------------------------\
12607 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
12608 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
12609 \ ------------------------------\
12610 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
12611 \ ------------------------------\
12612 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
12613 \ ------------------------------\
12614 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
12615 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
12616 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
12617 \ ------------------------------\
12618 BIS.B #LCDVo,&LCDVo_DIR \
12619 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
12620 \ ------------------------------\
12621 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
12622 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
12623 \ ------------------------------\
12624 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
12625 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
12626 \ ******************************\
12628 \ ******************************\
12629 BIS.B #RC5,&IR_IE \ enable RC5_Int
12630 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
12631 MOV #RC5_INT,&IR_Vec \ init interrupt vector
12632 \ ******************************\
12633 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
12634 \ ******************************\
12635 \ %01 0001 0100 \ TAxCTL
12636 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
12637 \ -- \ ID divided by 1
12638 \ -- \ MC MODE = up to TAxCCRn
12639 \ - \ TACLR clear timer count
12642 \ ------------------------------\
12643 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
12644 \ ------------------------------\
12646 \ --- \ TAIDEX pre divisor
12647 \ ------------------------------\
12648 \ %0000 0000 0000 0101 \ TAxCCR0
12649 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
12650 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
12651 \ ------------------------------\
12652 \ %0000 0000 0001 0000 \ TAxCCTL0
12653 \ - \ CAP capture/compare mode = compare
12656 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
12657 \ ------------------------------\
12658 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
12659 \ ------------------------------\
12660 \ define LPM mode for ACCEPT \
12661 \ ------------------------------\
12662 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
12663 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
12664 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
12666 \ ------------------------------\
12667 \ redirects to background task \
12668 \ ------------------------------\
12670 MOV #BACKGROUND,2(X) \
12671 \ ------------------------------\
12673 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
12675 \ ------------------------------\
12677 \ ------------------------------\
12678 $03E8 20_US \ 1- wait 20 ms
12679 $03 TOP_LCD \ 2- send DB5=DB4=1
12680 $CD 20_US \ 3- wait 4,1 ms
12681 $03 TOP_LCD \ 4- send again DB5=DB4=1
12682 $5 20_US \ 5- wait 0,1 ms
12683 $03 TOP_LCD \ 6- send again again DB5=DB4=1
12684 $2 20_US \ wait 40 us = LCD cycle
12685 $02 TOP_LCD \ 7- send DB5=1 DB4=0
12686 $2 20_US \ wait 40 us = LCD cycle
12687 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
12688 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
12689 LCD_Clear \ 10- "LCD_Clear"
12690 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
12691 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
12692 LCD_Clear \ 10- "LCD_Clear"
12693 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
12694 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
12696 ['] CR >BODY IS CR \
12697 ['] EMIT >BODY IS EMIT \
12698 ." RC5toLCD is running. Type STOP to quit"
12699 LIT RECURSE IS WARM \ replace WARM by this START routine
12700 ABORT \ and continue with the next word after WARM...
12701 ; \ ...until interpreter falls in sleep mode within ACCEPT.
12704 CODE STOP \ stops multitasking, must to be used before downloading app
12705 \ restore default action of primary DEFERred word SLEEP, assembly version
12706 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
12707 ADD #4,X \ X = BODY of SLEEP
12708 MOV X,-2(X) \ restore the default background
12711 \ restore default action of primary DEFERred word WARM, FORTH version
12712 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
12714 COLD \ because we want to reset CPU and interrupt vectors
12719 ; downloading RC5toLCD.4th is done
12720 RST_HERE ; this app is protected against <reset>
12728 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
12730 [DEFINED] ASM [IF] \ security test
12734 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
12736 CODE MAX \ n1 n2 -- n3 signed maximum
12737 CMP @PSP,TOS \ n2-n1
12738 S< ?GOTO FW1 \ n2<n1
12744 CODE MIN \ n1 n2 -- n3 signed minimum
12745 CMP @PSP,TOS \ n2-n1
12746 S< ?GOTO BW1 \ n2<n1
12754 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
12755 : U.R \ u n -- display u unsigned in n width (n >= 2)
12757 R> OVER - 0 MAX SPACES TYPE
12762 \ CODE 20_US \ n -- n * 20 us
12763 \ BEGIN \ 3 cycles loop + 6~
12764 \ \ MOV #5,W \ 3 MCLK = 1 MHz
12765 \ \ MOV #23,W \ 3 MCLK = 4 MHz
12766 \ \ MOV #51,W \ 3 MCLK = 8 MHz
12767 \ MOV #104,W \ 3 MCLK = 16 MHz
12768 \ \ MOV #158,W \ 3 MCLK = 24 MHz
12769 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
12774 \ MOV @PSP+,TOS \ 2
12779 CODE 20_US \ n -- n * 20 us
12780 BEGIN \ here we presume that LCD_TIM_IFG = 1...
12782 BIT #1,&LCD_TIM_CTL \ 3
12783 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
12784 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
12786 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
12792 CODE TOP_LCD \ LCD Sample
12793 \ \ if write : %xxxxWWWW --
12794 \ \ if read : -- %0000RRRR
12795 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
12796 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
12797 0= IF \ write LCD bits pattern
12798 AND.B #LCD_DB,TOS \
12799 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
12800 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
12803 THEN \ read LCD bits pattern
12806 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
12807 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
12808 AND.B #LCD_DB,TOS \
12813 CODE LCD_W \ byte -- write byte to LCD
12815 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
12816 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
12817 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
12818 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
12819 COLON \ high level word starts here
12820 TOP_LCD 2 20_US \ write high nibble first
12825 CODE LCD_WrC \ char -- Write Char
12826 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
12831 CODE LCD_WrF \ func -- Write Fonction
12832 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
12838 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
12843 $02 LCD_WrF 100 20_us
12847 [UNDEFINED] OR [IF]
12849 \ https://forth-standard.org/standard/core/OR
12850 \ C OR x1 x2 -- x3 logical OR
12859 : LCD_Entry_set $04 OR LCD_WrF ;
12861 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
12863 : LCD_DSP_Shift $10 OR LCD_WrF ;
12865 : LCD_Fn_Set $20 OR LCD_WrF ;
12867 : LCD_CGRAM_Set $40 OR LCD_WrF ;
12869 : LCD_Goto $80 OR LCD_WrF ;
12871 CODE LCD_R \ -- byte read byte from LCD
12872 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
12873 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
12874 COLON \ starts a FORTH word
12875 TOP_LCD 2 20_us \ -- %0000HHHH
12876 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
12877 HI2LO \ switch from FORTH to assembler
12878 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
12879 ADD.B @PSP+,TOS \ -- %HHHHLLLL
12880 MOV @RSP+,IP \ restore IP saved by COLON
12885 CODE LCD_RdS \ -- status Read Status
12886 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
12891 CODE LCD_RdC \ -- char Read Char
12892 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
12898 \ ******************************\
12899 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
12900 \ ******************************\
12901 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
12902 BIT.B #SW2,&SW2_IN \ test switch S2
12903 0= IF \ case of switch S2 pressed
12904 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
12906 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
12909 BIT.B #SW1,&SW1_IN \ test switch S1 input
12910 0= IF \ case of Switch S1 pressed
12911 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
12913 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
12917 BW1 \ from quit on truncated RC5 message
12918 BW2 \ from repeated RC5 command
12919 BW3 \ from end of RC5_INT
12920 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
12925 \ ******************************\
12926 ASM RC5_INT \ wake up on Px.RC5 change interrupt
12927 \ ******************************\
12928 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
12929 \ ******************************\
12930 \ \ in : SR(9)=old Toggle bit memory (ADD on)
12931 \ \ SMclock = 8|16|24 MHz
12932 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
12933 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
12934 \ \ SR(9)=new Toggle bit memory (ADD on)
12935 \ ******************************\
12936 \ RC5_FirstStartBitHalfCycle: \
12937 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
12938 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
12939 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
12940 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
12941 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
12942 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
12943 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
12944 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
12945 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
12946 MOV #1778,X \ RC5_Period * 1us
12947 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
12948 MOV #14,W \ count of loop
12950 \ ******************************\
12951 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
12952 \ ******************************\ |
12953 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
12954 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
12955 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
12956 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
12957 \ RC5_Compute_3/4_Period: \ |
12958 RRUM #1,X \ X=1/2 cycle |
12961 ADD X,Y \ Y=3/4 cycle
12962 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
12964 \ ******************************\
12965 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
12966 \ ******************************\
12967 BIT.B #RC5,&IR_IN \ C_flag = IR bit
12968 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
12969 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
12970 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
12971 SUB #1,W \ decrement count loop
12972 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
12973 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
12974 0<> WHILE \ ----> out of loop ----+
12975 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
12977 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
12978 CMP Y,X \ 1 | cycle time out of bound ?
12979 U>= IF \ 2 ^ | yes:
12980 BIC #$30,&RC5_TIM_CTL \ | | stop timer
12981 GOTO BW1 \ | | quit on truncated RC5 message
12983 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
12985 REPEAT \ ----> loop back --+ | with X = new RC5_period value
12986 \ ******************************\ |
12987 \ RC5_SampleEndOf: \ <---------------------+
12988 \ ******************************\
12989 BIC #$30,&RC5_TIM_CTL \ stop timer
12990 \ ******************************\
12991 \ RC5_ComputeNewRC5word \
12992 \ ******************************\
12993 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
12994 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
12995 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
12996 \ ******************************\
12997 \ RC5_ComputeC6bit \
12998 \ ******************************\
12999 BIT #BIT14,T \ test /C6 bit in T
13000 0= IF BIS #BIT6,X \ set C6 bit in X
13001 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
13002 \ ******************************\
13003 \ RC5_CommandByteIsDone \ -- BASE RC5_code
13004 \ ******************************\
13005 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
13006 \ ******************************\
13007 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
13008 XOR @RSP,T \ (new XOR old) Toggle bits
13009 BIT #UF10,T \ repeated RC5_command ?
13010 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
13011 XOR #UF10,0(RSP) \ 5 toggle bit memory
13012 \ ******************************\
13013 \ Display IR_RC5 code \ X = RC5 code
13014 \ ******************************\
13016 MOV &BASE,2(PSP) \ save current base
13017 MOV #$10,&BASE \ set hex base
13018 MOV TOS,0(PSP) \ save TOS
13020 LO2HI \ switch from assembler to FORTH
13021 ['] LCD_CLEAR IS CR \ redirects CR
13022 ['] LCD_WrC IS EMIT \ redirects EMIT
13023 CR ." $" 2 U.R \ print IR_RC5 code
13024 ['] CR >BODY IS CR \ restore CR
13025 ['] EMIT >BODY IS EMIT \ restore EMIT
13026 HI2LO \ switch from FORTH to assembler
13027 MOV TOS,&BASE \ restore current BASE
13029 \ ******************************\
13031 \ ******************************\
13035 \ ------------------------------\
13037 \ ------------------------------\
13038 \ ... \ insert here your background task
13041 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
13042 ADD #4,X \ 1 X = BODY of SLEEP
13045 \ ------------------------------\
13049 \ ------------------------------\
13050 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
13051 \ - - \CNTL Counter lentgh \ 00 = 16 bits
13052 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
13053 \ -- \ID input divider \ 10 = /4
13054 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
13055 \ - \TBCLR TimerB Clear
13058 \ -------------------------------\
13059 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
13060 \ -- \CM Capture Mode
13065 \ --- \OUTMOD \ 011 = set/reset
13071 \ -------------------------------\
13073 \ -------------------------------\
13075 \ ------------------------------\
13076 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
13077 \ ------------------------------\
13078 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
13079 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
13080 \ ------------------------------\
13081 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
13082 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
13083 \ ------------------------------\
13084 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
13085 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
13086 \ ------------------------------\
13087 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
13088 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
13089 \ ------------------------------\
13090 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
13091 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
13092 \ ------------------------------\
13093 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
13094 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
13095 \ ------------------------------\
13096 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
13097 \ ------------------------------\
13098 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
13099 \ ------------------------------\
13100 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
13101 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
13102 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
13103 \ ------------------------------\
13104 BIS.B #LCDVo,&LCDVo_DIR \
13105 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
13106 \ ------------------------------\
13107 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
13108 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
13109 \ ------------------------------\
13110 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
13111 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
13112 \ ******************************\
13114 \ ******************************\
13115 BIS.B #RC5,&IR_IE \ enable RC5_Int
13116 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
13117 MOV #RC5_INT,&IR_Vec \ init interrupt vector
13118 \ ******************************\
13119 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
13120 \ ******************************\
13121 \ %01 0001 0100 \ TAxCTL
13122 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
13123 \ -- \ ID divided by 1
13124 \ -- \ MC MODE = up to TAxCCRn
13125 \ - \ TACLR clear timer count
13128 \ ------------------------------\
13129 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
13130 \ ------------------------------\
13132 \ --- \ TAIDEX pre divisor
13133 \ ------------------------------\
13134 \ %0000 0000 0000 0101 \ TAxCCR0
13135 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
13136 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
13137 \ ------------------------------\
13138 \ %0000 0000 0001 0000 \ TAxCCTL0
13139 \ - \ CAP capture/compare mode = compare
13142 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
13143 \ ------------------------------\
13144 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
13145 \ ------------------------------\
13146 \ define LPM mode for ACCEPT \
13147 \ ------------------------------\
13148 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
13149 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
13150 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
13152 \ ------------------------------\
13153 \ redirects to background task \
13154 \ ------------------------------\
13156 MOV #BACKGROUND,2(X) \
13157 \ ------------------------------\
13159 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
13161 \ ------------------------------\
13163 \ ------------------------------\
13164 $03E8 20_US \ 1- wait 20 ms
13165 $03 TOP_LCD \ 2- send DB5=DB4=1
13166 $CD 20_US \ 3- wait 4,1 ms
13167 $03 TOP_LCD \ 4- send again DB5=DB4=1
13168 $5 20_US \ 5- wait 0,1 ms
13169 $03 TOP_LCD \ 6- send again again DB5=DB4=1
13170 $2 20_US \ wait 40 us = LCD cycle
13171 $02 TOP_LCD \ 7- send DB5=1 DB4=0
13172 $2 20_US \ wait 40 us = LCD cycle
13173 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
13174 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
13175 LCD_Clear \ 10- "LCD_Clear"
13176 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
13177 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
13178 LCD_Clear \ 10- "LCD_Clear"
13179 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
13180 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
13182 ['] CR >BODY IS CR \
13183 ['] EMIT >BODY IS EMIT \
13184 ." RC5toLCD is running. Type STOP to quit"
13185 LIT RECURSE IS WARM \ replace WARM by this START routine
13186 ABORT \ and continue with the next word after WARM...
13187 ; \ ...until interpreter falls in sleep mode within ACCEPT.
13190 CODE STOP \ stops multitasking, must to be used before downloading app
13191 \ restore default action of primary DEFERred word SLEEP, assembly version
13192 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
13193 ADD #4,X \ X = BODY of SLEEP
13194 MOV X,-2(X) \ restore the default background
13197 \ restore default action of primary DEFERred word WARM, FORTH version
13198 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
13200 COLD \ because we want to reset CPU and interrupt vectors
13205 ; downloading RC5toLCD.4th is done
13206 RST_HERE ; this app is protected against <reset>
13214 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
13216 [DEFINED] ASM [IF] \ security test
13220 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
13222 CODE MAX \ n1 n2 -- n3 signed maximum
13223 CMP @PSP,TOS \ n2-n1
13224 S< ?GOTO FW1 \ n2<n1
13230 CODE MIN \ n1 n2 -- n3 signed minimum
13231 CMP @PSP,TOS \ n2-n1
13232 S< ?GOTO BW1 \ n2<n1
13240 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
13241 : U.R \ u n -- display u unsigned in n width (n >= 2)
13243 R> OVER - 0 MAX SPACES TYPE
13248 \ CODE 20_US \ n -- n * 20 us
13249 \ BEGIN \ 3 cycles loop + 6~
13250 \ \ MOV #5,W \ 3 MCLK = 1 MHz
13251 \ \ MOV #23,W \ 3 MCLK = 4 MHz
13252 \ \ MOV #51,W \ 3 MCLK = 8 MHz
13253 \ MOV #104,W \ 3 MCLK = 16 MHz
13254 \ \ MOV #158,W \ 3 MCLK = 24 MHz
13255 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
13260 \ MOV @PSP+,TOS \ 2
13265 CODE 20_US \ n -- n * 20 us
13266 BEGIN \ here we presume that LCD_TIM_IFG = 1...
13268 BIT #1,&LCD_TIM_CTL \ 3
13269 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
13270 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
13272 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
13278 CODE TOP_LCD \ LCD Sample
13279 \ \ if write : %xxxxWWWW --
13280 \ \ if read : -- %0000RRRR
13281 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
13282 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
13283 0= IF \ write LCD bits pattern
13284 AND.B #LCD_DB,TOS \
13285 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
13286 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
13289 THEN \ read LCD bits pattern
13292 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
13293 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
13294 AND.B #LCD_DB,TOS \
13299 CODE LCD_W \ byte -- write byte to LCD
13301 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
13302 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
13303 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
13304 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
13305 COLON \ high level word starts here
13306 TOP_LCD 2 20_US \ write high nibble first
13311 CODE LCD_WrC \ char -- Write Char
13312 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
13317 CODE LCD_WrF \ func -- Write Fonction
13318 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
13324 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
13329 $02 LCD_WrF 100 20_us
13333 [UNDEFINED] OR [IF]
13335 \ https://forth-standard.org/standard/core/OR
13336 \ C OR x1 x2 -- x3 logical OR
13345 : LCD_Entry_set $04 OR LCD_WrF ;
13347 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
13349 : LCD_DSP_Shift $10 OR LCD_WrF ;
13351 : LCD_Fn_Set $20 OR LCD_WrF ;
13353 : LCD_CGRAM_Set $40 OR LCD_WrF ;
13355 : LCD_Goto $80 OR LCD_WrF ;
13357 CODE LCD_R \ -- byte read byte from LCD
13358 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
13359 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
13360 COLON \ starts a FORTH word
13361 TOP_LCD 2 20_us \ -- %0000HHHH
13362 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
13363 HI2LO \ switch from FORTH to assembler
13364 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
13365 ADD.B @PSP+,TOS \ -- %HHHHLLLL
13366 MOV @RSP+,IP \ restore IP saved by COLON
13371 CODE LCD_RdS \ -- status Read Status
13372 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
13377 CODE LCD_RdC \ -- char Read Char
13378 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
13384 \ ******************************\
13385 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
13386 \ ******************************\
13387 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
13388 BIT.B #SW2,&SW2_IN \ test switch S2
13389 0= IF \ case of switch S2 pressed
13390 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
13392 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
13395 BIT.B #SW1,&SW1_IN \ test switch S1 input
13396 0= IF \ case of Switch S1 pressed
13397 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
13399 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
13403 BW1 \ from quit on truncated RC5 message
13404 BW2 \ from repeated RC5 command
13405 BW3 \ from end of RC5_INT
13406 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
13411 \ ******************************\
13412 ASM RC5_INT \ wake up on Px.RC5 change interrupt
13413 \ ******************************\
13414 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
13415 \ ******************************\
13416 \ \ in : SR(9)=old Toggle bit memory (ADD on)
13417 \ \ SMclock = 8|16|24 MHz
13418 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
13419 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
13420 \ \ SR(9)=new Toggle bit memory (ADD on)
13421 \ ******************************\
13422 \ RC5_FirstStartBitHalfCycle: \
13423 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
13424 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
13425 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
13426 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
13427 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
13428 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
13429 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
13430 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
13431 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
13432 MOV #1778,X \ RC5_Period * 1us
13433 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
13434 MOV #14,W \ count of loop
13436 \ ******************************\
13437 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
13438 \ ******************************\ |
13439 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
13440 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
13441 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
13442 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
13443 \ RC5_Compute_3/4_Period: \ |
13444 RRUM #1,X \ X=1/2 cycle |
13447 ADD X,Y \ Y=3/4 cycle
13448 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
13450 \ ******************************\
13451 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
13452 \ ******************************\
13453 BIT.B #RC5,&IR_IN \ C_flag = IR bit
13454 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
13455 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
13456 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
13457 SUB #1,W \ decrement count loop
13458 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
13459 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
13460 0<> WHILE \ ----> out of loop ----+
13461 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
13463 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
13464 CMP Y,X \ 1 | cycle time out of bound ?
13465 U>= IF \ 2 ^ | yes:
13466 BIC #$30,&RC5_TIM_CTL \ | | stop timer
13467 GOTO BW1 \ | | quit on truncated RC5 message
13469 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
13471 REPEAT \ ----> loop back --+ | with X = new RC5_period value
13472 \ ******************************\ |
13473 \ RC5_SampleEndOf: \ <---------------------+
13474 \ ******************************\
13475 BIC #$30,&RC5_TIM_CTL \ stop timer
13476 \ ******************************\
13477 \ RC5_ComputeNewRC5word \
13478 \ ******************************\
13479 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
13480 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
13481 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
13482 \ ******************************\
13483 \ RC5_ComputeC6bit \
13484 \ ******************************\
13485 BIT #BIT14,T \ test /C6 bit in T
13486 0= IF BIS #BIT6,X \ set C6 bit in X
13487 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
13488 \ ******************************\
13489 \ RC5_CommandByteIsDone \ -- BASE RC5_code
13490 \ ******************************\
13491 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
13492 \ ******************************\
13493 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
13494 XOR @RSP,T \ (new XOR old) Toggle bits
13495 BIT #UF10,T \ repeated RC5_command ?
13496 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
13497 XOR #UF10,0(RSP) \ 5 toggle bit memory
13498 \ ******************************\
13499 \ Display IR_RC5 code \ X = RC5 code
13500 \ ******************************\
13502 MOV &BASE,2(PSP) \ save current base
13503 MOV #$10,&BASE \ set hex base
13504 MOV TOS,0(PSP) \ save TOS
13506 LO2HI \ switch from assembler to FORTH
13507 ['] LCD_CLEAR IS CR \ redirects CR
13508 ['] LCD_WrC IS EMIT \ redirects EMIT
13509 CR ." $" 2 U.R \ print IR_RC5 code
13510 ['] CR >BODY IS CR \ restore CR
13511 ['] EMIT >BODY IS EMIT \ restore EMIT
13512 HI2LO \ switch from FORTH to assembler
13513 MOV TOS,&BASE \ restore current BASE
13515 \ ******************************\
13517 \ ******************************\
13521 \ ------------------------------\
13523 \ ------------------------------\
13524 \ ... \ insert here your background task
13527 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
13528 ADD #4,X \ 1 X = BODY of SLEEP
13531 \ ------------------------------\
13535 \ ------------------------------\
13536 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
13537 \ - - \CNTL Counter lentgh \ 00 = 16 bits
13538 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
13539 \ -- \ID input divider \ 10 = /4
13540 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
13541 \ - \TBCLR TimerB Clear
13544 \ -------------------------------\
13545 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
13546 \ -- \CM Capture Mode
13551 \ --- \OUTMOD \ 011 = set/reset
13557 \ -------------------------------\
13559 \ -------------------------------\
13561 \ ------------------------------\
13562 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
13563 \ ------------------------------\
13564 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
13565 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
13566 \ ------------------------------\
13567 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
13568 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
13569 \ ------------------------------\
13570 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
13571 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
13572 \ ------------------------------\
13573 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
13574 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
13575 \ ------------------------------\
13576 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
13577 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
13578 \ ------------------------------\
13579 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
13580 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
13581 \ ------------------------------\
13582 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
13583 \ ------------------------------\
13584 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
13585 \ ------------------------------\
13586 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
13587 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
13588 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
13589 \ ------------------------------\
13590 BIS.B #LCDVo,&LCDVo_DIR \
13591 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
13592 \ ------------------------------\
13593 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
13594 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
13595 \ ------------------------------\
13596 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
13597 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
13598 \ ******************************\
13600 \ ******************************\
13601 BIS.B #RC5,&IR_IE \ enable RC5_Int
13602 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
13603 MOV #RC5_INT,&IR_Vec \ init interrupt vector
13604 \ ******************************\
13605 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
13606 \ ******************************\
13607 \ %01 0001 0100 \ TAxCTL
13608 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
13609 \ -- \ ID divided by 1
13610 \ -- \ MC MODE = up to TAxCCRn
13611 \ - \ TACLR clear timer count
13614 \ ------------------------------\
13615 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
13616 \ ------------------------------\
13618 \ --- \ TAIDEX pre divisor
13619 \ ------------------------------\
13620 \ %0000 0000 0000 0101 \ TAxCCR0
13621 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
13622 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
13623 \ ------------------------------\
13624 \ %0000 0000 0001 0000 \ TAxCCTL0
13625 \ - \ CAP capture/compare mode = compare
13628 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
13629 \ ------------------------------\
13630 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
13631 \ ------------------------------\
13632 \ define LPM mode for ACCEPT \
13633 \ ------------------------------\
13634 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
13635 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
13636 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
13638 \ ------------------------------\
13639 \ redirects to background task \
13640 \ ------------------------------\
13642 MOV #BACKGROUND,2(X) \
13643 \ ------------------------------\
13645 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
13647 \ ------------------------------\
13649 \ ------------------------------\
13650 $03E8 20_US \ 1- wait 20 ms
13651 $03 TOP_LCD \ 2- send DB5=DB4=1
13652 $CD 20_US \ 3- wait 4,1 ms
13653 $03 TOP_LCD \ 4- send again DB5=DB4=1
13654 $5 20_US \ 5- wait 0,1 ms
13655 $03 TOP_LCD \ 6- send again again DB5=DB4=1
13656 $2 20_US \ wait 40 us = LCD cycle
13657 $02 TOP_LCD \ 7- send DB5=1 DB4=0
13658 $2 20_US \ wait 40 us = LCD cycle
13659 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
13660 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
13661 LCD_Clear \ 10- "LCD_Clear"
13662 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
13663 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
13664 LCD_Clear \ 10- "LCD_Clear"
13665 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
13666 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
13668 ['] CR >BODY IS CR \
13669 ['] EMIT >BODY IS EMIT \
13670 ." RC5toLCD is running. Type STOP to quit"
13671 LIT RECURSE IS WARM \ replace WARM by this START routine
13672 ABORT \ and continue with the next word after WARM...
13673 ; \ ...until interpreter falls in sleep mode within ACCEPT.
13676 CODE STOP \ stops multitasking, must to be used before downloading app
13677 \ restore default action of primary DEFERred word SLEEP, assembly version
13678 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
13679 ADD #4,X \ X = BODY of SLEEP
13680 MOV X,-2(X) \ restore the default background
13683 \ restore default action of primary DEFERred word WARM, FORTH version
13684 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
13686 COLD \ because we want to reset CPU and interrupt vectors
13691 ; downloading RC5toLCD.4th is done
13692 RST_HERE ; this app is protected against <reset>
13700 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
13702 [DEFINED] ASM [IF] \ security test
13706 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
13708 CODE MAX \ n1 n2 -- n3 signed maximum
13709 CMP @PSP,TOS \ n2-n1
13710 S< ?GOTO FW1 \ n2<n1
13716 CODE MIN \ n1 n2 -- n3 signed minimum
13717 CMP @PSP,TOS \ n2-n1
13718 S< ?GOTO BW1 \ n2<n1
13726 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
13727 : U.R \ u n -- display u unsigned in n width (n >= 2)
13729 R> OVER - 0 MAX SPACES TYPE
13734 \ CODE 20_US \ n -- n * 20 us
13735 \ BEGIN \ 3 cycles loop + 6~
13736 \ \ MOV #5,W \ 3 MCLK = 1 MHz
13737 \ \ MOV #23,W \ 3 MCLK = 4 MHz
13738 \ \ MOV #51,W \ 3 MCLK = 8 MHz
13739 \ MOV #104,W \ 3 MCLK = 16 MHz
13740 \ \ MOV #158,W \ 3 MCLK = 24 MHz
13741 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
13746 \ MOV @PSP+,TOS \ 2
13751 CODE 20_US \ n -- n * 20 us
13752 BEGIN \ here we presume that LCD_TIM_IFG = 1...
13754 BIT #1,&LCD_TIM_CTL \ 3
13755 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
13756 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
13758 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
13764 CODE TOP_LCD \ LCD Sample
13765 \ \ if write : %xxxxWWWW --
13766 \ \ if read : -- %0000RRRR
13767 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
13768 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
13769 0= IF \ write LCD bits pattern
13770 AND.B #LCD_DB,TOS \
13771 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
13772 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
13775 THEN \ read LCD bits pattern
13778 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
13779 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
13780 AND.B #LCD_DB,TOS \
13785 CODE LCD_W \ byte -- write byte to LCD
13787 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
13788 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
13789 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
13790 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
13791 COLON \ high level word starts here
13792 TOP_LCD 2 20_US \ write high nibble first
13797 CODE LCD_WrC \ char -- Write Char
13798 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
13803 CODE LCD_WrF \ func -- Write Fonction
13804 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
13810 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
13815 $02 LCD_WrF 100 20_us
13819 [UNDEFINED] OR [IF]
13821 \ https://forth-standard.org/standard/core/OR
13822 \ C OR x1 x2 -- x3 logical OR
13831 : LCD_Entry_set $04 OR LCD_WrF ;
13833 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
13835 : LCD_DSP_Shift $10 OR LCD_WrF ;
13837 : LCD_Fn_Set $20 OR LCD_WrF ;
13839 : LCD_CGRAM_Set $40 OR LCD_WrF ;
13841 : LCD_Goto $80 OR LCD_WrF ;
13843 CODE LCD_R \ -- byte read byte from LCD
13844 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
13845 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
13846 COLON \ starts a FORTH word
13847 TOP_LCD 2 20_us \ -- %0000HHHH
13848 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
13849 HI2LO \ switch from FORTH to assembler
13850 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
13851 ADD.B @PSP+,TOS \ -- %HHHHLLLL
13852 MOV @RSP+,IP \ restore IP saved by COLON
13857 CODE LCD_RdS \ -- status Read Status
13858 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
13863 CODE LCD_RdC \ -- char Read Char
13864 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
13870 \ ******************************\
13871 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
13872 \ ******************************\
13873 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
13874 BIT.B #SW2,&SW2_IN \ test switch S2
13875 0= IF \ case of switch S2 pressed
13876 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
13878 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
13881 BIT.B #SW1,&SW1_IN \ test switch S1 input
13882 0= IF \ case of Switch S1 pressed
13883 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
13885 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
13889 BW1 \ from quit on truncated RC5 message
13890 BW2 \ from repeated RC5 command
13891 BW3 \ from end of RC5_INT
13892 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
13897 \ ******************************\
13898 ASM RC5_INT \ wake up on Px.RC5 change interrupt
13899 \ ******************************\
13900 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
13901 \ ******************************\
13902 \ \ in : SR(9)=old Toggle bit memory (ADD on)
13903 \ \ SMclock = 8|16|24 MHz
13904 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
13905 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
13906 \ \ SR(9)=new Toggle bit memory (ADD on)
13907 \ ******************************\
13908 \ RC5_FirstStartBitHalfCycle: \
13909 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
13910 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
13911 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
13912 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
13913 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
13914 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
13915 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
13916 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
13917 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
13918 MOV #1778,X \ RC5_Period * 1us
13919 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
13920 MOV #14,W \ count of loop
13922 \ ******************************\
13923 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
13924 \ ******************************\ |
13925 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
13926 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
13927 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
13928 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
13929 \ RC5_Compute_3/4_Period: \ |
13930 RRUM #1,X \ X=1/2 cycle |
13933 ADD X,Y \ Y=3/4 cycle
13934 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
13936 \ ******************************\
13937 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
13938 \ ******************************\
13939 BIT.B #RC5,&IR_IN \ C_flag = IR bit
13940 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
13941 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
13942 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
13943 SUB #1,W \ decrement count loop
13944 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
13945 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
13946 0<> WHILE \ ----> out of loop ----+
13947 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
13949 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
13950 CMP Y,X \ 1 | cycle time out of bound ?
13951 U>= IF \ 2 ^ | yes:
13952 BIC #$30,&RC5_TIM_CTL \ | | stop timer
13953 GOTO BW1 \ | | quit on truncated RC5 message
13955 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
13957 REPEAT \ ----> loop back --+ | with X = new RC5_period value
13958 \ ******************************\ |
13959 \ RC5_SampleEndOf: \ <---------------------+
13960 \ ******************************\
13961 BIC #$30,&RC5_TIM_CTL \ stop timer
13962 \ ******************************\
13963 \ RC5_ComputeNewRC5word \
13964 \ ******************************\
13965 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
13966 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
13967 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
13968 \ ******************************\
13969 \ RC5_ComputeC6bit \
13970 \ ******************************\
13971 BIT #BIT14,T \ test /C6 bit in T
13972 0= IF BIS #BIT6,X \ set C6 bit in X
13973 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
13974 \ ******************************\
13975 \ RC5_CommandByteIsDone \ -- BASE RC5_code
13976 \ ******************************\
13977 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
13978 \ ******************************\
13979 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
13980 XOR @RSP,T \ (new XOR old) Toggle bits
13981 BIT #UF10,T \ repeated RC5_command ?
13982 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
13983 XOR #UF10,0(RSP) \ 5 toggle bit memory
13984 \ ******************************\
13985 \ Display IR_RC5 code \ X = RC5 code
13986 \ ******************************\
13988 MOV &BASE,2(PSP) \ save current base
13989 MOV #$10,&BASE \ set hex base
13990 MOV TOS,0(PSP) \ save TOS
13992 LO2HI \ switch from assembler to FORTH
13993 ['] LCD_CLEAR IS CR \ redirects CR
13994 ['] LCD_WrC IS EMIT \ redirects EMIT
13995 CR ." $" 2 U.R \ print IR_RC5 code
13996 ['] CR >BODY IS CR \ restore CR
13997 ['] EMIT >BODY IS EMIT \ restore EMIT
13998 HI2LO \ switch from FORTH to assembler
13999 MOV TOS,&BASE \ restore current BASE
14001 \ ******************************\
14003 \ ******************************\
14007 \ ------------------------------\
14009 \ ------------------------------\
14010 \ ... \ insert here your background task
14013 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
14014 ADD #4,X \ 1 X = BODY of SLEEP
14017 \ ------------------------------\
14021 \ ------------------------------\
14022 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
14023 \ - - \CNTL Counter lentgh \ 00 = 16 bits
14024 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
14025 \ -- \ID input divider \ 10 = /4
14026 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
14027 \ - \TBCLR TimerB Clear
14030 \ -------------------------------\
14031 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
14032 \ -- \CM Capture Mode
14037 \ --- \OUTMOD \ 011 = set/reset
14043 \ -------------------------------\
14045 \ -------------------------------\
14047 \ ------------------------------\
14048 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
14049 \ ------------------------------\
14050 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
14051 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
14052 \ ------------------------------\
14053 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
14054 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
14055 \ ------------------------------\
14056 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
14057 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
14058 \ ------------------------------\
14059 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
14060 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
14061 \ ------------------------------\
14062 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
14063 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
14064 \ ------------------------------\
14065 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
14066 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
14067 \ ------------------------------\
14068 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
14069 \ ------------------------------\
14070 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
14071 \ ------------------------------\
14072 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
14073 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
14074 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
14075 \ ------------------------------\
14076 BIS.B #LCDVo,&LCDVo_DIR \
14077 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
14078 \ ------------------------------\
14079 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
14080 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
14081 \ ------------------------------\
14082 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
14083 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
14084 \ ******************************\
14086 \ ******************************\
14087 BIS.B #RC5,&IR_IE \ enable RC5_Int
14088 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
14089 MOV #RC5_INT,&IR_Vec \ init interrupt vector
14090 \ ******************************\
14091 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
14092 \ ******************************\
14093 \ %01 0001 0100 \ TAxCTL
14094 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
14095 \ -- \ ID divided by 1
14096 \ -- \ MC MODE = up to TAxCCRn
14097 \ - \ TACLR clear timer count
14100 \ ------------------------------\
14101 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
14102 \ ------------------------------\
14104 \ --- \ TAIDEX pre divisor
14105 \ ------------------------------\
14106 \ %0000 0000 0000 0101 \ TAxCCR0
14107 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
14108 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
14109 \ ------------------------------\
14110 \ %0000 0000 0001 0000 \ TAxCCTL0
14111 \ - \ CAP capture/compare mode = compare
14114 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
14115 \ ------------------------------\
14116 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
14117 \ ------------------------------\
14118 \ define LPM mode for ACCEPT \
14119 \ ------------------------------\
14120 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
14121 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
14122 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
14124 \ ------------------------------\
14125 \ redirects to background task \
14126 \ ------------------------------\
14128 MOV #BACKGROUND,2(X) \
14129 \ ------------------------------\
14131 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
14133 \ ------------------------------\
14135 \ ------------------------------\
14136 $03E8 20_US \ 1- wait 20 ms
14137 $03 TOP_LCD \ 2- send DB5=DB4=1
14138 $CD 20_US \ 3- wait 4,1 ms
14139 $03 TOP_LCD \ 4- send again DB5=DB4=1
14140 $5 20_US \ 5- wait 0,1 ms
14141 $03 TOP_LCD \ 6- send again again DB5=DB4=1
14142 $2 20_US \ wait 40 us = LCD cycle
14143 $02 TOP_LCD \ 7- send DB5=1 DB4=0
14144 $2 20_US \ wait 40 us = LCD cycle
14145 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
14146 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
14147 LCD_Clear \ 10- "LCD_Clear"
14148 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
14149 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
14150 LCD_Clear \ 10- "LCD_Clear"
14151 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
14152 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
14154 ['] CR >BODY IS CR \
14155 ['] EMIT >BODY IS EMIT \
14156 ." RC5toLCD is running. Type STOP to quit"
14157 LIT RECURSE IS WARM \ replace WARM by this START routine
14158 ABORT \ and continue with the next word after WARM...
14159 ; \ ...until interpreter falls in sleep mode within ACCEPT.
14162 CODE STOP \ stops multitasking, must to be used before downloading app
14163 \ restore default action of primary DEFERred word SLEEP, assembly version
14164 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
14165 ADD #4,X \ X = BODY of SLEEP
14166 MOV X,-2(X) \ restore the default background
14169 \ restore default action of primary DEFERred word WARM, FORTH version
14170 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
14172 COLD \ because we want to reset CPU and interrupt vectors
14177 ; downloading RC5toLCD.4th is done
14178 RST_HERE ; this app is protected against <reset>
14186 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
14188 [DEFINED] ASM [IF] \ security test
14192 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
14194 CODE MAX \ n1 n2 -- n3 signed maximum
14195 CMP @PSP,TOS \ n2-n1
14196 S< ?GOTO FW1 \ n2<n1
14202 CODE MIN \ n1 n2 -- n3 signed minimum
14203 CMP @PSP,TOS \ n2-n1
14204 S< ?GOTO BW1 \ n2<n1
14212 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
14213 : U.R \ u n -- display u unsigned in n width (n >= 2)
14215 R> OVER - 0 MAX SPACES TYPE
14220 \ CODE 20_US \ n -- n * 20 us
14221 \ BEGIN \ 3 cycles loop + 6~
14222 \ \ MOV #5,W \ 3 MCLK = 1 MHz
14223 \ \ MOV #23,W \ 3 MCLK = 4 MHz
14224 \ \ MOV #51,W \ 3 MCLK = 8 MHz
14225 \ MOV #104,W \ 3 MCLK = 16 MHz
14226 \ \ MOV #158,W \ 3 MCLK = 24 MHz
14227 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
14232 \ MOV @PSP+,TOS \ 2
14237 CODE 20_US \ n -- n * 20 us
14238 BEGIN \ here we presume that LCD_TIM_IFG = 1...
14240 BIT #1,&LCD_TIM_CTL \ 3
14241 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
14242 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
14244 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
14250 CODE TOP_LCD \ LCD Sample
14251 \ \ if write : %xxxxWWWW --
14252 \ \ if read : -- %0000RRRR
14253 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
14254 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
14255 0= IF \ write LCD bits pattern
14256 AND.B #LCD_DB,TOS \
14257 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
14258 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
14261 THEN \ read LCD bits pattern
14264 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
14265 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
14266 AND.B #LCD_DB,TOS \
14271 CODE LCD_W \ byte -- write byte to LCD
14273 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
14274 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
14275 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
14276 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
14277 COLON \ high level word starts here
14278 TOP_LCD 2 20_US \ write high nibble first
14283 CODE LCD_WrC \ char -- Write Char
14284 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
14289 CODE LCD_WrF \ func -- Write Fonction
14290 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
14296 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
14301 $02 LCD_WrF 100 20_us
14305 [UNDEFINED] OR [IF]
14307 \ https://forth-standard.org/standard/core/OR
14308 \ C OR x1 x2 -- x3 logical OR
14317 : LCD_Entry_set $04 OR LCD_WrF ;
14319 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
14321 : LCD_DSP_Shift $10 OR LCD_WrF ;
14323 : LCD_Fn_Set $20 OR LCD_WrF ;
14325 : LCD_CGRAM_Set $40 OR LCD_WrF ;
14327 : LCD_Goto $80 OR LCD_WrF ;
14329 CODE LCD_R \ -- byte read byte from LCD
14330 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
14331 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
14332 COLON \ starts a FORTH word
14333 TOP_LCD 2 20_us \ -- %0000HHHH
14334 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
14335 HI2LO \ switch from FORTH to assembler
14336 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
14337 ADD.B @PSP+,TOS \ -- %HHHHLLLL
14338 MOV @RSP+,IP \ restore IP saved by COLON
14343 CODE LCD_RdS \ -- status Read Status
14344 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
14349 CODE LCD_RdC \ -- char Read Char
14350 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
14356 \ ******************************\
14357 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
14358 \ ******************************\
14359 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
14360 BIT.B #SW2,&SW2_IN \ test switch S2
14361 0= IF \ case of switch S2 pressed
14362 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
14364 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
14367 BIT.B #SW1,&SW1_IN \ test switch S1 input
14368 0= IF \ case of Switch S1 pressed
14369 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
14371 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
14375 BW1 \ from quit on truncated RC5 message
14376 BW2 \ from repeated RC5 command
14377 BW3 \ from end of RC5_INT
14378 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
14383 \ ******************************\
14384 ASM RC5_INT \ wake up on Px.RC5 change interrupt
14385 \ ******************************\
14386 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
14387 \ ******************************\
14388 \ \ in : SR(9)=old Toggle bit memory (ADD on)
14389 \ \ SMclock = 8|16|24 MHz
14390 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
14391 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
14392 \ \ SR(9)=new Toggle bit memory (ADD on)
14393 \ ******************************\
14394 \ RC5_FirstStartBitHalfCycle: \
14395 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
14396 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
14397 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
14398 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
14399 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
14400 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
14401 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
14402 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
14403 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
14404 MOV #1778,X \ RC5_Period * 1us
14405 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
14406 MOV #14,W \ count of loop
14408 \ ******************************\
14409 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
14410 \ ******************************\ |
14411 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
14412 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
14413 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
14414 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
14415 \ RC5_Compute_3/4_Period: \ |
14416 RRUM #1,X \ X=1/2 cycle |
14419 ADD X,Y \ Y=3/4 cycle
14420 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
14422 \ ******************************\
14423 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
14424 \ ******************************\
14425 BIT.B #RC5,&IR_IN \ C_flag = IR bit
14426 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
14427 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
14428 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
14429 SUB #1,W \ decrement count loop
14430 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
14431 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
14432 0<> WHILE \ ----> out of loop ----+
14433 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
14435 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
14436 CMP Y,X \ 1 | cycle time out of bound ?
14437 U>= IF \ 2 ^ | yes:
14438 BIC #$30,&RC5_TIM_CTL \ | | stop timer
14439 GOTO BW1 \ | | quit on truncated RC5 message
14441 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
14443 REPEAT \ ----> loop back --+ | with X = new RC5_period value
14444 \ ******************************\ |
14445 \ RC5_SampleEndOf: \ <---------------------+
14446 \ ******************************\
14447 BIC #$30,&RC5_TIM_CTL \ stop timer
14448 \ ******************************\
14449 \ RC5_ComputeNewRC5word \
14450 \ ******************************\
14451 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
14452 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
14453 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
14454 \ ******************************\
14455 \ RC5_ComputeC6bit \
14456 \ ******************************\
14457 BIT #BIT14,T \ test /C6 bit in T
14458 0= IF BIS #BIT6,X \ set C6 bit in X
14459 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
14460 \ ******************************\
14461 \ RC5_CommandByteIsDone \ -- BASE RC5_code
14462 \ ******************************\
14463 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
14464 \ ******************************\
14465 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
14466 XOR @RSP,T \ (new XOR old) Toggle bits
14467 BIT #UF10,T \ repeated RC5_command ?
14468 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
14469 XOR #UF10,0(RSP) \ 5 toggle bit memory
14470 \ ******************************\
14471 \ Display IR_RC5 code \ X = RC5 code
14472 \ ******************************\
14474 MOV &BASE,2(PSP) \ save current base
14475 MOV #$10,&BASE \ set hex base
14476 MOV TOS,0(PSP) \ save TOS
14478 LO2HI \ switch from assembler to FORTH
14479 ['] LCD_CLEAR IS CR \ redirects CR
14480 ['] LCD_WrC IS EMIT \ redirects EMIT
14481 CR ." $" 2 U.R \ print IR_RC5 code
14482 ['] CR >BODY IS CR \ restore CR
14483 ['] EMIT >BODY IS EMIT \ restore EMIT
14484 HI2LO \ switch from FORTH to assembler
14485 MOV TOS,&BASE \ restore current BASE
14487 \ ******************************\
14489 \ ******************************\
14493 \ ------------------------------\
14495 \ ------------------------------\
14496 \ ... \ insert here your background task
14499 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
14500 ADD #4,X \ 1 X = BODY of SLEEP
14503 \ ------------------------------\
14507 \ ------------------------------\
14508 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
14509 \ - - \CNTL Counter lentgh \ 00 = 16 bits
14510 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
14511 \ -- \ID input divider \ 10 = /4
14512 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
14513 \ - \TBCLR TimerB Clear
14516 \ -------------------------------\
14517 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
14518 \ -- \CM Capture Mode
14523 \ --- \OUTMOD \ 011 = set/reset
14529 \ -------------------------------\
14531 \ -------------------------------\
14533 \ ------------------------------\
14534 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
14535 \ ------------------------------\
14536 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
14537 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
14538 \ ------------------------------\
14539 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
14540 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
14541 \ ------------------------------\
14542 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
14543 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
14544 \ ------------------------------\
14545 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
14546 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
14547 \ ------------------------------\
14548 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
14549 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
14550 \ ------------------------------\
14551 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
14552 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
14553 \ ------------------------------\
14554 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
14555 \ ------------------------------\
14556 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
14557 \ ------------------------------\
14558 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
14559 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
14560 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
14561 \ ------------------------------\
14562 BIS.B #LCDVo,&LCDVo_DIR \
14563 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
14564 \ ------------------------------\
14565 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
14566 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
14567 \ ------------------------------\
14568 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
14569 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
14570 \ ******************************\
14572 \ ******************************\
14573 BIS.B #RC5,&IR_IE \ enable RC5_Int
14574 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
14575 MOV #RC5_INT,&IR_Vec \ init interrupt vector
14576 \ ******************************\
14577 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
14578 \ ******************************\
14579 \ %01 0001 0100 \ TAxCTL
14580 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
14581 \ -- \ ID divided by 1
14582 \ -- \ MC MODE = up to TAxCCRn
14583 \ - \ TACLR clear timer count
14586 \ ------------------------------\
14587 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
14588 \ ------------------------------\
14590 \ --- \ TAIDEX pre divisor
14591 \ ------------------------------\
14592 \ %0000 0000 0000 0101 \ TAxCCR0
14593 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
14594 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
14595 \ ------------------------------\
14596 \ %0000 0000 0001 0000 \ TAxCCTL0
14597 \ - \ CAP capture/compare mode = compare
14600 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
14601 \ ------------------------------\
14602 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
14603 \ ------------------------------\
14604 \ define LPM mode for ACCEPT \
14605 \ ------------------------------\
14606 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
14607 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
14608 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
14610 \ ------------------------------\
14611 \ redirects to background task \
14612 \ ------------------------------\
14614 MOV #BACKGROUND,2(X) \
14615 \ ------------------------------\
14617 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
14619 \ ------------------------------\
14621 \ ------------------------------\
14622 $03E8 20_US \ 1- wait 20 ms
14623 $03 TOP_LCD \ 2- send DB5=DB4=1
14624 $CD 20_US \ 3- wait 4,1 ms
14625 $03 TOP_LCD \ 4- send again DB5=DB4=1
14626 $5 20_US \ 5- wait 0,1 ms
14627 $03 TOP_LCD \ 6- send again again DB5=DB4=1
14628 $2 20_US \ wait 40 us = LCD cycle
14629 $02 TOP_LCD \ 7- send DB5=1 DB4=0
14630 $2 20_US \ wait 40 us = LCD cycle
14631 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
14632 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
14633 LCD_Clear \ 10- "LCD_Clear"
14634 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
14635 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
14636 LCD_Clear \ 10- "LCD_Clear"
14637 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
14638 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
14640 ['] CR >BODY IS CR \
14641 ['] EMIT >BODY IS EMIT \
14642 ." RC5toLCD is running. Type STOP to quit"
14643 LIT RECURSE IS WARM \ replace WARM by this START routine
14644 ABORT \ and continue with the next word after WARM...
14645 ; \ ...until interpreter falls in sleep mode within ACCEPT.
14648 CODE STOP \ stops multitasking, must to be used before downloading app
14649 \ restore default action of primary DEFERred word SLEEP, assembly version
14650 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
14651 ADD #4,X \ X = BODY of SLEEP
14652 MOV X,-2(X) \ restore the default background
14655 \ restore default action of primary DEFERred word WARM, FORTH version
14656 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
14658 COLD \ because we want to reset CPU and interrupt vectors
14663 ; downloading RC5toLCD.4th is done
14664 RST_HERE ; this app is protected against <reset>
14672 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
14674 [DEFINED] ASM [IF] \ security test
14678 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
14680 CODE MAX \ n1 n2 -- n3 signed maximum
14681 CMP @PSP,TOS \ n2-n1
14682 S< ?GOTO FW1 \ n2<n1
14688 CODE MIN \ n1 n2 -- n3 signed minimum
14689 CMP @PSP,TOS \ n2-n1
14690 S< ?GOTO BW1 \ n2<n1
14698 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
14699 : U.R \ u n -- display u unsigned in n width (n >= 2)
14701 R> OVER - 0 MAX SPACES TYPE
14706 \ CODE 20_US \ n -- n * 20 us
14707 \ BEGIN \ 3 cycles loop + 6~
14708 \ \ MOV #5,W \ 3 MCLK = 1 MHz
14709 \ \ MOV #23,W \ 3 MCLK = 4 MHz
14710 \ \ MOV #51,W \ 3 MCLK = 8 MHz
14711 \ MOV #104,W \ 3 MCLK = 16 MHz
14712 \ \ MOV #158,W \ 3 MCLK = 24 MHz
14713 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
14718 \ MOV @PSP+,TOS \ 2
14723 CODE 20_US \ n -- n * 20 us
14724 BEGIN \ here we presume that LCD_TIM_IFG = 1...
14726 BIT #1,&LCD_TIM_CTL \ 3
14727 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
14728 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
14730 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
14736 CODE TOP_LCD \ LCD Sample
14737 \ \ if write : %xxxxWWWW --
14738 \ \ if read : -- %0000RRRR
14739 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
14740 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
14741 0= IF \ write LCD bits pattern
14742 AND.B #LCD_DB,TOS \
14743 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
14744 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
14747 THEN \ read LCD bits pattern
14750 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
14751 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
14752 AND.B #LCD_DB,TOS \
14757 CODE LCD_W \ byte -- write byte to LCD
14759 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
14760 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
14761 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
14762 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
14763 COLON \ high level word starts here
14764 TOP_LCD 2 20_US \ write high nibble first
14769 CODE LCD_WrC \ char -- Write Char
14770 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
14775 CODE LCD_WrF \ func -- Write Fonction
14776 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
14782 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
14787 $02 LCD_WrF 100 20_us
14791 [UNDEFINED] OR [IF]
14793 \ https://forth-standard.org/standard/core/OR
14794 \ C OR x1 x2 -- x3 logical OR
14803 : LCD_Entry_set $04 OR LCD_WrF ;
14805 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
14807 : LCD_DSP_Shift $10 OR LCD_WrF ;
14809 : LCD_Fn_Set $20 OR LCD_WrF ;
14811 : LCD_CGRAM_Set $40 OR LCD_WrF ;
14813 : LCD_Goto $80 OR LCD_WrF ;
14815 CODE LCD_R \ -- byte read byte from LCD
14816 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
14817 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
14818 COLON \ starts a FORTH word
14819 TOP_LCD 2 20_us \ -- %0000HHHH
14820 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
14821 HI2LO \ switch from FORTH to assembler
14822 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
14823 ADD.B @PSP+,TOS \ -- %HHHHLLLL
14824 MOV @RSP+,IP \ restore IP saved by COLON
14829 CODE LCD_RdS \ -- status Read Status
14830 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
14835 CODE LCD_RdC \ -- char Read Char
14836 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
14842 \ ******************************\
14843 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
14844 \ ******************************\
14845 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
14846 BIT.B #SW2,&SW2_IN \ test switch S2
14847 0= IF \ case of switch S2 pressed
14848 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
14850 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
14853 BIT.B #SW1,&SW1_IN \ test switch S1 input
14854 0= IF \ case of Switch S1 pressed
14855 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
14857 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
14861 BW1 \ from quit on truncated RC5 message
14862 BW2 \ from repeated RC5 command
14863 BW3 \ from end of RC5_INT
14864 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
14869 \ ******************************\
14870 ASM RC5_INT \ wake up on Px.RC5 change interrupt
14871 \ ******************************\
14872 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
14873 \ ******************************\
14874 \ \ in : SR(9)=old Toggle bit memory (ADD on)
14875 \ \ SMclock = 8|16|24 MHz
14876 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
14877 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
14878 \ \ SR(9)=new Toggle bit memory (ADD on)
14879 \ ******************************\
14880 \ RC5_FirstStartBitHalfCycle: \
14881 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
14882 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
14883 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
14884 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
14885 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
14886 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
14887 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
14888 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
14889 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
14890 MOV #1778,X \ RC5_Period * 1us
14891 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
14892 MOV #14,W \ count of loop
14894 \ ******************************\
14895 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
14896 \ ******************************\ |
14897 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
14898 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
14899 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
14900 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
14901 \ RC5_Compute_3/4_Period: \ |
14902 RRUM #1,X \ X=1/2 cycle |
14905 ADD X,Y \ Y=3/4 cycle
14906 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
14908 \ ******************************\
14909 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
14910 \ ******************************\
14911 BIT.B #RC5,&IR_IN \ C_flag = IR bit
14912 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
14913 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
14914 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
14915 SUB #1,W \ decrement count loop
14916 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
14917 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
14918 0<> WHILE \ ----> out of loop ----+
14919 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
14921 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
14922 CMP Y,X \ 1 | cycle time out of bound ?
14923 U>= IF \ 2 ^ | yes:
14924 BIC #$30,&RC5_TIM_CTL \ | | stop timer
14925 GOTO BW1 \ | | quit on truncated RC5 message
14927 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
14929 REPEAT \ ----> loop back --+ | with X = new RC5_period value
14930 \ ******************************\ |
14931 \ RC5_SampleEndOf: \ <---------------------+
14932 \ ******************************\
14933 BIC #$30,&RC5_TIM_CTL \ stop timer
14934 \ ******************************\
14935 \ RC5_ComputeNewRC5word \
14936 \ ******************************\
14937 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
14938 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
14939 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
14940 \ ******************************\
14941 \ RC5_ComputeC6bit \
14942 \ ******************************\
14943 BIT #BIT14,T \ test /C6 bit in T
14944 0= IF BIS #BIT6,X \ set C6 bit in X
14945 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
14946 \ ******************************\
14947 \ RC5_CommandByteIsDone \ -- BASE RC5_code
14948 \ ******************************\
14949 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
14950 \ ******************************\
14951 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
14952 XOR @RSP,T \ (new XOR old) Toggle bits
14953 BIT #UF10,T \ repeated RC5_command ?
14954 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
14955 XOR #UF10,0(RSP) \ 5 toggle bit memory
14956 \ ******************************\
14957 \ Display IR_RC5 code \ X = RC5 code
14958 \ ******************************\
14960 MOV &BASE,2(PSP) \ save current base
14961 MOV #$10,&BASE \ set hex base
14962 MOV TOS,0(PSP) \ save TOS
14964 LO2HI \ switch from assembler to FORTH
14965 ['] LCD_CLEAR IS CR \ redirects CR
14966 ['] LCD_WrC IS EMIT \ redirects EMIT
14967 CR ." $" 2 U.R \ print IR_RC5 code
14968 ['] CR >BODY IS CR \ restore CR
14969 ['] EMIT >BODY IS EMIT \ restore EMIT
14970 HI2LO \ switch from FORTH to assembler
14971 MOV TOS,&BASE \ restore current BASE
14973 \ ******************************\
14975 \ ******************************\
14979 \ ------------------------------\
14981 \ ------------------------------\
14982 \ ... \ insert here your background task
14985 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
14986 ADD #4,X \ 1 X = BODY of SLEEP
14989 \ ------------------------------\
14993 \ ------------------------------\
14994 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
14995 \ - - \CNTL Counter lentgh \ 00 = 16 bits
14996 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
14997 \ -- \ID input divider \ 10 = /4
14998 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
14999 \ - \TBCLR TimerB Clear
15002 \ -------------------------------\
15003 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
15004 \ -- \CM Capture Mode
15009 \ --- \OUTMOD \ 011 = set/reset
15015 \ -------------------------------\
15017 \ -------------------------------\
15019 \ ------------------------------\
15020 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
15021 \ ------------------------------\
15022 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
15023 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
15024 \ ------------------------------\
15025 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
15026 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
15027 \ ------------------------------\
15028 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
15029 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
15030 \ ------------------------------\
15031 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
15032 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
15033 \ ------------------------------\
15034 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
15035 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
15036 \ ------------------------------\
15037 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
15038 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
15039 \ ------------------------------\
15040 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
15041 \ ------------------------------\
15042 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
15043 \ ------------------------------\
15044 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
15045 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
15046 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
15047 \ ------------------------------\
15048 BIS.B #LCDVo,&LCDVo_DIR \
15049 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
15050 \ ------------------------------\
15051 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
15052 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
15053 \ ------------------------------\
15054 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
15055 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
15056 \ ******************************\
15058 \ ******************************\
15059 BIS.B #RC5,&IR_IE \ enable RC5_Int
15060 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
15061 MOV #RC5_INT,&IR_Vec \ init interrupt vector
15062 \ ******************************\
15063 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
15064 \ ******************************\
15065 \ %01 0001 0100 \ TAxCTL
15066 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
15067 \ -- \ ID divided by 1
15068 \ -- \ MC MODE = up to TAxCCRn
15069 \ - \ TACLR clear timer count
15072 \ ------------------------------\
15073 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
15074 \ ------------------------------\
15076 \ --- \ TAIDEX pre divisor
15077 \ ------------------------------\
15078 \ %0000 0000 0000 0101 \ TAxCCR0
15079 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
15080 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
15081 \ ------------------------------\
15082 \ %0000 0000 0001 0000 \ TAxCCTL0
15083 \ - \ CAP capture/compare mode = compare
15086 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
15087 \ ------------------------------\
15088 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
15089 \ ------------------------------\
15090 \ define LPM mode for ACCEPT \
15091 \ ------------------------------\
15092 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
15093 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
15094 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
15096 \ ------------------------------\
15097 \ redirects to background task \
15098 \ ------------------------------\
15100 MOV #BACKGROUND,2(X) \
15101 \ ------------------------------\
15103 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
15105 \ ------------------------------\
15107 \ ------------------------------\
15108 $03E8 20_US \ 1- wait 20 ms
15109 $03 TOP_LCD \ 2- send DB5=DB4=1
15110 $CD 20_US \ 3- wait 4,1 ms
15111 $03 TOP_LCD \ 4- send again DB5=DB4=1
15112 $5 20_US \ 5- wait 0,1 ms
15113 $03 TOP_LCD \ 6- send again again DB5=DB4=1
15114 $2 20_US \ wait 40 us = LCD cycle
15115 $02 TOP_LCD \ 7- send DB5=1 DB4=0
15116 $2 20_US \ wait 40 us = LCD cycle
15117 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
15118 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
15119 LCD_Clear \ 10- "LCD_Clear"
15120 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
15121 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
15122 LCD_Clear \ 10- "LCD_Clear"
15123 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
15124 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
15126 ['] CR >BODY IS CR \
15127 ['] EMIT >BODY IS EMIT \
15128 ." RC5toLCD is running. Type STOP to quit"
15129 LIT RECURSE IS WARM \ replace WARM by this START routine
15130 ABORT \ and continue with the next word after WARM...
15131 ; \ ...until interpreter falls in sleep mode within ACCEPT.
15134 CODE STOP \ stops multitasking, must to be used before downloading app
15135 \ restore default action of primary DEFERred word SLEEP, assembly version
15136 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
15137 ADD #4,X \ X = BODY of SLEEP
15138 MOV X,-2(X) \ restore the default background
15141 \ restore default action of primary DEFERred word WARM, FORTH version
15142 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
15144 COLD \ because we want to reset CPU and interrupt vectors
15149 ; downloading RC5toLCD.4th is done
15150 RST_HERE ; this app is protected against <reset>
15158 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
15160 [DEFINED] ASM [IF] \ security test
15164 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
15166 CODE MAX \ n1 n2 -- n3 signed maximum
15167 CMP @PSP,TOS \ n2-n1
15168 S< ?GOTO FW1 \ n2<n1
15174 CODE MIN \ n1 n2 -- n3 signed minimum
15175 CMP @PSP,TOS \ n2-n1
15176 S< ?GOTO BW1 \ n2<n1
15184 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
15185 : U.R \ u n -- display u unsigned in n width (n >= 2)
15187 R> OVER - 0 MAX SPACES TYPE
15192 \ CODE 20_US \ n -- n * 20 us
15193 \ BEGIN \ 3 cycles loop + 6~
15194 \ \ MOV #5,W \ 3 MCLK = 1 MHz
15195 \ \ MOV #23,W \ 3 MCLK = 4 MHz
15196 \ \ MOV #51,W \ 3 MCLK = 8 MHz
15197 \ MOV #104,W \ 3 MCLK = 16 MHz
15198 \ \ MOV #158,W \ 3 MCLK = 24 MHz
15199 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
15204 \ MOV @PSP+,TOS \ 2
15209 CODE 20_US \ n -- n * 20 us
15210 BEGIN \ here we presume that LCD_TIM_IFG = 1...
15212 BIT #1,&LCD_TIM_CTL \ 3
15213 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
15214 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
15216 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
15222 CODE TOP_LCD \ LCD Sample
15223 \ \ if write : %xxxxWWWW --
15224 \ \ if read : -- %0000RRRR
15225 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
15226 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
15227 0= IF \ write LCD bits pattern
15228 AND.B #LCD_DB,TOS \
15229 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
15230 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
15233 THEN \ read LCD bits pattern
15236 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
15237 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
15238 AND.B #LCD_DB,TOS \
15243 CODE LCD_W \ byte -- write byte to LCD
15245 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
15246 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
15247 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
15248 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
15249 COLON \ high level word starts here
15250 TOP_LCD 2 20_US \ write high nibble first
15255 CODE LCD_WrC \ char -- Write Char
15256 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
15261 CODE LCD_WrF \ func -- Write Fonction
15262 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
15268 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
15273 $02 LCD_WrF 100 20_us
15277 [UNDEFINED] OR [IF]
15279 \ https://forth-standard.org/standard/core/OR
15280 \ C OR x1 x2 -- x3 logical OR
15289 : LCD_Entry_set $04 OR LCD_WrF ;
15291 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
15293 : LCD_DSP_Shift $10 OR LCD_WrF ;
15295 : LCD_Fn_Set $20 OR LCD_WrF ;
15297 : LCD_CGRAM_Set $40 OR LCD_WrF ;
15299 : LCD_Goto $80 OR LCD_WrF ;
15301 CODE LCD_R \ -- byte read byte from LCD
15302 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
15303 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
15304 COLON \ starts a FORTH word
15305 TOP_LCD 2 20_us \ -- %0000HHHH
15306 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
15307 HI2LO \ switch from FORTH to assembler
15308 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
15309 ADD.B @PSP+,TOS \ -- %HHHHLLLL
15310 MOV @RSP+,IP \ restore IP saved by COLON
15315 CODE LCD_RdS \ -- status Read Status
15316 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
15321 CODE LCD_RdC \ -- char Read Char
15322 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
15328 \ ******************************\
15329 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
15330 \ ******************************\
15331 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
15332 BIT.B #SW2,&SW2_IN \ test switch S2
15333 0= IF \ case of switch S2 pressed
15334 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
15336 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
15339 BIT.B #SW1,&SW1_IN \ test switch S1 input
15340 0= IF \ case of Switch S1 pressed
15341 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
15343 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
15347 BW1 \ from quit on truncated RC5 message
15348 BW2 \ from repeated RC5 command
15349 BW3 \ from end of RC5_INT
15350 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
15355 \ ******************************\
15356 ASM RC5_INT \ wake up on Px.RC5 change interrupt
15357 \ ******************************\
15358 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
15359 \ ******************************\
15360 \ \ in : SR(9)=old Toggle bit memory (ADD on)
15361 \ \ SMclock = 8|16|24 MHz
15362 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
15363 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
15364 \ \ SR(9)=new Toggle bit memory (ADD on)
15365 \ ******************************\
15366 \ RC5_FirstStartBitHalfCycle: \
15367 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
15368 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
15369 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
15370 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
15371 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
15372 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
15373 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
15374 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
15375 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
15376 MOV #1778,X \ RC5_Period * 1us
15377 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
15378 MOV #14,W \ count of loop
15380 \ ******************************\
15381 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
15382 \ ******************************\ |
15383 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
15384 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
15385 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
15386 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
15387 \ RC5_Compute_3/4_Period: \ |
15388 RRUM #1,X \ X=1/2 cycle |
15391 ADD X,Y \ Y=3/4 cycle
15392 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
15394 \ ******************************\
15395 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
15396 \ ******************************\
15397 BIT.B #RC5,&IR_IN \ C_flag = IR bit
15398 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
15399 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
15400 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
15401 SUB #1,W \ decrement count loop
15402 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
15403 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
15404 0<> WHILE \ ----> out of loop ----+
15405 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
15407 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
15408 CMP Y,X \ 1 | cycle time out of bound ?
15409 U>= IF \ 2 ^ | yes:
15410 BIC #$30,&RC5_TIM_CTL \ | | stop timer
15411 GOTO BW1 \ | | quit on truncated RC5 message
15413 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
15415 REPEAT \ ----> loop back --+ | with X = new RC5_period value
15416 \ ******************************\ |
15417 \ RC5_SampleEndOf: \ <---------------------+
15418 \ ******************************\
15419 BIC #$30,&RC5_TIM_CTL \ stop timer
15420 \ ******************************\
15421 \ RC5_ComputeNewRC5word \
15422 \ ******************************\
15423 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
15424 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
15425 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
15426 \ ******************************\
15427 \ RC5_ComputeC6bit \
15428 \ ******************************\
15429 BIT #BIT14,T \ test /C6 bit in T
15430 0= IF BIS #BIT6,X \ set C6 bit in X
15431 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
15432 \ ******************************\
15433 \ RC5_CommandByteIsDone \ -- BASE RC5_code
15434 \ ******************************\
15435 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
15436 \ ******************************\
15437 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
15438 XOR @RSP,T \ (new XOR old) Toggle bits
15439 BIT #UF10,T \ repeated RC5_command ?
15440 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
15441 XOR #UF10,0(RSP) \ 5 toggle bit memory
15442 \ ******************************\
15443 \ Display IR_RC5 code \ X = RC5 code
15444 \ ******************************\
15446 MOV &BASE,2(PSP) \ save current base
15447 MOV #$10,&BASE \ set hex base
15448 MOV TOS,0(PSP) \ save TOS
15450 LO2HI \ switch from assembler to FORTH
15451 ['] LCD_CLEAR IS CR \ redirects CR
15452 ['] LCD_WrC IS EMIT \ redirects EMIT
15453 CR ." $" 2 U.R \ print IR_RC5 code
15454 ['] CR >BODY IS CR \ restore CR
15455 ['] EMIT >BODY IS EMIT \ restore EMIT
15456 HI2LO \ switch from FORTH to assembler
15457 MOV TOS,&BASE \ restore current BASE
15459 \ ******************************\
15461 \ ******************************\
15465 \ ------------------------------\
15467 \ ------------------------------\
15468 \ ... \ insert here your background task
15471 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
15472 ADD #4,X \ 1 X = BODY of SLEEP
15475 \ ------------------------------\
15479 \ ------------------------------\
15480 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
15481 \ - - \CNTL Counter lentgh \ 00 = 16 bits
15482 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
15483 \ -- \ID input divider \ 10 = /4
15484 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
15485 \ - \TBCLR TimerB Clear
15488 \ -------------------------------\
15489 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
15490 \ -- \CM Capture Mode
15495 \ --- \OUTMOD \ 011 = set/reset
15501 \ -------------------------------\
15503 \ -------------------------------\
15505 \ ------------------------------\
15506 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
15507 \ ------------------------------\
15508 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
15509 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
15510 \ ------------------------------\
15511 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
15512 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
15513 \ ------------------------------\
15514 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
15515 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
15516 \ ------------------------------\
15517 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
15518 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
15519 \ ------------------------------\
15520 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
15521 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
15522 \ ------------------------------\
15523 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
15524 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
15525 \ ------------------------------\
15526 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
15527 \ ------------------------------\
15528 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
15529 \ ------------------------------\
15530 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
15531 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
15532 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
15533 \ ------------------------------\
15534 BIS.B #LCDVo,&LCDVo_DIR \
15535 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
15536 \ ------------------------------\
15537 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
15538 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
15539 \ ------------------------------\
15540 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
15541 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
15542 \ ******************************\
15544 \ ******************************\
15545 BIS.B #RC5,&IR_IE \ enable RC5_Int
15546 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
15547 MOV #RC5_INT,&IR_Vec \ init interrupt vector
15548 \ ******************************\
15549 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
15550 \ ******************************\
15551 \ %01 0001 0100 \ TAxCTL
15552 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
15553 \ -- \ ID divided by 1
15554 \ -- \ MC MODE = up to TAxCCRn
15555 \ - \ TACLR clear timer count
15558 \ ------------------------------\
15559 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
15560 \ ------------------------------\
15562 \ --- \ TAIDEX pre divisor
15563 \ ------------------------------\
15564 \ %0000 0000 0000 0101 \ TAxCCR0
15565 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
15566 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
15567 \ ------------------------------\
15568 \ %0000 0000 0001 0000 \ TAxCCTL0
15569 \ - \ CAP capture/compare mode = compare
15572 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
15573 \ ------------------------------\
15574 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
15575 \ ------------------------------\
15576 \ define LPM mode for ACCEPT \
15577 \ ------------------------------\
15578 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
15579 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
15580 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
15582 \ ------------------------------\
15583 \ redirects to background task \
15584 \ ------------------------------\
15586 MOV #BACKGROUND,2(X) \
15587 \ ------------------------------\
15589 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
15591 \ ------------------------------\
15593 \ ------------------------------\
15594 $03E8 20_US \ 1- wait 20 ms
15595 $03 TOP_LCD \ 2- send DB5=DB4=1
15596 $CD 20_US \ 3- wait 4,1 ms
15597 $03 TOP_LCD \ 4- send again DB5=DB4=1
15598 $5 20_US \ 5- wait 0,1 ms
15599 $03 TOP_LCD \ 6- send again again DB5=DB4=1
15600 $2 20_US \ wait 40 us = LCD cycle
15601 $02 TOP_LCD \ 7- send DB5=1 DB4=0
15602 $2 20_US \ wait 40 us = LCD cycle
15603 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
15604 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
15605 LCD_Clear \ 10- "LCD_Clear"
15606 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
15607 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
15608 LCD_Clear \ 10- "LCD_Clear"
15609 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
15610 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
15612 ['] CR >BODY IS CR \
15613 ['] EMIT >BODY IS EMIT \
15614 ." RC5toLCD is running. Type STOP to quit"
15615 LIT RECURSE IS WARM \ replace WARM by this START routine
15616 ABORT \ and continue with the next word after WARM...
15617 ; \ ...until interpreter falls in sleep mode within ACCEPT.
15620 CODE STOP \ stops multitasking, must to be used before downloading app
15621 \ restore default action of primary DEFERred word SLEEP, assembly version
15622 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
15623 ADD #4,X \ X = BODY of SLEEP
15624 MOV X,-2(X) \ restore the default background
15627 \ restore default action of primary DEFERred word WARM, FORTH version
15628 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
15630 COLD \ because we want to reset CPU and interrupt vectors
15635 ; downloading RC5toLCD.4th is done
15636 RST_HERE ; this app is protected against <reset>
15644 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
15646 [DEFINED] ASM [IF] \ security test
15650 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
15652 CODE MAX \ n1 n2 -- n3 signed maximum
15653 CMP @PSP,TOS \ n2-n1
15654 S< ?GOTO FW1 \ n2<n1
15660 CODE MIN \ n1 n2 -- n3 signed minimum
15661 CMP @PSP,TOS \ n2-n1
15662 S< ?GOTO BW1 \ n2<n1
15670 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
15671 : U.R \ u n -- display u unsigned in n width (n >= 2)
15673 R> OVER - 0 MAX SPACES TYPE
15678 \ CODE 20_US \ n -- n * 20 us
15679 \ BEGIN \ 3 cycles loop + 6~
15680 \ \ MOV #5,W \ 3 MCLK = 1 MHz
15681 \ \ MOV #23,W \ 3 MCLK = 4 MHz
15682 \ \ MOV #51,W \ 3 MCLK = 8 MHz
15683 \ MOV #104,W \ 3 MCLK = 16 MHz
15684 \ \ MOV #158,W \ 3 MCLK = 24 MHz
15685 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
15690 \ MOV @PSP+,TOS \ 2
15695 CODE 20_US \ n -- n * 20 us
15696 BEGIN \ here we presume that LCD_TIM_IFG = 1...
15698 BIT #1,&LCD_TIM_CTL \ 3
15699 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
15700 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
15702 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
15708 CODE TOP_LCD \ LCD Sample
15709 \ \ if write : %xxxxWWWW --
15710 \ \ if read : -- %0000RRRR
15711 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
15712 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
15713 0= IF \ write LCD bits pattern
15714 AND.B #LCD_DB,TOS \
15715 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
15716 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
15719 THEN \ read LCD bits pattern
15722 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
15723 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
15724 AND.B #LCD_DB,TOS \
15729 CODE LCD_W \ byte -- write byte to LCD
15731 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
15732 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
15733 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
15734 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
15735 COLON \ high level word starts here
15736 TOP_LCD 2 20_US \ write high nibble first
15741 CODE LCD_WrC \ char -- Write Char
15742 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
15747 CODE LCD_WrF \ func -- Write Fonction
15748 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
15754 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
15759 $02 LCD_WrF 100 20_us
15763 [UNDEFINED] OR [IF]
15765 \ https://forth-standard.org/standard/core/OR
15766 \ C OR x1 x2 -- x3 logical OR
15775 : LCD_Entry_set $04 OR LCD_WrF ;
15777 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
15779 : LCD_DSP_Shift $10 OR LCD_WrF ;
15781 : LCD_Fn_Set $20 OR LCD_WrF ;
15783 : LCD_CGRAM_Set $40 OR LCD_WrF ;
15785 : LCD_Goto $80 OR LCD_WrF ;
15787 CODE LCD_R \ -- byte read byte from LCD
15788 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
15789 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
15790 COLON \ starts a FORTH word
15791 TOP_LCD 2 20_us \ -- %0000HHHH
15792 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
15793 HI2LO \ switch from FORTH to assembler
15794 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
15795 ADD.B @PSP+,TOS \ -- %HHHHLLLL
15796 MOV @RSP+,IP \ restore IP saved by COLON
15801 CODE LCD_RdS \ -- status Read Status
15802 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
15807 CODE LCD_RdC \ -- char Read Char
15808 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
15814 \ ******************************\
15815 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
15816 \ ******************************\
15817 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
15818 BIT.B #SW2,&SW2_IN \ test switch S2
15819 0= IF \ case of switch S2 pressed
15820 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
15822 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
15825 BIT.B #SW1,&SW1_IN \ test switch S1 input
15826 0= IF \ case of Switch S1 pressed
15827 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
15829 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
15833 BW1 \ from quit on truncated RC5 message
15834 BW2 \ from repeated RC5 command
15835 BW3 \ from end of RC5_INT
15836 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
15841 \ ******************************\
15842 ASM RC5_INT \ wake up on Px.RC5 change interrupt
15843 \ ******************************\
15844 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
15845 \ ******************************\
15846 \ \ in : SR(9)=old Toggle bit memory (ADD on)
15847 \ \ SMclock = 8|16|24 MHz
15848 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
15849 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
15850 \ \ SR(9)=new Toggle bit memory (ADD on)
15851 \ ******************************\
15852 \ RC5_FirstStartBitHalfCycle: \
15853 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
15854 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
15855 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
15856 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
15857 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
15858 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
15859 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
15860 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
15861 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
15862 MOV #1778,X \ RC5_Period * 1us
15863 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
15864 MOV #14,W \ count of loop
15866 \ ******************************\
15867 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
15868 \ ******************************\ |
15869 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
15870 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
15871 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
15872 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
15873 \ RC5_Compute_3/4_Period: \ |
15874 RRUM #1,X \ X=1/2 cycle |
15877 ADD X,Y \ Y=3/4 cycle
15878 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
15880 \ ******************************\
15881 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
15882 \ ******************************\
15883 BIT.B #RC5,&IR_IN \ C_flag = IR bit
15884 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
15885 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
15886 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
15887 SUB #1,W \ decrement count loop
15888 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
15889 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
15890 0<> WHILE \ ----> out of loop ----+
15891 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
15893 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
15894 CMP Y,X \ 1 | cycle time out of bound ?
15895 U>= IF \ 2 ^ | yes:
15896 BIC #$30,&RC5_TIM_CTL \ | | stop timer
15897 GOTO BW1 \ | | quit on truncated RC5 message
15899 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
15901 REPEAT \ ----> loop back --+ | with X = new RC5_period value
15902 \ ******************************\ |
15903 \ RC5_SampleEndOf: \ <---------------------+
15904 \ ******************************\
15905 BIC #$30,&RC5_TIM_CTL \ stop timer
15906 \ ******************************\
15907 \ RC5_ComputeNewRC5word \
15908 \ ******************************\
15909 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
15910 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
15911 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
15912 \ ******************************\
15913 \ RC5_ComputeC6bit \
15914 \ ******************************\
15915 BIT #BIT14,T \ test /C6 bit in T
15916 0= IF BIS #BIT6,X \ set C6 bit in X
15917 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
15918 \ ******************************\
15919 \ RC5_CommandByteIsDone \ -- BASE RC5_code
15920 \ ******************************\
15921 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
15922 \ ******************************\
15923 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
15924 XOR @RSP,T \ (new XOR old) Toggle bits
15925 BIT #UF10,T \ repeated RC5_command ?
15926 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
15927 XOR #UF10,0(RSP) \ 5 toggle bit memory
15928 \ ******************************\
15929 \ Display IR_RC5 code \ X = RC5 code
15930 \ ******************************\
15932 MOV &BASE,2(PSP) \ save current base
15933 MOV #$10,&BASE \ set hex base
15934 MOV TOS,0(PSP) \ save TOS
15936 LO2HI \ switch from assembler to FORTH
15937 ['] LCD_CLEAR IS CR \ redirects CR
15938 ['] LCD_WrC IS EMIT \ redirects EMIT
15939 CR ." $" 2 U.R \ print IR_RC5 code
15940 ['] CR >BODY IS CR \ restore CR
15941 ['] EMIT >BODY IS EMIT \ restore EMIT
15942 HI2LO \ switch from FORTH to assembler
15943 MOV TOS,&BASE \ restore current BASE
15945 \ ******************************\
15947 \ ******************************\
15951 \ ------------------------------\
15953 \ ------------------------------\
15954 \ ... \ insert here your background task
15957 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
15958 ADD #4,X \ 1 X = BODY of SLEEP
15961 \ ------------------------------\
15965 \ ------------------------------\
15966 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
15967 \ - - \CNTL Counter lentgh \ 00 = 16 bits
15968 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
15969 \ -- \ID input divider \ 10 = /4
15970 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
15971 \ - \TBCLR TimerB Clear
15974 \ -------------------------------\
15975 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
15976 \ -- \CM Capture Mode
15981 \ --- \OUTMOD \ 011 = set/reset
15987 \ -------------------------------\
15989 \ -------------------------------\
15991 \ ------------------------------\
15992 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
15993 \ ------------------------------\
15994 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
15995 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
15996 \ ------------------------------\
15997 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
15998 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
15999 \ ------------------------------\
16000 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
16001 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
16002 \ ------------------------------\
16003 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
16004 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
16005 \ ------------------------------\
16006 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
16007 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
16008 \ ------------------------------\
16009 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
16010 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
16011 \ ------------------------------\
16012 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
16013 \ ------------------------------\
16014 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
16015 \ ------------------------------\
16016 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
16017 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
16018 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
16019 \ ------------------------------\
16020 BIS.B #LCDVo,&LCDVo_DIR \
16021 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
16022 \ ------------------------------\
16023 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
16024 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
16025 \ ------------------------------\
16026 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
16027 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
16028 \ ******************************\
16030 \ ******************************\
16031 BIS.B #RC5,&IR_IE \ enable RC5_Int
16032 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
16033 MOV #RC5_INT,&IR_Vec \ init interrupt vector
16034 \ ******************************\
16035 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
16036 \ ******************************\
16037 \ %01 0001 0100 \ TAxCTL
16038 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
16039 \ -- \ ID divided by 1
16040 \ -- \ MC MODE = up to TAxCCRn
16041 \ - \ TACLR clear timer count
16044 \ ------------------------------\
16045 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
16046 \ ------------------------------\
16048 \ --- \ TAIDEX pre divisor
16049 \ ------------------------------\
16050 \ %0000 0000 0000 0101 \ TAxCCR0
16051 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
16052 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
16053 \ ------------------------------\
16054 \ %0000 0000 0001 0000 \ TAxCCTL0
16055 \ - \ CAP capture/compare mode = compare
16058 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
16059 \ ------------------------------\
16060 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
16061 \ ------------------------------\
16062 \ define LPM mode for ACCEPT \
16063 \ ------------------------------\
16064 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
16065 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
16066 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
16068 \ ------------------------------\
16069 \ redirects to background task \
16070 \ ------------------------------\
16072 MOV #BACKGROUND,2(X) \
16073 \ ------------------------------\
16075 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
16077 \ ------------------------------\
16079 \ ------------------------------\
16080 $03E8 20_US \ 1- wait 20 ms
16081 $03 TOP_LCD \ 2- send DB5=DB4=1
16082 $CD 20_US \ 3- wait 4,1 ms
16083 $03 TOP_LCD \ 4- send again DB5=DB4=1
16084 $5 20_US \ 5- wait 0,1 ms
16085 $03 TOP_LCD \ 6- send again again DB5=DB4=1
16086 $2 20_US \ wait 40 us = LCD cycle
16087 $02 TOP_LCD \ 7- send DB5=1 DB4=0
16088 $2 20_US \ wait 40 us = LCD cycle
16089 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
16090 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
16091 LCD_Clear \ 10- "LCD_Clear"
16092 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
16093 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
16094 LCD_Clear \ 10- "LCD_Clear"
16095 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
16096 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
16098 ['] CR >BODY IS CR \
16099 ['] EMIT >BODY IS EMIT \
16100 ." RC5toLCD is running. Type STOP to quit"
16101 LIT RECURSE IS WARM \ replace WARM by this START routine
16102 ABORT \ and continue with the next word after WARM...
16103 ; \ ...until interpreter falls in sleep mode within ACCEPT.
16106 CODE STOP \ stops multitasking, must to be used before downloading app
16107 \ restore default action of primary DEFERred word SLEEP, assembly version
16108 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
16109 ADD #4,X \ X = BODY of SLEEP
16110 MOV X,-2(X) \ restore the default background
16113 \ restore default action of primary DEFERred word WARM, FORTH version
16114 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
16116 COLD \ because we want to reset CPU and interrupt vectors
16121 ; downloading RC5toLCD.4th is done
16122 RST_HERE ; this app is protected against <reset>
16130 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
16132 [DEFINED] ASM [IF] \ security test
16136 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
16138 CODE MAX \ n1 n2 -- n3 signed maximum
16139 CMP @PSP,TOS \ n2-n1
16140 S< ?GOTO FW1 \ n2<n1
16146 CODE MIN \ n1 n2 -- n3 signed minimum
16147 CMP @PSP,TOS \ n2-n1
16148 S< ?GOTO BW1 \ n2<n1
16156 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
16157 : U.R \ u n -- display u unsigned in n width (n >= 2)
16159 R> OVER - 0 MAX SPACES TYPE
16164 \ CODE 20_US \ n -- n * 20 us
16165 \ BEGIN \ 3 cycles loop + 6~
16166 \ \ MOV #5,W \ 3 MCLK = 1 MHz
16167 \ \ MOV #23,W \ 3 MCLK = 4 MHz
16168 \ \ MOV #51,W \ 3 MCLK = 8 MHz
16169 \ MOV #104,W \ 3 MCLK = 16 MHz
16170 \ \ MOV #158,W \ 3 MCLK = 24 MHz
16171 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
16176 \ MOV @PSP+,TOS \ 2
16181 CODE 20_US \ n -- n * 20 us
16182 BEGIN \ here we presume that LCD_TIM_IFG = 1...
16184 BIT #1,&LCD_TIM_CTL \ 3
16185 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
16186 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
16188 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
16194 CODE TOP_LCD \ LCD Sample
16195 \ \ if write : %xxxxWWWW --
16196 \ \ if read : -- %0000RRRR
16197 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
16198 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
16199 0= IF \ write LCD bits pattern
16200 AND.B #LCD_DB,TOS \
16201 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
16202 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
16205 THEN \ read LCD bits pattern
16208 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
16209 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
16210 AND.B #LCD_DB,TOS \
16215 CODE LCD_W \ byte -- write byte to LCD
16217 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
16218 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
16219 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
16220 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
16221 COLON \ high level word starts here
16222 TOP_LCD 2 20_US \ write high nibble first
16227 CODE LCD_WrC \ char -- Write Char
16228 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
16233 CODE LCD_WrF \ func -- Write Fonction
16234 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
16240 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
16245 $02 LCD_WrF 100 20_us
16249 [UNDEFINED] OR [IF]
16251 \ https://forth-standard.org/standard/core/OR
16252 \ C OR x1 x2 -- x3 logical OR
16261 : LCD_Entry_set $04 OR LCD_WrF ;
16263 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
16265 : LCD_DSP_Shift $10 OR LCD_WrF ;
16267 : LCD_Fn_Set $20 OR LCD_WrF ;
16269 : LCD_CGRAM_Set $40 OR LCD_WrF ;
16271 : LCD_Goto $80 OR LCD_WrF ;
16273 CODE LCD_R \ -- byte read byte from LCD
16274 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
16275 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
16276 COLON \ starts a FORTH word
16277 TOP_LCD 2 20_us \ -- %0000HHHH
16278 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
16279 HI2LO \ switch from FORTH to assembler
16280 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
16281 ADD.B @PSP+,TOS \ -- %HHHHLLLL
16282 MOV @RSP+,IP \ restore IP saved by COLON
16287 CODE LCD_RdS \ -- status Read Status
16288 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
16293 CODE LCD_RdC \ -- char Read Char
16294 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
16300 \ ******************************\
16301 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
16302 \ ******************************\
16303 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
16304 BIT.B #SW2,&SW2_IN \ test switch S2
16305 0= IF \ case of switch S2 pressed
16306 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
16308 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
16311 BIT.B #SW1,&SW1_IN \ test switch S1 input
16312 0= IF \ case of Switch S1 pressed
16313 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
16315 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
16319 BW1 \ from quit on truncated RC5 message
16320 BW2 \ from repeated RC5 command
16321 BW3 \ from end of RC5_INT
16322 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
16327 \ ******************************\
16328 ASM RC5_INT \ wake up on Px.RC5 change interrupt
16329 \ ******************************\
16330 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
16331 \ ******************************\
16332 \ \ in : SR(9)=old Toggle bit memory (ADD on)
16333 \ \ SMclock = 8|16|24 MHz
16334 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
16335 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
16336 \ \ SR(9)=new Toggle bit memory (ADD on)
16337 \ ******************************\
16338 \ RC5_FirstStartBitHalfCycle: \
16339 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
16340 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
16341 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
16342 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
16343 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
16344 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
16345 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
16346 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
16347 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
16348 MOV #1778,X \ RC5_Period * 1us
16349 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
16350 MOV #14,W \ count of loop
16352 \ ******************************\
16353 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
16354 \ ******************************\ |
16355 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
16356 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
16357 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
16358 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
16359 \ RC5_Compute_3/4_Period: \ |
16360 RRUM #1,X \ X=1/2 cycle |
16363 ADD X,Y \ Y=3/4 cycle
16364 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
16366 \ ******************************\
16367 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
16368 \ ******************************\
16369 BIT.B #RC5,&IR_IN \ C_flag = IR bit
16370 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
16371 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
16372 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
16373 SUB #1,W \ decrement count loop
16374 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
16375 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
16376 0<> WHILE \ ----> out of loop ----+
16377 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
16379 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
16380 CMP Y,X \ 1 | cycle time out of bound ?
16381 U>= IF \ 2 ^ | yes:
16382 BIC #$30,&RC5_TIM_CTL \ | | stop timer
16383 GOTO BW1 \ | | quit on truncated RC5 message
16385 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
16387 REPEAT \ ----> loop back --+ | with X = new RC5_period value
16388 \ ******************************\ |
16389 \ RC5_SampleEndOf: \ <---------------------+
16390 \ ******************************\
16391 BIC #$30,&RC5_TIM_CTL \ stop timer
16392 \ ******************************\
16393 \ RC5_ComputeNewRC5word \
16394 \ ******************************\
16395 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
16396 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
16397 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
16398 \ ******************************\
16399 \ RC5_ComputeC6bit \
16400 \ ******************************\
16401 BIT #BIT14,T \ test /C6 bit in T
16402 0= IF BIS #BIT6,X \ set C6 bit in X
16403 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
16404 \ ******************************\
16405 \ RC5_CommandByteIsDone \ -- BASE RC5_code
16406 \ ******************************\
16407 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
16408 \ ******************************\
16409 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
16410 XOR @RSP,T \ (new XOR old) Toggle bits
16411 BIT #UF10,T \ repeated RC5_command ?
16412 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
16413 XOR #UF10,0(RSP) \ 5 toggle bit memory
16414 \ ******************************\
16415 \ Display IR_RC5 code \ X = RC5 code
16416 \ ******************************\
16418 MOV &BASE,2(PSP) \ save current base
16419 MOV #$10,&BASE \ set hex base
16420 MOV TOS,0(PSP) \ save TOS
16422 LO2HI \ switch from assembler to FORTH
16423 ['] LCD_CLEAR IS CR \ redirects CR
16424 ['] LCD_WrC IS EMIT \ redirects EMIT
16425 CR ." $" 2 U.R \ print IR_RC5 code
16426 ['] CR >BODY IS CR \ restore CR
16427 ['] EMIT >BODY IS EMIT \ restore EMIT
16428 HI2LO \ switch from FORTH to assembler
16429 MOV TOS,&BASE \ restore current BASE
16431 \ ******************************\
16433 \ ******************************\
16437 \ ------------------------------\
16439 \ ------------------------------\
16440 \ ... \ insert here your background task
16443 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
16444 ADD #4,X \ 1 X = BODY of SLEEP
16447 \ ------------------------------\
16451 \ ------------------------------\
16452 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
16453 \ - - \CNTL Counter lentgh \ 00 = 16 bits
16454 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
16455 \ -- \ID input divider \ 10 = /4
16456 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
16457 \ - \TBCLR TimerB Clear
16460 \ -------------------------------\
16461 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
16462 \ -- \CM Capture Mode
16467 \ --- \OUTMOD \ 011 = set/reset
16473 \ -------------------------------\
16475 \ -------------------------------\
16477 \ ------------------------------\
16478 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
16479 \ ------------------------------\
16480 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
16481 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
16482 \ ------------------------------\
16483 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
16484 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
16485 \ ------------------------------\
16486 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
16487 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
16488 \ ------------------------------\
16489 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
16490 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
16491 \ ------------------------------\
16492 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
16493 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
16494 \ ------------------------------\
16495 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
16496 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
16497 \ ------------------------------\
16498 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
16499 \ ------------------------------\
16500 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
16501 \ ------------------------------\
16502 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
16503 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
16504 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
16505 \ ------------------------------\
16506 BIS.B #LCDVo,&LCDVo_DIR \
16507 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
16508 \ ------------------------------\
16509 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
16510 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
16511 \ ------------------------------\
16512 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
16513 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
16514 \ ******************************\
16516 \ ******************************\
16517 BIS.B #RC5,&IR_IE \ enable RC5_Int
16518 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
16519 MOV #RC5_INT,&IR_Vec \ init interrupt vector
16520 \ ******************************\
16521 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
16522 \ ******************************\
16523 \ %01 0001 0100 \ TAxCTL
16524 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
16525 \ -- \ ID divided by 1
16526 \ -- \ MC MODE = up to TAxCCRn
16527 \ - \ TACLR clear timer count
16530 \ ------------------------------\
16531 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
16532 \ ------------------------------\
16534 \ --- \ TAIDEX pre divisor
16535 \ ------------------------------\
16536 \ %0000 0000 0000 0101 \ TAxCCR0
16537 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
16538 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
16539 \ ------------------------------\
16540 \ %0000 0000 0001 0000 \ TAxCCTL0
16541 \ - \ CAP capture/compare mode = compare
16544 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
16545 \ ------------------------------\
16546 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
16547 \ ------------------------------\
16548 \ define LPM mode for ACCEPT \
16549 \ ------------------------------\
16550 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
16551 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
16552 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
16554 \ ------------------------------\
16555 \ redirects to background task \
16556 \ ------------------------------\
16558 MOV #BACKGROUND,2(X) \
16559 \ ------------------------------\
16561 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
16563 \ ------------------------------\
16565 \ ------------------------------\
16566 $03E8 20_US \ 1- wait 20 ms
16567 $03 TOP_LCD \ 2- send DB5=DB4=1
16568 $CD 20_US \ 3- wait 4,1 ms
16569 $03 TOP_LCD \ 4- send again DB5=DB4=1
16570 $5 20_US \ 5- wait 0,1 ms
16571 $03 TOP_LCD \ 6- send again again DB5=DB4=1
16572 $2 20_US \ wait 40 us = LCD cycle
16573 $02 TOP_LCD \ 7- send DB5=1 DB4=0
16574 $2 20_US \ wait 40 us = LCD cycle
16575 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
16576 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
16577 LCD_Clear \ 10- "LCD_Clear"
16578 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
16579 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
16580 LCD_Clear \ 10- "LCD_Clear"
16581 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
16582 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
16584 ['] CR >BODY IS CR \
16585 ['] EMIT >BODY IS EMIT \
16586 ." RC5toLCD is running. Type STOP to quit"
16587 LIT RECURSE IS WARM \ replace WARM by this START routine
16588 ABORT \ and continue with the next word after WARM...
16589 ; \ ...until interpreter falls in sleep mode within ACCEPT.
16592 CODE STOP \ stops multitasking, must to be used before downloading app
16593 \ restore default action of primary DEFERred word SLEEP, assembly version
16594 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
16595 ADD #4,X \ X = BODY of SLEEP
16596 MOV X,-2(X) \ restore the default background
16599 \ restore default action of primary DEFERred word WARM, FORTH version
16600 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
16602 COLD \ because we want to reset CPU and interrupt vectors
16607 ; downloading RC5toLCD.4th is done
16608 RST_HERE ; this app is protected against <reset>
16616 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
16618 [DEFINED] ASM [IF] \ security test
16622 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
16624 CODE MAX \ n1 n2 -- n3 signed maximum
16625 CMP @PSP,TOS \ n2-n1
16626 S< ?GOTO FW1 \ n2<n1
16632 CODE MIN \ n1 n2 -- n3 signed minimum
16633 CMP @PSP,TOS \ n2-n1
16634 S< ?GOTO BW1 \ n2<n1
16642 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
16643 : U.R \ u n -- display u unsigned in n width (n >= 2)
16645 R> OVER - 0 MAX SPACES TYPE
16650 \ CODE 20_US \ n -- n * 20 us
16651 \ BEGIN \ 3 cycles loop + 6~
16652 \ \ MOV #5,W \ 3 MCLK = 1 MHz
16653 \ \ MOV #23,W \ 3 MCLK = 4 MHz
16654 \ \ MOV #51,W \ 3 MCLK = 8 MHz
16655 \ MOV #104,W \ 3 MCLK = 16 MHz
16656 \ \ MOV #158,W \ 3 MCLK = 24 MHz
16657 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
16662 \ MOV @PSP+,TOS \ 2
16667 CODE 20_US \ n -- n * 20 us
16668 BEGIN \ here we presume that LCD_TIM_IFG = 1...
16670 BIT #1,&LCD_TIM_CTL \ 3
16671 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
16672 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
16674 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
16680 CODE TOP_LCD \ LCD Sample
16681 \ \ if write : %xxxxWWWW --
16682 \ \ if read : -- %0000RRRR
16683 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
16684 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
16685 0= IF \ write LCD bits pattern
16686 AND.B #LCD_DB,TOS \
16687 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
16688 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
16691 THEN \ read LCD bits pattern
16694 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
16695 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
16696 AND.B #LCD_DB,TOS \
16701 CODE LCD_W \ byte -- write byte to LCD
16703 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
16704 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
16705 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
16706 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
16707 COLON \ high level word starts here
16708 TOP_LCD 2 20_US \ write high nibble first
16713 CODE LCD_WrC \ char -- Write Char
16714 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
16719 CODE LCD_WrF \ func -- Write Fonction
16720 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
16726 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
16731 $02 LCD_WrF 100 20_us
16735 [UNDEFINED] OR [IF]
16737 \ https://forth-standard.org/standard/core/OR
16738 \ C OR x1 x2 -- x3 logical OR
16747 : LCD_Entry_set $04 OR LCD_WrF ;
16749 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
16751 : LCD_DSP_Shift $10 OR LCD_WrF ;
16753 : LCD_Fn_Set $20 OR LCD_WrF ;
16755 : LCD_CGRAM_Set $40 OR LCD_WrF ;
16757 : LCD_Goto $80 OR LCD_WrF ;
16759 CODE LCD_R \ -- byte read byte from LCD
16760 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
16761 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
16762 COLON \ starts a FORTH word
16763 TOP_LCD 2 20_us \ -- %0000HHHH
16764 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
16765 HI2LO \ switch from FORTH to assembler
16766 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
16767 ADD.B @PSP+,TOS \ -- %HHHHLLLL
16768 MOV @RSP+,IP \ restore IP saved by COLON
16773 CODE LCD_RdS \ -- status Read Status
16774 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
16779 CODE LCD_RdC \ -- char Read Char
16780 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
16786 \ ******************************\
16787 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
16788 \ ******************************\
16789 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
16790 BIT.B #SW2,&SW2_IN \ test switch S2
16791 0= IF \ case of switch S2 pressed
16792 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
16794 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
16797 BIT.B #SW1,&SW1_IN \ test switch S1 input
16798 0= IF \ case of Switch S1 pressed
16799 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
16801 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
16805 BW1 \ from quit on truncated RC5 message
16806 BW2 \ from repeated RC5 command
16807 BW3 \ from end of RC5_INT
16808 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
16813 \ ******************************\
16814 ASM RC5_INT \ wake up on Px.RC5 change interrupt
16815 \ ******************************\
16816 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
16817 \ ******************************\
16818 \ \ in : SR(9)=old Toggle bit memory (ADD on)
16819 \ \ SMclock = 8|16|24 MHz
16820 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
16821 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
16822 \ \ SR(9)=new Toggle bit memory (ADD on)
16823 \ ******************************\
16824 \ RC5_FirstStartBitHalfCycle: \
16825 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
16826 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
16827 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
16828 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
16829 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
16830 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
16831 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
16832 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
16833 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
16834 MOV #1778,X \ RC5_Period * 1us
16835 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
16836 MOV #14,W \ count of loop
16838 \ ******************************\
16839 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
16840 \ ******************************\ |
16841 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
16842 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
16843 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
16844 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
16845 \ RC5_Compute_3/4_Period: \ |
16846 RRUM #1,X \ X=1/2 cycle |
16849 ADD X,Y \ Y=3/4 cycle
16850 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
16852 \ ******************************\
16853 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
16854 \ ******************************\
16855 BIT.B #RC5,&IR_IN \ C_flag = IR bit
16856 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
16857 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
16858 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
16859 SUB #1,W \ decrement count loop
16860 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
16861 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
16862 0<> WHILE \ ----> out of loop ----+
16863 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
16865 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
16866 CMP Y,X \ 1 | cycle time out of bound ?
16867 U>= IF \ 2 ^ | yes:
16868 BIC #$30,&RC5_TIM_CTL \ | | stop timer
16869 GOTO BW1 \ | | quit on truncated RC5 message
16871 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
16873 REPEAT \ ----> loop back --+ | with X = new RC5_period value
16874 \ ******************************\ |
16875 \ RC5_SampleEndOf: \ <---------------------+
16876 \ ******************************\
16877 BIC #$30,&RC5_TIM_CTL \ stop timer
16878 \ ******************************\
16879 \ RC5_ComputeNewRC5word \
16880 \ ******************************\
16881 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
16882 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
16883 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
16884 \ ******************************\
16885 \ RC5_ComputeC6bit \
16886 \ ******************************\
16887 BIT #BIT14,T \ test /C6 bit in T
16888 0= IF BIS #BIT6,X \ set C6 bit in X
16889 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
16890 \ ******************************\
16891 \ RC5_CommandByteIsDone \ -- BASE RC5_code
16892 \ ******************************\
16893 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
16894 \ ******************************\
16895 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
16896 XOR @RSP,T \ (new XOR old) Toggle bits
16897 BIT #UF10,T \ repeated RC5_command ?
16898 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
16899 XOR #UF10,0(RSP) \ 5 toggle bit memory
16900 \ ******************************\
16901 \ Display IR_RC5 code \ X = RC5 code
16902 \ ******************************\
16904 MOV &BASE,2(PSP) \ save current base
16905 MOV #$10,&BASE \ set hex base
16906 MOV TOS,0(PSP) \ save TOS
16908 LO2HI \ switch from assembler to FORTH
16909 ['] LCD_CLEAR IS CR \ redirects CR
16910 ['] LCD_WrC IS EMIT \ redirects EMIT
16911 CR ." $" 2 U.R \ print IR_RC5 code
16912 ['] CR >BODY IS CR \ restore CR
16913 ['] EMIT >BODY IS EMIT \ restore EMIT
16914 HI2LO \ switch from FORTH to assembler
16915 MOV TOS,&BASE \ restore current BASE
16917 \ ******************************\
16919 \ ******************************\
16923 \ ------------------------------\
16925 \ ------------------------------\
16926 \ ... \ insert here your background task
16929 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
16930 ADD #4,X \ 1 X = BODY of SLEEP
16933 \ ------------------------------\
16937 \ ------------------------------\
16938 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
16939 \ - - \CNTL Counter lentgh \ 00 = 16 bits
16940 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
16941 \ -- \ID input divider \ 10 = /4
16942 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
16943 \ - \TBCLR TimerB Clear
16946 \ -------------------------------\
16947 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
16948 \ -- \CM Capture Mode
16953 \ --- \OUTMOD \ 011 = set/reset
16959 \ -------------------------------\
16961 \ -------------------------------\
16963 \ ------------------------------\
16964 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
16965 \ ------------------------------\
16966 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
16967 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
16968 \ ------------------------------\
16969 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
16970 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
16971 \ ------------------------------\
16972 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
16973 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
16974 \ ------------------------------\
16975 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
16976 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
16977 \ ------------------------------\
16978 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
16979 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
16980 \ ------------------------------\
16981 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
16982 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
16983 \ ------------------------------\
16984 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
16985 \ ------------------------------\
16986 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
16987 \ ------------------------------\
16988 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
16989 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
16990 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
16991 \ ------------------------------\
16992 BIS.B #LCDVo,&LCDVo_DIR \
16993 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
16994 \ ------------------------------\
16995 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
16996 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
16997 \ ------------------------------\
16998 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
16999 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
17000 \ ******************************\
17002 \ ******************************\
17003 BIS.B #RC5,&IR_IE \ enable RC5_Int
17004 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
17005 MOV #RC5_INT,&IR_Vec \ init interrupt vector
17006 \ ******************************\
17007 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
17008 \ ******************************\
17009 \ %01 0001 0100 \ TAxCTL
17010 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
17011 \ -- \ ID divided by 1
17012 \ -- \ MC MODE = up to TAxCCRn
17013 \ - \ TACLR clear timer count
17016 \ ------------------------------\
17017 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
17018 \ ------------------------------\
17020 \ --- \ TAIDEX pre divisor
17021 \ ------------------------------\
17022 \ %0000 0000 0000 0101 \ TAxCCR0
17023 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
17024 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
17025 \ ------------------------------\
17026 \ %0000 0000 0001 0000 \ TAxCCTL0
17027 \ - \ CAP capture/compare mode = compare
17030 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
17031 \ ------------------------------\
17032 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
17033 \ ------------------------------\
17034 \ define LPM mode for ACCEPT \
17035 \ ------------------------------\
17036 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
17037 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
17038 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
17040 \ ------------------------------\
17041 \ redirects to background task \
17042 \ ------------------------------\
17044 MOV #BACKGROUND,2(X) \
17045 \ ------------------------------\
17047 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
17049 \ ------------------------------\
17051 \ ------------------------------\
17052 $03E8 20_US \ 1- wait 20 ms
17053 $03 TOP_LCD \ 2- send DB5=DB4=1
17054 $CD 20_US \ 3- wait 4,1 ms
17055 $03 TOP_LCD \ 4- send again DB5=DB4=1
17056 $5 20_US \ 5- wait 0,1 ms
17057 $03 TOP_LCD \ 6- send again again DB5=DB4=1
17058 $2 20_US \ wait 40 us = LCD cycle
17059 $02 TOP_LCD \ 7- send DB5=1 DB4=0
17060 $2 20_US \ wait 40 us = LCD cycle
17061 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
17062 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
17063 LCD_Clear \ 10- "LCD_Clear"
17064 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
17065 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
17066 LCD_Clear \ 10- "LCD_Clear"
17067 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
17068 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
17070 ['] CR >BODY IS CR \
17071 ['] EMIT >BODY IS EMIT \
17072 ." RC5toLCD is running. Type STOP to quit"
17073 LIT RECURSE IS WARM \ replace WARM by this START routine
17074 ABORT \ and continue with the next word after WARM...
17075 ; \ ...until interpreter falls in sleep mode within ACCEPT.
17078 CODE STOP \ stops multitasking, must to be used before downloading app
17079 \ restore default action of primary DEFERred word SLEEP, assembly version
17080 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
17081 ADD #4,X \ X = BODY of SLEEP
17082 MOV X,-2(X) \ restore the default background
17085 \ restore default action of primary DEFERred word WARM, FORTH version
17086 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
17088 COLD \ because we want to reset CPU and interrupt vectors
17093 ; downloading RC5toLCD.4th is done
17094 RST_HERE ; this app is protected against <reset>
17102 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
17104 [DEFINED] ASM [IF] \ security test
17108 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
17110 CODE MAX \ n1 n2 -- n3 signed maximum
17111 CMP @PSP,TOS \ n2-n1
17112 S< ?GOTO FW1 \ n2<n1
17118 CODE MIN \ n1 n2 -- n3 signed minimum
17119 CMP @PSP,TOS \ n2-n1
17120 S< ?GOTO BW1 \ n2<n1
17128 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
17129 : U.R \ u n -- display u unsigned in n width (n >= 2)
17131 R> OVER - 0 MAX SPACES TYPE
17136 \ CODE 20_US \ n -- n * 20 us
17137 \ BEGIN \ 3 cycles loop + 6~
17138 \ \ MOV #5,W \ 3 MCLK = 1 MHz
17139 \ \ MOV #23,W \ 3 MCLK = 4 MHz
17140 \ \ MOV #51,W \ 3 MCLK = 8 MHz
17141 \ MOV #104,W \ 3 MCLK = 16 MHz
17142 \ \ MOV #158,W \ 3 MCLK = 24 MHz
17143 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
17148 \ MOV @PSP+,TOS \ 2
17153 CODE 20_US \ n -- n * 20 us
17154 BEGIN \ here we presume that LCD_TIM_IFG = 1...
17156 BIT #1,&LCD_TIM_CTL \ 3
17157 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
17158 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
17160 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
17166 CODE TOP_LCD \ LCD Sample
17167 \ \ if write : %xxxxWWWW --
17168 \ \ if read : -- %0000RRRR
17169 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
17170 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
17171 0= IF \ write LCD bits pattern
17172 AND.B #LCD_DB,TOS \
17173 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
17174 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
17177 THEN \ read LCD bits pattern
17180 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
17181 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
17182 AND.B #LCD_DB,TOS \
17187 CODE LCD_W \ byte -- write byte to LCD
17189 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
17190 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
17191 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
17192 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
17193 COLON \ high level word starts here
17194 TOP_LCD 2 20_US \ write high nibble first
17199 CODE LCD_WrC \ char -- Write Char
17200 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
17205 CODE LCD_WrF \ func -- Write Fonction
17206 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
17212 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
17217 $02 LCD_WrF 100 20_us
17221 [UNDEFINED] OR [IF]
17223 \ https://forth-standard.org/standard/core/OR
17224 \ C OR x1 x2 -- x3 logical OR
17233 : LCD_Entry_set $04 OR LCD_WrF ;
17235 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
17237 : LCD_DSP_Shift $10 OR LCD_WrF ;
17239 : LCD_Fn_Set $20 OR LCD_WrF ;
17241 : LCD_CGRAM_Set $40 OR LCD_WrF ;
17243 : LCD_Goto $80 OR LCD_WrF ;
17245 CODE LCD_R \ -- byte read byte from LCD
17246 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
17247 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
17248 COLON \ starts a FORTH word
17249 TOP_LCD 2 20_us \ -- %0000HHHH
17250 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
17251 HI2LO \ switch from FORTH to assembler
17252 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
17253 ADD.B @PSP+,TOS \ -- %HHHHLLLL
17254 MOV @RSP+,IP \ restore IP saved by COLON
17259 CODE LCD_RdS \ -- status Read Status
17260 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
17265 CODE LCD_RdC \ -- char Read Char
17266 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
17272 \ ******************************\
17273 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
17274 \ ******************************\
17275 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
17276 BIT.B #SW2,&SW2_IN \ test switch S2
17277 0= IF \ case of switch S2 pressed
17278 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
17280 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
17283 BIT.B #SW1,&SW1_IN \ test switch S1 input
17284 0= IF \ case of Switch S1 pressed
17285 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
17287 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
17291 BW1 \ from quit on truncated RC5 message
17292 BW2 \ from repeated RC5 command
17293 BW3 \ from end of RC5_INT
17294 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
17299 \ ******************************\
17300 ASM RC5_INT \ wake up on Px.RC5 change interrupt
17301 \ ******************************\
17302 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
17303 \ ******************************\
17304 \ \ in : SR(9)=old Toggle bit memory (ADD on)
17305 \ \ SMclock = 8|16|24 MHz
17306 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
17307 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
17308 \ \ SR(9)=new Toggle bit memory (ADD on)
17309 \ ******************************\
17310 \ RC5_FirstStartBitHalfCycle: \
17311 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
17312 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
17313 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
17314 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
17315 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
17316 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
17317 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
17318 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
17319 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
17320 MOV #1778,X \ RC5_Period * 1us
17321 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
17322 MOV #14,W \ count of loop
17324 \ ******************************\
17325 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
17326 \ ******************************\ |
17327 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
17328 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
17329 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
17330 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
17331 \ RC5_Compute_3/4_Period: \ |
17332 RRUM #1,X \ X=1/2 cycle |
17335 ADD X,Y \ Y=3/4 cycle
17336 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
17338 \ ******************************\
17339 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
17340 \ ******************************\
17341 BIT.B #RC5,&IR_IN \ C_flag = IR bit
17342 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
17343 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
17344 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
17345 SUB #1,W \ decrement count loop
17346 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
17347 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
17348 0<> WHILE \ ----> out of loop ----+
17349 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
17351 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
17352 CMP Y,X \ 1 | cycle time out of bound ?
17353 U>= IF \ 2 ^ | yes:
17354 BIC #$30,&RC5_TIM_CTL \ | | stop timer
17355 GOTO BW1 \ | | quit on truncated RC5 message
17357 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
17359 REPEAT \ ----> loop back --+ | with X = new RC5_period value
17360 \ ******************************\ |
17361 \ RC5_SampleEndOf: \ <---------------------+
17362 \ ******************************\
17363 BIC #$30,&RC5_TIM_CTL \ stop timer
17364 \ ******************************\
17365 \ RC5_ComputeNewRC5word \
17366 \ ******************************\
17367 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
17368 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
17369 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
17370 \ ******************************\
17371 \ RC5_ComputeC6bit \
17372 \ ******************************\
17373 BIT #BIT14,T \ test /C6 bit in T
17374 0= IF BIS #BIT6,X \ set C6 bit in X
17375 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
17376 \ ******************************\
17377 \ RC5_CommandByteIsDone \ -- BASE RC5_code
17378 \ ******************************\
17379 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
17380 \ ******************************\
17381 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
17382 XOR @RSP,T \ (new XOR old) Toggle bits
17383 BIT #UF10,T \ repeated RC5_command ?
17384 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
17385 XOR #UF10,0(RSP) \ 5 toggle bit memory
17386 \ ******************************\
17387 \ Display IR_RC5 code \ X = RC5 code
17388 \ ******************************\
17390 MOV &BASE,2(PSP) \ save current base
17391 MOV #$10,&BASE \ set hex base
17392 MOV TOS,0(PSP) \ save TOS
17394 LO2HI \ switch from assembler to FORTH
17395 ['] LCD_CLEAR IS CR \ redirects CR
17396 ['] LCD_WrC IS EMIT \ redirects EMIT
17397 CR ." $" 2 U.R \ print IR_RC5 code
17398 ['] CR >BODY IS CR \ restore CR
17399 ['] EMIT >BODY IS EMIT \ restore EMIT
17400 HI2LO \ switch from FORTH to assembler
17401 MOV TOS,&BASE \ restore current BASE
17403 \ ******************************\
17405 \ ******************************\
17409 \ ------------------------------\
17411 \ ------------------------------\
17412 \ ... \ insert here your background task
17415 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
17416 ADD #4,X \ 1 X = BODY of SLEEP
17419 \ ------------------------------\
17423 \ ------------------------------\
17424 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
17425 \ - - \CNTL Counter lentgh \ 00 = 16 bits
17426 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
17427 \ -- \ID input divider \ 10 = /4
17428 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
17429 \ - \TBCLR TimerB Clear
17432 \ -------------------------------\
17433 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
17434 \ -- \CM Capture Mode
17439 \ --- \OUTMOD \ 011 = set/reset
17445 \ -------------------------------\
17447 \ -------------------------------\
17449 \ ------------------------------\
17450 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
17451 \ ------------------------------\
17452 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
17453 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
17454 \ ------------------------------\
17455 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
17456 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
17457 \ ------------------------------\
17458 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
17459 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
17460 \ ------------------------------\
17461 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
17462 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
17463 \ ------------------------------\
17464 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
17465 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
17466 \ ------------------------------\
17467 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
17468 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
17469 \ ------------------------------\
17470 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
17471 \ ------------------------------\
17472 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
17473 \ ------------------------------\
17474 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
17475 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
17476 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
17477 \ ------------------------------\
17478 BIS.B #LCDVo,&LCDVo_DIR \
17479 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
17480 \ ------------------------------\
17481 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
17482 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
17483 \ ------------------------------\
17484 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
17485 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
17486 \ ******************************\
17488 \ ******************************\
17489 BIS.B #RC5,&IR_IE \ enable RC5_Int
17490 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
17491 MOV #RC5_INT,&IR_Vec \ init interrupt vector
17492 \ ******************************\
17493 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
17494 \ ******************************\
17495 \ %01 0001 0100 \ TAxCTL
17496 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
17497 \ -- \ ID divided by 1
17498 \ -- \ MC MODE = up to TAxCCRn
17499 \ - \ TACLR clear timer count
17502 \ ------------------------------\
17503 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
17504 \ ------------------------------\
17506 \ --- \ TAIDEX pre divisor
17507 \ ------------------------------\
17508 \ %0000 0000 0000 0101 \ TAxCCR0
17509 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
17510 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
17511 \ ------------------------------\
17512 \ %0000 0000 0001 0000 \ TAxCCTL0
17513 \ - \ CAP capture/compare mode = compare
17516 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
17517 \ ------------------------------\
17518 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
17519 \ ------------------------------\
17520 \ define LPM mode for ACCEPT \
17521 \ ------------------------------\
17522 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
17523 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
17524 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
17526 \ ------------------------------\
17527 \ redirects to background task \
17528 \ ------------------------------\
17530 MOV #BACKGROUND,2(X) \
17531 \ ------------------------------\
17533 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
17535 \ ------------------------------\
17537 \ ------------------------------\
17538 $03E8 20_US \ 1- wait 20 ms
17539 $03 TOP_LCD \ 2- send DB5=DB4=1
17540 $CD 20_US \ 3- wait 4,1 ms
17541 $03 TOP_LCD \ 4- send again DB5=DB4=1
17542 $5 20_US \ 5- wait 0,1 ms
17543 $03 TOP_LCD \ 6- send again again DB5=DB4=1
17544 $2 20_US \ wait 40 us = LCD cycle
17545 $02 TOP_LCD \ 7- send DB5=1 DB4=0
17546 $2 20_US \ wait 40 us = LCD cycle
17547 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
17548 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
17549 LCD_Clear \ 10- "LCD_Clear"
17550 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
17551 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
17552 LCD_Clear \ 10- "LCD_Clear"
17553 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
17554 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
17556 ['] CR >BODY IS CR \
17557 ['] EMIT >BODY IS EMIT \
17558 ." RC5toLCD is running. Type STOP to quit"
17559 LIT RECURSE IS WARM \ replace WARM by this START routine
17560 ABORT \ and continue with the next word after WARM...
17561 ; \ ...until interpreter falls in sleep mode within ACCEPT.
17564 CODE STOP \ stops multitasking, must to be used before downloading app
17565 \ restore default action of primary DEFERred word SLEEP, assembly version
17566 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
17567 ADD #4,X \ X = BODY of SLEEP
17568 MOV X,-2(X) \ restore the default background
17571 \ restore default action of primary DEFERred word WARM, FORTH version
17572 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
17574 COLD \ because we want to reset CPU and interrupt vectors
17579 ; downloading RC5toLCD.4th is done
17580 RST_HERE ; this app is protected against <reset>
17588 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
17590 [DEFINED] ASM [IF] \ security test
17594 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
17596 CODE MAX \ n1 n2 -- n3 signed maximum
17597 CMP @PSP,TOS \ n2-n1
17598 S< ?GOTO FW1 \ n2<n1
17604 CODE MIN \ n1 n2 -- n3 signed minimum
17605 CMP @PSP,TOS \ n2-n1
17606 S< ?GOTO BW1 \ n2<n1
17614 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
17615 : U.R \ u n -- display u unsigned in n width (n >= 2)
17617 R> OVER - 0 MAX SPACES TYPE
17622 \ CODE 20_US \ n -- n * 20 us
17623 \ BEGIN \ 3 cycles loop + 6~
17624 \ \ MOV #5,W \ 3 MCLK = 1 MHz
17625 \ \ MOV #23,W \ 3 MCLK = 4 MHz
17626 \ \ MOV #51,W \ 3 MCLK = 8 MHz
17627 \ MOV #104,W \ 3 MCLK = 16 MHz
17628 \ \ MOV #158,W \ 3 MCLK = 24 MHz
17629 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
17634 \ MOV @PSP+,TOS \ 2
17639 CODE 20_US \ n -- n * 20 us
17640 BEGIN \ here we presume that LCD_TIM_IFG = 1...
17642 BIT #1,&LCD_TIM_CTL \ 3
17643 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
17644 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
17646 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
17652 CODE TOP_LCD \ LCD Sample
17653 \ \ if write : %xxxxWWWW --
17654 \ \ if read : -- %0000RRRR
17655 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
17656 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
17657 0= IF \ write LCD bits pattern
17658 AND.B #LCD_DB,TOS \
17659 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
17660 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
17663 THEN \ read LCD bits pattern
17666 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
17667 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
17668 AND.B #LCD_DB,TOS \
17673 CODE LCD_W \ byte -- write byte to LCD
17675 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
17676 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
17677 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
17678 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
17679 COLON \ high level word starts here
17680 TOP_LCD 2 20_US \ write high nibble first
17685 CODE LCD_WrC \ char -- Write Char
17686 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
17691 CODE LCD_WrF \ func -- Write Fonction
17692 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
17698 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
17703 $02 LCD_WrF 100 20_us
17707 [UNDEFINED] OR [IF]
17709 \ https://forth-standard.org/standard/core/OR
17710 \ C OR x1 x2 -- x3 logical OR
17719 : LCD_Entry_set $04 OR LCD_WrF ;
17721 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
17723 : LCD_DSP_Shift $10 OR LCD_WrF ;
17725 : LCD_Fn_Set $20 OR LCD_WrF ;
17727 : LCD_CGRAM_Set $40 OR LCD_WrF ;
17729 : LCD_Goto $80 OR LCD_WrF ;
17731 CODE LCD_R \ -- byte read byte from LCD
17732 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
17733 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
17734 COLON \ starts a FORTH word
17735 TOP_LCD 2 20_us \ -- %0000HHHH
17736 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
17737 HI2LO \ switch from FORTH to assembler
17738 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
17739 ADD.B @PSP+,TOS \ -- %HHHHLLLL
17740 MOV @RSP+,IP \ restore IP saved by COLON
17745 CODE LCD_RdS \ -- status Read Status
17746 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
17751 CODE LCD_RdC \ -- char Read Char
17752 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
17758 \ ******************************\
17759 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
17760 \ ******************************\
17761 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
17762 BIT.B #SW2,&SW2_IN \ test switch S2
17763 0= IF \ case of switch S2 pressed
17764 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
17766 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
17769 BIT.B #SW1,&SW1_IN \ test switch S1 input
17770 0= IF \ case of Switch S1 pressed
17771 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
17773 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
17777 BW1 \ from quit on truncated RC5 message
17778 BW2 \ from repeated RC5 command
17779 BW3 \ from end of RC5_INT
17780 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
17785 \ ******************************\
17786 ASM RC5_INT \ wake up on Px.RC5 change interrupt
17787 \ ******************************\
17788 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
17789 \ ******************************\
17790 \ \ in : SR(9)=old Toggle bit memory (ADD on)
17791 \ \ SMclock = 8|16|24 MHz
17792 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
17793 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
17794 \ \ SR(9)=new Toggle bit memory (ADD on)
17795 \ ******************************\
17796 \ RC5_FirstStartBitHalfCycle: \
17797 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
17798 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
17799 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
17800 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
17801 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
17802 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
17803 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
17804 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
17805 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
17806 MOV #1778,X \ RC5_Period * 1us
17807 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
17808 MOV #14,W \ count of loop
17810 \ ******************************\
17811 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
17812 \ ******************************\ |
17813 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
17814 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
17815 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
17816 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
17817 \ RC5_Compute_3/4_Period: \ |
17818 RRUM #1,X \ X=1/2 cycle |
17821 ADD X,Y \ Y=3/4 cycle
17822 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
17824 \ ******************************\
17825 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
17826 \ ******************************\
17827 BIT.B #RC5,&IR_IN \ C_flag = IR bit
17828 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
17829 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
17830 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
17831 SUB #1,W \ decrement count loop
17832 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
17833 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
17834 0<> WHILE \ ----> out of loop ----+
17835 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
17837 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
17838 CMP Y,X \ 1 | cycle time out of bound ?
17839 U>= IF \ 2 ^ | yes:
17840 BIC #$30,&RC5_TIM_CTL \ | | stop timer
17841 GOTO BW1 \ | | quit on truncated RC5 message
17843 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
17845 REPEAT \ ----> loop back --+ | with X = new RC5_period value
17846 \ ******************************\ |
17847 \ RC5_SampleEndOf: \ <---------------------+
17848 \ ******************************\
17849 BIC #$30,&RC5_TIM_CTL \ stop timer
17850 \ ******************************\
17851 \ RC5_ComputeNewRC5word \
17852 \ ******************************\
17853 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
17854 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
17855 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
17856 \ ******************************\
17857 \ RC5_ComputeC6bit \
17858 \ ******************************\
17859 BIT #BIT14,T \ test /C6 bit in T
17860 0= IF BIS #BIT6,X \ set C6 bit in X
17861 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
17862 \ ******************************\
17863 \ RC5_CommandByteIsDone \ -- BASE RC5_code
17864 \ ******************************\
17865 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
17866 \ ******************************\
17867 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
17868 XOR @RSP,T \ (new XOR old) Toggle bits
17869 BIT #UF10,T \ repeated RC5_command ?
17870 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
17871 XOR #UF10,0(RSP) \ 5 toggle bit memory
17872 \ ******************************\
17873 \ Display IR_RC5 code \ X = RC5 code
17874 \ ******************************\
17876 MOV &BASE,2(PSP) \ save current base
17877 MOV #$10,&BASE \ set hex base
17878 MOV TOS,0(PSP) \ save TOS
17880 LO2HI \ switch from assembler to FORTH
17881 ['] LCD_CLEAR IS CR \ redirects CR
17882 ['] LCD_WrC IS EMIT \ redirects EMIT
17883 CR ." $" 2 U.R \ print IR_RC5 code
17884 ['] CR >BODY IS CR \ restore CR
17885 ['] EMIT >BODY IS EMIT \ restore EMIT
17886 HI2LO \ switch from FORTH to assembler
17887 MOV TOS,&BASE \ restore current BASE
17889 \ ******************************\
17891 \ ******************************\
17895 \ ------------------------------\
17897 \ ------------------------------\
17898 \ ... \ insert here your background task
17901 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
17902 ADD #4,X \ 1 X = BODY of SLEEP
17905 \ ------------------------------\
17909 \ ------------------------------\
17910 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
17911 \ - - \CNTL Counter lentgh \ 00 = 16 bits
17912 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
17913 \ -- \ID input divider \ 10 = /4
17914 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
17915 \ - \TBCLR TimerB Clear
17918 \ -------------------------------\
17919 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
17920 \ -- \CM Capture Mode
17925 \ --- \OUTMOD \ 011 = set/reset
17931 \ -------------------------------\
17933 \ -------------------------------\
17935 \ ------------------------------\
17936 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
17937 \ ------------------------------\
17938 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
17939 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
17940 \ ------------------------------\
17941 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
17942 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
17943 \ ------------------------------\
17944 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
17945 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
17946 \ ------------------------------\
17947 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
17948 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
17949 \ ------------------------------\
17950 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
17951 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
17952 \ ------------------------------\
17953 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
17954 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
17955 \ ------------------------------\
17956 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
17957 \ ------------------------------\
17958 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
17959 \ ------------------------------\
17960 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
17961 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
17962 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
17963 \ ------------------------------\
17964 BIS.B #LCDVo,&LCDVo_DIR \
17965 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
17966 \ ------------------------------\
17967 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
17968 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
17969 \ ------------------------------\
17970 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
17971 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
17972 \ ******************************\
17974 \ ******************************\
17975 BIS.B #RC5,&IR_IE \ enable RC5_Int
17976 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
17977 MOV #RC5_INT,&IR_Vec \ init interrupt vector
17978 \ ******************************\
17979 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
17980 \ ******************************\
17981 \ %01 0001 0100 \ TAxCTL
17982 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
17983 \ -- \ ID divided by 1
17984 \ -- \ MC MODE = up to TAxCCRn
17985 \ - \ TACLR clear timer count
17988 \ ------------------------------\
17989 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
17990 \ ------------------------------\
17992 \ --- \ TAIDEX pre divisor
17993 \ ------------------------------\
17994 \ %0000 0000 0000 0101 \ TAxCCR0
17995 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
17996 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
17997 \ ------------------------------\
17998 \ %0000 0000 0001 0000 \ TAxCCTL0
17999 \ - \ CAP capture/compare mode = compare
18002 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
18003 \ ------------------------------\
18004 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
18005 \ ------------------------------\
18006 \ define LPM mode for ACCEPT \
18007 \ ------------------------------\
18008 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
18009 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
18010 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
18012 \ ------------------------------\
18013 \ redirects to background task \
18014 \ ------------------------------\
18016 MOV #BACKGROUND,2(X) \
18017 \ ------------------------------\
18019 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
18021 \ ------------------------------\
18023 \ ------------------------------\
18024 $03E8 20_US \ 1- wait 20 ms
18025 $03 TOP_LCD \ 2- send DB5=DB4=1
18026 $CD 20_US \ 3- wait 4,1 ms
18027 $03 TOP_LCD \ 4- send again DB5=DB4=1
18028 $5 20_US \ 5- wait 0,1 ms
18029 $03 TOP_LCD \ 6- send again again DB5=DB4=1
18030 $2 20_US \ wait 40 us = LCD cycle
18031 $02 TOP_LCD \ 7- send DB5=1 DB4=0
18032 $2 20_US \ wait 40 us = LCD cycle
18033 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
18034 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
18035 LCD_Clear \ 10- "LCD_Clear"
18036 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
18037 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
18038 LCD_Clear \ 10- "LCD_Clear"
18039 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
18040 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
18042 ['] CR >BODY IS CR \
18043 ['] EMIT >BODY IS EMIT \
18044 ." RC5toLCD is running. Type STOP to quit"
18045 LIT RECURSE IS WARM \ replace WARM by this START routine
18046 ABORT \ and continue with the next word after WARM...
18047 ; \ ...until interpreter falls in sleep mode within ACCEPT.
18050 CODE STOP \ stops multitasking, must to be used before downloading app
18051 \ restore default action of primary DEFERred word SLEEP, assembly version
18052 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
18053 ADD #4,X \ X = BODY of SLEEP
18054 MOV X,-2(X) \ restore the default background
18057 \ restore default action of primary DEFERred word WARM, FORTH version
18058 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
18060 COLD \ because we want to reset CPU and interrupt vectors
18065 ; downloading RC5toLCD.4th is done
18066 RST_HERE ; this app is protected against <reset>
18074 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
18076 [DEFINED] ASM [IF] \ security test
18080 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
18082 CODE MAX \ n1 n2 -- n3 signed maximum
18083 CMP @PSP,TOS \ n2-n1
18084 S< ?GOTO FW1 \ n2<n1
18090 CODE MIN \ n1 n2 -- n3 signed minimum
18091 CMP @PSP,TOS \ n2-n1
18092 S< ?GOTO BW1 \ n2<n1
18100 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
18101 : U.R \ u n -- display u unsigned in n width (n >= 2)
18103 R> OVER - 0 MAX SPACES TYPE
18108 \ CODE 20_US \ n -- n * 20 us
18109 \ BEGIN \ 3 cycles loop + 6~
18110 \ \ MOV #5,W \ 3 MCLK = 1 MHz
18111 \ \ MOV #23,W \ 3 MCLK = 4 MHz
18112 \ \ MOV #51,W \ 3 MCLK = 8 MHz
18113 \ MOV #104,W \ 3 MCLK = 16 MHz
18114 \ \ MOV #158,W \ 3 MCLK = 24 MHz
18115 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
18120 \ MOV @PSP+,TOS \ 2
18125 CODE 20_US \ n -- n * 20 us
18126 BEGIN \ here we presume that LCD_TIM_IFG = 1...
18128 BIT #1,&LCD_TIM_CTL \ 3
18129 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
18130 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
18132 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
18138 CODE TOP_LCD \ LCD Sample
18139 \ \ if write : %xxxxWWWW --
18140 \ \ if read : -- %0000RRRR
18141 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
18142 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
18143 0= IF \ write LCD bits pattern
18144 AND.B #LCD_DB,TOS \
18145 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
18146 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
18149 THEN \ read LCD bits pattern
18152 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
18153 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
18154 AND.B #LCD_DB,TOS \
18159 CODE LCD_W \ byte -- write byte to LCD
18161 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
18162 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
18163 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
18164 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
18165 COLON \ high level word starts here
18166 TOP_LCD 2 20_US \ write high nibble first
18171 CODE LCD_WrC \ char -- Write Char
18172 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
18177 CODE LCD_WrF \ func -- Write Fonction
18178 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
18184 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
18189 $02 LCD_WrF 100 20_us
18193 [UNDEFINED] OR [IF]
18195 \ https://forth-standard.org/standard/core/OR
18196 \ C OR x1 x2 -- x3 logical OR
18205 : LCD_Entry_set $04 OR LCD_WrF ;
18207 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
18209 : LCD_DSP_Shift $10 OR LCD_WrF ;
18211 : LCD_Fn_Set $20 OR LCD_WrF ;
18213 : LCD_CGRAM_Set $40 OR LCD_WrF ;
18215 : LCD_Goto $80 OR LCD_WrF ;
18217 CODE LCD_R \ -- byte read byte from LCD
18218 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
18219 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
18220 COLON \ starts a FORTH word
18221 TOP_LCD 2 20_us \ -- %0000HHHH
18222 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
18223 HI2LO \ switch from FORTH to assembler
18224 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
18225 ADD.B @PSP+,TOS \ -- %HHHHLLLL
18226 MOV @RSP+,IP \ restore IP saved by COLON
18231 CODE LCD_RdS \ -- status Read Status
18232 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
18237 CODE LCD_RdC \ -- char Read Char
18238 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
18244 \ ******************************\
18245 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
18246 \ ******************************\
18247 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
18248 BIT.B #SW2,&SW2_IN \ test switch S2
18249 0= IF \ case of switch S2 pressed
18250 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
18252 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
18255 BIT.B #SW1,&SW1_IN \ test switch S1 input
18256 0= IF \ case of Switch S1 pressed
18257 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
18259 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
18263 BW1 \ from quit on truncated RC5 message
18264 BW2 \ from repeated RC5 command
18265 BW3 \ from end of RC5_INT
18266 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
18271 \ ******************************\
18272 ASM RC5_INT \ wake up on Px.RC5 change interrupt
18273 \ ******************************\
18274 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
18275 \ ******************************\
18276 \ \ in : SR(9)=old Toggle bit memory (ADD on)
18277 \ \ SMclock = 8|16|24 MHz
18278 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
18279 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
18280 \ \ SR(9)=new Toggle bit memory (ADD on)
18281 \ ******************************\
18282 \ RC5_FirstStartBitHalfCycle: \
18283 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
18284 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
18285 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
18286 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
18287 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
18288 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
18289 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
18290 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
18291 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
18292 MOV #1778,X \ RC5_Period * 1us
18293 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
18294 MOV #14,W \ count of loop
18296 \ ******************************\
18297 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
18298 \ ******************************\ |
18299 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
18300 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
18301 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
18302 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
18303 \ RC5_Compute_3/4_Period: \ |
18304 RRUM #1,X \ X=1/2 cycle |
18307 ADD X,Y \ Y=3/4 cycle
18308 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
18310 \ ******************************\
18311 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
18312 \ ******************************\
18313 BIT.B #RC5,&IR_IN \ C_flag = IR bit
18314 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
18315 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
18316 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
18317 SUB #1,W \ decrement count loop
18318 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
18319 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
18320 0<> WHILE \ ----> out of loop ----+
18321 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
18323 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
18324 CMP Y,X \ 1 | cycle time out of bound ?
18325 U>= IF \ 2 ^ | yes:
18326 BIC #$30,&RC5_TIM_CTL \ | | stop timer
18327 GOTO BW1 \ | | quit on truncated RC5 message
18329 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
18331 REPEAT \ ----> loop back --+ | with X = new RC5_period value
18332 \ ******************************\ |
18333 \ RC5_SampleEndOf: \ <---------------------+
18334 \ ******************************\
18335 BIC #$30,&RC5_TIM_CTL \ stop timer
18336 \ ******************************\
18337 \ RC5_ComputeNewRC5word \
18338 \ ******************************\
18339 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
18340 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
18341 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
18342 \ ******************************\
18343 \ RC5_ComputeC6bit \
18344 \ ******************************\
18345 BIT #BIT14,T \ test /C6 bit in T
18346 0= IF BIS #BIT6,X \ set C6 bit in X
18347 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
18348 \ ******************************\
18349 \ RC5_CommandByteIsDone \ -- BASE RC5_code
18350 \ ******************************\
18351 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
18352 \ ******************************\
18353 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
18354 XOR @RSP,T \ (new XOR old) Toggle bits
18355 BIT #UF10,T \ repeated RC5_command ?
18356 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
18357 XOR #UF10,0(RSP) \ 5 toggle bit memory
18358 \ ******************************\
18359 \ Display IR_RC5 code \ X = RC5 code
18360 \ ******************************\
18362 MOV &BASE,2(PSP) \ save current base
18363 MOV #$10,&BASE \ set hex base
18364 MOV TOS,0(PSP) \ save TOS
18366 LO2HI \ switch from assembler to FORTH
18367 ['] LCD_CLEAR IS CR \ redirects CR
18368 ['] LCD_WrC IS EMIT \ redirects EMIT
18369 CR ." $" 2 U.R \ print IR_RC5 code
18370 ['] CR >BODY IS CR \ restore CR
18371 ['] EMIT >BODY IS EMIT \ restore EMIT
18372 HI2LO \ switch from FORTH to assembler
18373 MOV TOS,&BASE \ restore current BASE
18375 \ ******************************\
18377 \ ******************************\
18381 \ ------------------------------\
18383 \ ------------------------------\
18384 \ ... \ insert here your background task
18387 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
18388 ADD #4,X \ 1 X = BODY of SLEEP
18391 \ ------------------------------\
18395 \ ------------------------------\
18396 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
18397 \ - - \CNTL Counter lentgh \ 00 = 16 bits
18398 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
18399 \ -- \ID input divider \ 10 = /4
18400 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
18401 \ - \TBCLR TimerB Clear
18404 \ -------------------------------\
18405 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
18406 \ -- \CM Capture Mode
18411 \ --- \OUTMOD \ 011 = set/reset
18417 \ -------------------------------\
18419 \ -------------------------------\
18421 \ ------------------------------\
18422 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
18423 \ ------------------------------\
18424 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
18425 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
18426 \ ------------------------------\
18427 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
18428 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
18429 \ ------------------------------\
18430 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
18431 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
18432 \ ------------------------------\
18433 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
18434 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
18435 \ ------------------------------\
18436 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
18437 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
18438 \ ------------------------------\
18439 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
18440 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
18441 \ ------------------------------\
18442 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
18443 \ ------------------------------\
18444 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
18445 \ ------------------------------\
18446 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
18447 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
18448 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
18449 \ ------------------------------\
18450 BIS.B #LCDVo,&LCDVo_DIR \
18451 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
18452 \ ------------------------------\
18453 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
18454 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
18455 \ ------------------------------\
18456 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
18457 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
18458 \ ******************************\
18460 \ ******************************\
18461 BIS.B #RC5,&IR_IE \ enable RC5_Int
18462 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
18463 MOV #RC5_INT,&IR_Vec \ init interrupt vector
18464 \ ******************************\
18465 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
18466 \ ******************************\
18467 \ %01 0001 0100 \ TAxCTL
18468 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
18469 \ -- \ ID divided by 1
18470 \ -- \ MC MODE = up to TAxCCRn
18471 \ - \ TACLR clear timer count
18474 \ ------------------------------\
18475 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
18476 \ ------------------------------\
18478 \ --- \ TAIDEX pre divisor
18479 \ ------------------------------\
18480 \ %0000 0000 0000 0101 \ TAxCCR0
18481 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
18482 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
18483 \ ------------------------------\
18484 \ %0000 0000 0001 0000 \ TAxCCTL0
18485 \ - \ CAP capture/compare mode = compare
18488 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
18489 \ ------------------------------\
18490 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
18491 \ ------------------------------\
18492 \ define LPM mode for ACCEPT \
18493 \ ------------------------------\
18494 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
18495 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
18496 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
18498 \ ------------------------------\
18499 \ redirects to background task \
18500 \ ------------------------------\
18502 MOV #BACKGROUND,2(X) \
18503 \ ------------------------------\
18505 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
18507 \ ------------------------------\
18509 \ ------------------------------\
18510 $03E8 20_US \ 1- wait 20 ms
18511 $03 TOP_LCD \ 2- send DB5=DB4=1
18512 $CD 20_US \ 3- wait 4,1 ms
18513 $03 TOP_LCD \ 4- send again DB5=DB4=1
18514 $5 20_US \ 5- wait 0,1 ms
18515 $03 TOP_LCD \ 6- send again again DB5=DB4=1
18516 $2 20_US \ wait 40 us = LCD cycle
18517 $02 TOP_LCD \ 7- send DB5=1 DB4=0
18518 $2 20_US \ wait 40 us = LCD cycle
18519 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
18520 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
18521 LCD_Clear \ 10- "LCD_Clear"
18522 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
18523 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
18524 LCD_Clear \ 10- "LCD_Clear"
18525 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
18526 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
18528 ['] CR >BODY IS CR \
18529 ['] EMIT >BODY IS EMIT \
18530 ." RC5toLCD is running. Type STOP to quit"
18531 LIT RECURSE IS WARM \ replace WARM by this START routine
18532 ABORT \ and continue with the next word after WARM...
18533 ; \ ...until interpreter falls in sleep mode within ACCEPT.
18536 CODE STOP \ stops multitasking, must to be used before downloading app
18537 \ restore default action of primary DEFERred word SLEEP, assembly version
18538 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
18539 ADD #4,X \ X = BODY of SLEEP
18540 MOV X,-2(X) \ restore the default background
18543 \ restore default action of primary DEFERred word WARM, FORTH version
18544 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
18546 COLD \ because we want to reset CPU and interrupt vectors
18551 ; downloading RC5toLCD.4th is done
18552 RST_HERE ; this app is protected against <reset>
18560 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
18562 [DEFINED] ASM [IF] \ security test
18566 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
18568 CODE MAX \ n1 n2 -- n3 signed maximum
18569 CMP @PSP,TOS \ n2-n1
18570 S< ?GOTO FW1 \ n2<n1
18576 CODE MIN \ n1 n2 -- n3 signed minimum
18577 CMP @PSP,TOS \ n2-n1
18578 S< ?GOTO BW1 \ n2<n1
18586 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
18587 : U.R \ u n -- display u unsigned in n width (n >= 2)
18589 R> OVER - 0 MAX SPACES TYPE
18594 \ CODE 20_US \ n -- n * 20 us
18595 \ BEGIN \ 3 cycles loop + 6~
18596 \ \ MOV #5,W \ 3 MCLK = 1 MHz
18597 \ \ MOV #23,W \ 3 MCLK = 4 MHz
18598 \ \ MOV #51,W \ 3 MCLK = 8 MHz
18599 \ MOV #104,W \ 3 MCLK = 16 MHz
18600 \ \ MOV #158,W \ 3 MCLK = 24 MHz
18601 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
18606 \ MOV @PSP+,TOS \ 2
18611 CODE 20_US \ n -- n * 20 us
18612 BEGIN \ here we presume that LCD_TIM_IFG = 1...
18614 BIT #1,&LCD_TIM_CTL \ 3
18615 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
18616 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
18618 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
18624 CODE TOP_LCD \ LCD Sample
18625 \ \ if write : %xxxxWWWW --
18626 \ \ if read : -- %0000RRRR
18627 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
18628 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
18629 0= IF \ write LCD bits pattern
18630 AND.B #LCD_DB,TOS \
18631 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
18632 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
18635 THEN \ read LCD bits pattern
18638 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
18639 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
18640 AND.B #LCD_DB,TOS \
18645 CODE LCD_W \ byte -- write byte to LCD
18647 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
18648 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
18649 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
18650 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
18651 COLON \ high level word starts here
18652 TOP_LCD 2 20_US \ write high nibble first
18657 CODE LCD_WrC \ char -- Write Char
18658 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
18663 CODE LCD_WrF \ func -- Write Fonction
18664 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
18670 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
18675 $02 LCD_WrF 100 20_us
18679 [UNDEFINED] OR [IF]
18681 \ https://forth-standard.org/standard/core/OR
18682 \ C OR x1 x2 -- x3 logical OR
18691 : LCD_Entry_set $04 OR LCD_WrF ;
18693 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
18695 : LCD_DSP_Shift $10 OR LCD_WrF ;
18697 : LCD_Fn_Set $20 OR LCD_WrF ;
18699 : LCD_CGRAM_Set $40 OR LCD_WrF ;
18701 : LCD_Goto $80 OR LCD_WrF ;
18703 CODE LCD_R \ -- byte read byte from LCD
18704 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
18705 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
18706 COLON \ starts a FORTH word
18707 TOP_LCD 2 20_us \ -- %0000HHHH
18708 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
18709 HI2LO \ switch from FORTH to assembler
18710 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
18711 ADD.B @PSP+,TOS \ -- %HHHHLLLL
18712 MOV @RSP+,IP \ restore IP saved by COLON
18717 CODE LCD_RdS \ -- status Read Status
18718 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
18723 CODE LCD_RdC \ -- char Read Char
18724 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
18730 \ ******************************\
18731 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
18732 \ ******************************\
18733 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
18734 BIT.B #SW2,&SW2_IN \ test switch S2
18735 0= IF \ case of switch S2 pressed
18736 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
18738 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
18741 BIT.B #SW1,&SW1_IN \ test switch S1 input
18742 0= IF \ case of Switch S1 pressed
18743 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
18745 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
18749 BW1 \ from quit on truncated RC5 message
18750 BW2 \ from repeated RC5 command
18751 BW3 \ from end of RC5_INT
18752 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
18757 \ ******************************\
18758 ASM RC5_INT \ wake up on Px.RC5 change interrupt
18759 \ ******************************\
18760 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
18761 \ ******************************\
18762 \ \ in : SR(9)=old Toggle bit memory (ADD on)
18763 \ \ SMclock = 8|16|24 MHz
18764 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
18765 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
18766 \ \ SR(9)=new Toggle bit memory (ADD on)
18767 \ ******************************\
18768 \ RC5_FirstStartBitHalfCycle: \
18769 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
18770 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
18771 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
18772 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
18773 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
18774 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
18775 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
18776 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
18777 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
18778 MOV #1778,X \ RC5_Period * 1us
18779 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
18780 MOV #14,W \ count of loop
18782 \ ******************************\
18783 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
18784 \ ******************************\ |
18785 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
18786 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
18787 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
18788 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
18789 \ RC5_Compute_3/4_Period: \ |
18790 RRUM #1,X \ X=1/2 cycle |
18793 ADD X,Y \ Y=3/4 cycle
18794 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
18796 \ ******************************\
18797 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
18798 \ ******************************\
18799 BIT.B #RC5,&IR_IN \ C_flag = IR bit
18800 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
18801 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
18802 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
18803 SUB #1,W \ decrement count loop
18804 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
18805 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
18806 0<> WHILE \ ----> out of loop ----+
18807 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
18809 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
18810 CMP Y,X \ 1 | cycle time out of bound ?
18811 U>= IF \ 2 ^ | yes:
18812 BIC #$30,&RC5_TIM_CTL \ | | stop timer
18813 GOTO BW1 \ | | quit on truncated RC5 message
18815 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
18817 REPEAT \ ----> loop back --+ | with X = new RC5_period value
18818 \ ******************************\ |
18819 \ RC5_SampleEndOf: \ <---------------------+
18820 \ ******************************\
18821 BIC #$30,&RC5_TIM_CTL \ stop timer
18822 \ ******************************\
18823 \ RC5_ComputeNewRC5word \
18824 \ ******************************\
18825 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
18826 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
18827 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
18828 \ ******************************\
18829 \ RC5_ComputeC6bit \
18830 \ ******************************\
18831 BIT #BIT14,T \ test /C6 bit in T
18832 0= IF BIS #BIT6,X \ set C6 bit in X
18833 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
18834 \ ******************************\
18835 \ RC5_CommandByteIsDone \ -- BASE RC5_code
18836 \ ******************************\
18837 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
18838 \ ******************************\
18839 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
18840 XOR @RSP,T \ (new XOR old) Toggle bits
18841 BIT #UF10,T \ repeated RC5_command ?
18842 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
18843 XOR #UF10,0(RSP) \ 5 toggle bit memory
18844 \ ******************************\
18845 \ Display IR_RC5 code \ X = RC5 code
18846 \ ******************************\
18848 MOV &BASE,2(PSP) \ save current base
18849 MOV #$10,&BASE \ set hex base
18850 MOV TOS,0(PSP) \ save TOS
18852 LO2HI \ switch from assembler to FORTH
18853 ['] LCD_CLEAR IS CR \ redirects CR
18854 ['] LCD_WrC IS EMIT \ redirects EMIT
18855 CR ." $" 2 U.R \ print IR_RC5 code
18856 ['] CR >BODY IS CR \ restore CR
18857 ['] EMIT >BODY IS EMIT \ restore EMIT
18858 HI2LO \ switch from FORTH to assembler
18859 MOV TOS,&BASE \ restore current BASE
18861 \ ******************************\
18863 \ ******************************\
18867 \ ------------------------------\
18869 \ ------------------------------\
18870 \ ... \ insert here your background task
18873 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
18874 ADD #4,X \ 1 X = BODY of SLEEP
18877 \ ------------------------------\
18881 \ ------------------------------\
18882 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
18883 \ - - \CNTL Counter lentgh \ 00 = 16 bits
18884 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
18885 \ -- \ID input divider \ 10 = /4
18886 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
18887 \ - \TBCLR TimerB Clear
18890 \ -------------------------------\
18891 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
18892 \ -- \CM Capture Mode
18897 \ --- \OUTMOD \ 011 = set/reset
18903 \ -------------------------------\
18905 \ -------------------------------\
18907 \ ------------------------------\
18908 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
18909 \ ------------------------------\
18910 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
18911 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
18912 \ ------------------------------\
18913 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
18914 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
18915 \ ------------------------------\
18916 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
18917 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
18918 \ ------------------------------\
18919 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
18920 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
18921 \ ------------------------------\
18922 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
18923 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
18924 \ ------------------------------\
18925 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
18926 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
18927 \ ------------------------------\
18928 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
18929 \ ------------------------------\
18930 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
18931 \ ------------------------------\
18932 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
18933 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
18934 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
18935 \ ------------------------------\
18936 BIS.B #LCDVo,&LCDVo_DIR \
18937 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
18938 \ ------------------------------\
18939 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
18940 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
18941 \ ------------------------------\
18942 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
18943 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
18944 \ ******************************\
18946 \ ******************************\
18947 BIS.B #RC5,&IR_IE \ enable RC5_Int
18948 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
18949 MOV #RC5_INT,&IR_Vec \ init interrupt vector
18950 \ ******************************\
18951 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
18952 \ ******************************\
18953 \ %01 0001 0100 \ TAxCTL
18954 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
18955 \ -- \ ID divided by 1
18956 \ -- \ MC MODE = up to TAxCCRn
18957 \ - \ TACLR clear timer count
18960 \ ------------------------------\
18961 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
18962 \ ------------------------------\
18964 \ --- \ TAIDEX pre divisor
18965 \ ------------------------------\
18966 \ %0000 0000 0000 0101 \ TAxCCR0
18967 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
18968 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
18969 \ ------------------------------\
18970 \ %0000 0000 0001 0000 \ TAxCCTL0
18971 \ - \ CAP capture/compare mode = compare
18974 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
18975 \ ------------------------------\
18976 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
18977 \ ------------------------------\
18978 \ define LPM mode for ACCEPT \
18979 \ ------------------------------\
18980 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
18981 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
18982 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
18984 \ ------------------------------\
18985 \ redirects to background task \
18986 \ ------------------------------\
18988 MOV #BACKGROUND,2(X) \
18989 \ ------------------------------\
18991 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
18993 \ ------------------------------\
18995 \ ------------------------------\
18996 $03E8 20_US \ 1- wait 20 ms
18997 $03 TOP_LCD \ 2- send DB5=DB4=1
18998 $CD 20_US \ 3- wait 4,1 ms
18999 $03 TOP_LCD \ 4- send again DB5=DB4=1
19000 $5 20_US \ 5- wait 0,1 ms
19001 $03 TOP_LCD \ 6- send again again DB5=DB4=1
19002 $2 20_US \ wait 40 us = LCD cycle
19003 $02 TOP_LCD \ 7- send DB5=1 DB4=0
19004 $2 20_US \ wait 40 us = LCD cycle
19005 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
19006 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
19007 LCD_Clear \ 10- "LCD_Clear"
19008 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
19009 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
19010 LCD_Clear \ 10- "LCD_Clear"
19011 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
19012 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
19014 ['] CR >BODY IS CR \
19015 ['] EMIT >BODY IS EMIT \
19016 ." RC5toLCD is running. Type STOP to quit"
19017 LIT RECURSE IS WARM \ replace WARM by this START routine
19018 ABORT \ and continue with the next word after WARM...
19019 ; \ ...until interpreter falls in sleep mode within ACCEPT.
19022 CODE STOP \ stops multitasking, must to be used before downloading app
19023 \ restore default action of primary DEFERred word SLEEP, assembly version
19024 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
19025 ADD #4,X \ X = BODY of SLEEP
19026 MOV X,-2(X) \ restore the default background
19029 \ restore default action of primary DEFERred word WARM, FORTH version
19030 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
19032 COLD \ because we want to reset CPU and interrupt vectors
19037 ; downloading RC5toLCD.4th is done
19038 RST_HERE ; this app is protected against <reset>
19046 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
19048 [DEFINED] ASM [IF] \ security test
19052 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
19054 CODE MAX \ n1 n2 -- n3 signed maximum
19055 CMP @PSP,TOS \ n2-n1
19056 S< ?GOTO FW1 \ n2<n1
19062 CODE MIN \ n1 n2 -- n3 signed minimum
19063 CMP @PSP,TOS \ n2-n1
19064 S< ?GOTO BW1 \ n2<n1
19072 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
19073 : U.R \ u n -- display u unsigned in n width (n >= 2)
19075 R> OVER - 0 MAX SPACES TYPE
19080 \ CODE 20_US \ n -- n * 20 us
19081 \ BEGIN \ 3 cycles loop + 6~
19082 \ \ MOV #5,W \ 3 MCLK = 1 MHz
19083 \ \ MOV #23,W \ 3 MCLK = 4 MHz
19084 \ \ MOV #51,W \ 3 MCLK = 8 MHz
19085 \ MOV #104,W \ 3 MCLK = 16 MHz
19086 \ \ MOV #158,W \ 3 MCLK = 24 MHz
19087 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
19092 \ MOV @PSP+,TOS \ 2
19097 CODE 20_US \ n -- n * 20 us
19098 BEGIN \ here we presume that LCD_TIM_IFG = 1...
19100 BIT #1,&LCD_TIM_CTL \ 3
19101 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
19102 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
19104 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
19110 CODE TOP_LCD \ LCD Sample
19111 \ \ if write : %xxxxWWWW --
19112 \ \ if read : -- %0000RRRR
19113 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
19114 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
19115 0= IF \ write LCD bits pattern
19116 AND.B #LCD_DB,TOS \
19117 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
19118 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
19121 THEN \ read LCD bits pattern
19124 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
19125 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
19126 AND.B #LCD_DB,TOS \
19131 CODE LCD_W \ byte -- write byte to LCD
19133 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
19134 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
19135 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
19136 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
19137 COLON \ high level word starts here
19138 TOP_LCD 2 20_US \ write high nibble first
19143 CODE LCD_WrC \ char -- Write Char
19144 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
19149 CODE LCD_WrF \ func -- Write Fonction
19150 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
19156 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
19161 $02 LCD_WrF 100 20_us
19165 [UNDEFINED] OR [IF]
19167 \ https://forth-standard.org/standard/core/OR
19168 \ C OR x1 x2 -- x3 logical OR
19177 : LCD_Entry_set $04 OR LCD_WrF ;
19179 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
19181 : LCD_DSP_Shift $10 OR LCD_WrF ;
19183 : LCD_Fn_Set $20 OR LCD_WrF ;
19185 : LCD_CGRAM_Set $40 OR LCD_WrF ;
19187 : LCD_Goto $80 OR LCD_WrF ;
19189 CODE LCD_R \ -- byte read byte from LCD
19190 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
19191 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
19192 COLON \ starts a FORTH word
19193 TOP_LCD 2 20_us \ -- %0000HHHH
19194 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
19195 HI2LO \ switch from FORTH to assembler
19196 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
19197 ADD.B @PSP+,TOS \ -- %HHHHLLLL
19198 MOV @RSP+,IP \ restore IP saved by COLON
19203 CODE LCD_RdS \ -- status Read Status
19204 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
19209 CODE LCD_RdC \ -- char Read Char
19210 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
19216 \ ******************************\
19217 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
19218 \ ******************************\
19219 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
19220 BIT.B #SW2,&SW2_IN \ test switch S2
19221 0= IF \ case of switch S2 pressed
19222 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
19224 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
19227 BIT.B #SW1,&SW1_IN \ test switch S1 input
19228 0= IF \ case of Switch S1 pressed
19229 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
19231 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
19235 BW1 \ from quit on truncated RC5 message
19236 BW2 \ from repeated RC5 command
19237 BW3 \ from end of RC5_INT
19238 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
19243 \ ******************************\
19244 ASM RC5_INT \ wake up on Px.RC5 change interrupt
19245 \ ******************************\
19246 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
19247 \ ******************************\
19248 \ \ in : SR(9)=old Toggle bit memory (ADD on)
19249 \ \ SMclock = 8|16|24 MHz
19250 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
19251 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
19252 \ \ SR(9)=new Toggle bit memory (ADD on)
19253 \ ******************************\
19254 \ RC5_FirstStartBitHalfCycle: \
19255 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
19256 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
19257 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
19258 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
19259 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
19260 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
19261 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
19262 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
19263 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
19264 MOV #1778,X \ RC5_Period * 1us
19265 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
19266 MOV #14,W \ count of loop
19268 \ ******************************\
19269 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
19270 \ ******************************\ |
19271 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
19272 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
19273 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
19274 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
19275 \ RC5_Compute_3/4_Period: \ |
19276 RRUM #1,X \ X=1/2 cycle |
19279 ADD X,Y \ Y=3/4 cycle
19280 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
19282 \ ******************************\
19283 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
19284 \ ******************************\
19285 BIT.B #RC5,&IR_IN \ C_flag = IR bit
19286 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
19287 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
19288 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
19289 SUB #1,W \ decrement count loop
19290 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
19291 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
19292 0<> WHILE \ ----> out of loop ----+
19293 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
19295 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
19296 CMP Y,X \ 1 | cycle time out of bound ?
19297 U>= IF \ 2 ^ | yes:
19298 BIC #$30,&RC5_TIM_CTL \ | | stop timer
19299 GOTO BW1 \ | | quit on truncated RC5 message
19301 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
19303 REPEAT \ ----> loop back --+ | with X = new RC5_period value
19304 \ ******************************\ |
19305 \ RC5_SampleEndOf: \ <---------------------+
19306 \ ******************************\
19307 BIC #$30,&RC5_TIM_CTL \ stop timer
19308 \ ******************************\
19309 \ RC5_ComputeNewRC5word \
19310 \ ******************************\
19311 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
19312 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
19313 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
19314 \ ******************************\
19315 \ RC5_ComputeC6bit \
19316 \ ******************************\
19317 BIT #BIT14,T \ test /C6 bit in T
19318 0= IF BIS #BIT6,X \ set C6 bit in X
19319 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
19320 \ ******************************\
19321 \ RC5_CommandByteIsDone \ -- BASE RC5_code
19322 \ ******************************\
19323 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
19324 \ ******************************\
19325 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
19326 XOR @RSP,T \ (new XOR old) Toggle bits
19327 BIT #UF10,T \ repeated RC5_command ?
19328 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
19329 XOR #UF10,0(RSP) \ 5 toggle bit memory
19330 \ ******************************\
19331 \ Display IR_RC5 code \ X = RC5 code
19332 \ ******************************\
19334 MOV &BASE,2(PSP) \ save current base
19335 MOV #$10,&BASE \ set hex base
19336 MOV TOS,0(PSP) \ save TOS
19338 LO2HI \ switch from assembler to FORTH
19339 ['] LCD_CLEAR IS CR \ redirects CR
19340 ['] LCD_WrC IS EMIT \ redirects EMIT
19341 CR ." $" 2 U.R \ print IR_RC5 code
19342 ['] CR >BODY IS CR \ restore CR
19343 ['] EMIT >BODY IS EMIT \ restore EMIT
19344 HI2LO \ switch from FORTH to assembler
19345 MOV TOS,&BASE \ restore current BASE
19347 \ ******************************\
19349 \ ******************************\
19353 \ ------------------------------\
19355 \ ------------------------------\
19356 \ ... \ insert here your background task
19359 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
19360 ADD #4,X \ 1 X = BODY of SLEEP
19363 \ ------------------------------\
19367 \ ------------------------------\
19368 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
19369 \ - - \CNTL Counter lentgh \ 00 = 16 bits
19370 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
19371 \ -- \ID input divider \ 10 = /4
19372 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
19373 \ - \TBCLR TimerB Clear
19376 \ -------------------------------\
19377 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
19378 \ -- \CM Capture Mode
19383 \ --- \OUTMOD \ 011 = set/reset
19389 \ -------------------------------\
19391 \ -------------------------------\
19393 \ ------------------------------\
19394 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
19395 \ ------------------------------\
19396 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
19397 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
19398 \ ------------------------------\
19399 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
19400 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
19401 \ ------------------------------\
19402 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
19403 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
19404 \ ------------------------------\
19405 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
19406 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
19407 \ ------------------------------\
19408 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
19409 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
19410 \ ------------------------------\
19411 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
19412 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
19413 \ ------------------------------\
19414 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
19415 \ ------------------------------\
19416 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
19417 \ ------------------------------\
19418 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
19419 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
19420 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
19421 \ ------------------------------\
19422 BIS.B #LCDVo,&LCDVo_DIR \
19423 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
19424 \ ------------------------------\
19425 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
19426 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
19427 \ ------------------------------\
19428 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
19429 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
19430 \ ******************************\
19432 \ ******************************\
19433 BIS.B #RC5,&IR_IE \ enable RC5_Int
19434 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
19435 MOV #RC5_INT,&IR_Vec \ init interrupt vector
19436 \ ******************************\
19437 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
19438 \ ******************************\
19439 \ %01 0001 0100 \ TAxCTL
19440 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
19441 \ -- \ ID divided by 1
19442 \ -- \ MC MODE = up to TAxCCRn
19443 \ - \ TACLR clear timer count
19446 \ ------------------------------\
19447 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
19448 \ ------------------------------\
19450 \ --- \ TAIDEX pre divisor
19451 \ ------------------------------\
19452 \ %0000 0000 0000 0101 \ TAxCCR0
19453 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
19454 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
19455 \ ------------------------------\
19456 \ %0000 0000 0001 0000 \ TAxCCTL0
19457 \ - \ CAP capture/compare mode = compare
19460 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
19461 \ ------------------------------\
19462 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
19463 \ ------------------------------\
19464 \ define LPM mode for ACCEPT \
19465 \ ------------------------------\
19466 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
19467 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
19468 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
19470 \ ------------------------------\
19471 \ redirects to background task \
19472 \ ------------------------------\
19474 MOV #BACKGROUND,2(X) \
19475 \ ------------------------------\
19477 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
19479 \ ------------------------------\
19481 \ ------------------------------\
19482 $03E8 20_US \ 1- wait 20 ms
19483 $03 TOP_LCD \ 2- send DB5=DB4=1
19484 $CD 20_US \ 3- wait 4,1 ms
19485 $03 TOP_LCD \ 4- send again DB5=DB4=1
19486 $5 20_US \ 5- wait 0,1 ms
19487 $03 TOP_LCD \ 6- send again again DB5=DB4=1
19488 $2 20_US \ wait 40 us = LCD cycle
19489 $02 TOP_LCD \ 7- send DB5=1 DB4=0
19490 $2 20_US \ wait 40 us = LCD cycle
19491 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
19492 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
19493 LCD_Clear \ 10- "LCD_Clear"
19494 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
19495 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
19496 LCD_Clear \ 10- "LCD_Clear"
19497 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
19498 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
19500 ['] CR >BODY IS CR \
19501 ['] EMIT >BODY IS EMIT \
19502 ." RC5toLCD is running. Type STOP to quit"
19503 LIT RECURSE IS WARM \ replace WARM by this START routine
19504 ABORT \ and continue with the next word after WARM...
19505 ; \ ...until interpreter falls in sleep mode within ACCEPT.
19508 CODE STOP \ stops multitasking, must to be used before downloading app
19509 \ restore default action of primary DEFERred word SLEEP, assembly version
19510 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
19511 ADD #4,X \ X = BODY of SLEEP
19512 MOV X,-2(X) \ restore the default background
19515 \ restore default action of primary DEFERred word WARM, FORTH version
19516 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
19518 COLD \ because we want to reset CPU and interrupt vectors
19523 ; downloading RC5toLCD.4th is done
19524 RST_HERE ; this app is protected against <reset>
19532 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
19534 [DEFINED] ASM [IF] \ security test
19538 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
19540 CODE MAX \ n1 n2 -- n3 signed maximum
19541 CMP @PSP,TOS \ n2-n1
19542 S< ?GOTO FW1 \ n2<n1
19548 CODE MIN \ n1 n2 -- n3 signed minimum
19549 CMP @PSP,TOS \ n2-n1
19550 S< ?GOTO BW1 \ n2<n1
19558 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
19559 : U.R \ u n -- display u unsigned in n width (n >= 2)
19561 R> OVER - 0 MAX SPACES TYPE
19566 \ CODE 20_US \ n -- n * 20 us
19567 \ BEGIN \ 3 cycles loop + 6~
19568 \ \ MOV #5,W \ 3 MCLK = 1 MHz
19569 \ \ MOV #23,W \ 3 MCLK = 4 MHz
19570 \ \ MOV #51,W \ 3 MCLK = 8 MHz
19571 \ MOV #104,W \ 3 MCLK = 16 MHz
19572 \ \ MOV #158,W \ 3 MCLK = 24 MHz
19573 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
19578 \ MOV @PSP+,TOS \ 2
19583 CODE 20_US \ n -- n * 20 us
19584 BEGIN \ here we presume that LCD_TIM_IFG = 1...
19586 BIT #1,&LCD_TIM_CTL \ 3
19587 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
19588 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
19590 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
19596 CODE TOP_LCD \ LCD Sample
19597 \ \ if write : %xxxxWWWW --
19598 \ \ if read : -- %0000RRRR
19599 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
19600 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
19601 0= IF \ write LCD bits pattern
19602 AND.B #LCD_DB,TOS \
19603 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
19604 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
19607 THEN \ read LCD bits pattern
19610 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
19611 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
19612 AND.B #LCD_DB,TOS \
19617 CODE LCD_W \ byte -- write byte to LCD
19619 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
19620 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
19621 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
19622 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
19623 COLON \ high level word starts here
19624 TOP_LCD 2 20_US \ write high nibble first
19629 CODE LCD_WrC \ char -- Write Char
19630 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
19635 CODE LCD_WrF \ func -- Write Fonction
19636 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
19642 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
19647 $02 LCD_WrF 100 20_us
19651 [UNDEFINED] OR [IF]
19653 \ https://forth-standard.org/standard/core/OR
19654 \ C OR x1 x2 -- x3 logical OR
19663 : LCD_Entry_set $04 OR LCD_WrF ;
19665 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
19667 : LCD_DSP_Shift $10 OR LCD_WrF ;
19669 : LCD_Fn_Set $20 OR LCD_WrF ;
19671 : LCD_CGRAM_Set $40 OR LCD_WrF ;
19673 : LCD_Goto $80 OR LCD_WrF ;
19675 CODE LCD_R \ -- byte read byte from LCD
19676 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
19677 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
19678 COLON \ starts a FORTH word
19679 TOP_LCD 2 20_us \ -- %0000HHHH
19680 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
19681 HI2LO \ switch from FORTH to assembler
19682 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
19683 ADD.B @PSP+,TOS \ -- %HHHHLLLL
19684 MOV @RSP+,IP \ restore IP saved by COLON
19689 CODE LCD_RdS \ -- status Read Status
19690 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
19695 CODE LCD_RdC \ -- char Read Char
19696 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
19702 \ ******************************\
19703 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
19704 \ ******************************\
19705 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
19706 BIT.B #SW2,&SW2_IN \ test switch S2
19707 0= IF \ case of switch S2 pressed
19708 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
19710 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
19713 BIT.B #SW1,&SW1_IN \ test switch S1 input
19714 0= IF \ case of Switch S1 pressed
19715 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
19717 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
19721 BW1 \ from quit on truncated RC5 message
19722 BW2 \ from repeated RC5 command
19723 BW3 \ from end of RC5_INT
19724 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
19729 \ ******************************\
19730 ASM RC5_INT \ wake up on Px.RC5 change interrupt
19731 \ ******************************\
19732 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
19733 \ ******************************\
19734 \ \ in : SR(9)=old Toggle bit memory (ADD on)
19735 \ \ SMclock = 8|16|24 MHz
19736 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
19737 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
19738 \ \ SR(9)=new Toggle bit memory (ADD on)
19739 \ ******************************\
19740 \ RC5_FirstStartBitHalfCycle: \
19741 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
19742 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
19743 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
19744 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
19745 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
19746 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
19747 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
19748 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
19749 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
19750 MOV #1778,X \ RC5_Period * 1us
19751 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
19752 MOV #14,W \ count of loop
19754 \ ******************************\
19755 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
19756 \ ******************************\ |
19757 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
19758 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
19759 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
19760 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
19761 \ RC5_Compute_3/4_Period: \ |
19762 RRUM #1,X \ X=1/2 cycle |
19765 ADD X,Y \ Y=3/4 cycle
19766 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
19768 \ ******************************\
19769 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
19770 \ ******************************\
19771 BIT.B #RC5,&IR_IN \ C_flag = IR bit
19772 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
19773 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
19774 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
19775 SUB #1,W \ decrement count loop
19776 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
19777 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
19778 0<> WHILE \ ----> out of loop ----+
19779 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
19781 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
19782 CMP Y,X \ 1 | cycle time out of bound ?
19783 U>= IF \ 2 ^ | yes:
19784 BIC #$30,&RC5_TIM_CTL \ | | stop timer
19785 GOTO BW1 \ | | quit on truncated RC5 message
19787 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
19789 REPEAT \ ----> loop back --+ | with X = new RC5_period value
19790 \ ******************************\ |
19791 \ RC5_SampleEndOf: \ <---------------------+
19792 \ ******************************\
19793 BIC #$30,&RC5_TIM_CTL \ stop timer
19794 \ ******************************\
19795 \ RC5_ComputeNewRC5word \
19796 \ ******************************\
19797 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
19798 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
19799 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
19800 \ ******************************\
19801 \ RC5_ComputeC6bit \
19802 \ ******************************\
19803 BIT #BIT14,T \ test /C6 bit in T
19804 0= IF BIS #BIT6,X \ set C6 bit in X
19805 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
19806 \ ******************************\
19807 \ RC5_CommandByteIsDone \ -- BASE RC5_code
19808 \ ******************************\
19809 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
19810 \ ******************************\
19811 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
19812 XOR @RSP,T \ (new XOR old) Toggle bits
19813 BIT #UF10,T \ repeated RC5_command ?
19814 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
19815 XOR #UF10,0(RSP) \ 5 toggle bit memory
19816 \ ******************************\
19817 \ Display IR_RC5 code \ X = RC5 code
19818 \ ******************************\
19820 MOV &BASE,2(PSP) \ save current base
19821 MOV #$10,&BASE \ set hex base
19822 MOV TOS,0(PSP) \ save TOS
19824 LO2HI \ switch from assembler to FORTH
19825 ['] LCD_CLEAR IS CR \ redirects CR
19826 ['] LCD_WrC IS EMIT \ redirects EMIT
19827 CR ." $" 2 U.R \ print IR_RC5 code
19828 ['] CR >BODY IS CR \ restore CR
19829 ['] EMIT >BODY IS EMIT \ restore EMIT
19830 HI2LO \ switch from FORTH to assembler
19831 MOV TOS,&BASE \ restore current BASE
19833 \ ******************************\
19835 \ ******************************\
19839 \ ------------------------------\
19841 \ ------------------------------\
19842 \ ... \ insert here your background task
19845 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
19846 ADD #4,X \ 1 X = BODY of SLEEP
19849 \ ------------------------------\
19853 \ ------------------------------\
19854 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
19855 \ - - \CNTL Counter lentgh \ 00 = 16 bits
19856 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
19857 \ -- \ID input divider \ 10 = /4
19858 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
19859 \ - \TBCLR TimerB Clear
19862 \ -------------------------------\
19863 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
19864 \ -- \CM Capture Mode
19869 \ --- \OUTMOD \ 011 = set/reset
19875 \ -------------------------------\
19877 \ -------------------------------\
19879 \ ------------------------------\
19880 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
19881 \ ------------------------------\
19882 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
19883 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
19884 \ ------------------------------\
19885 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
19886 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
19887 \ ------------------------------\
19888 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
19889 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
19890 \ ------------------------------\
19891 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
19892 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
19893 \ ------------------------------\
19894 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
19895 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
19896 \ ------------------------------\
19897 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
19898 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
19899 \ ------------------------------\
19900 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
19901 \ ------------------------------\
19902 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
19903 \ ------------------------------\
19904 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
19905 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
19906 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
19907 \ ------------------------------\
19908 BIS.B #LCDVo,&LCDVo_DIR \
19909 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
19910 \ ------------------------------\
19911 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
19912 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
19913 \ ------------------------------\
19914 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
19915 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
19916 \ ******************************\
19918 \ ******************************\
19919 BIS.B #RC5,&IR_IE \ enable RC5_Int
19920 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
19921 MOV #RC5_INT,&IR_Vec \ init interrupt vector
19922 \ ******************************\
19923 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
19924 \ ******************************\
19925 \ %01 0001 0100 \ TAxCTL
19926 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
19927 \ -- \ ID divided by 1
19928 \ -- \ MC MODE = up to TAxCCRn
19929 \ - \ TACLR clear timer count
19932 \ ------------------------------\
19933 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
19934 \ ------------------------------\
19936 \ --- \ TAIDEX pre divisor
19937 \ ------------------------------\
19938 \ %0000 0000 0000 0101 \ TAxCCR0
19939 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
19940 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
19941 \ ------------------------------\
19942 \ %0000 0000 0001 0000 \ TAxCCTL0
19943 \ - \ CAP capture/compare mode = compare
19946 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
19947 \ ------------------------------\
19948 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
19949 \ ------------------------------\
19950 \ define LPM mode for ACCEPT \
19951 \ ------------------------------\
19952 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
19953 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
19954 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
19956 \ ------------------------------\
19957 \ redirects to background task \
19958 \ ------------------------------\
19960 MOV #BACKGROUND,2(X) \
19961 \ ------------------------------\
19963 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
19965 \ ------------------------------\
19967 \ ------------------------------\
19968 $03E8 20_US \ 1- wait 20 ms
19969 $03 TOP_LCD \ 2- send DB5=DB4=1
19970 $CD 20_US \ 3- wait 4,1 ms
19971 $03 TOP_LCD \ 4- send again DB5=DB4=1
19972 $5 20_US \ 5- wait 0,1 ms
19973 $03 TOP_LCD \ 6- send again again DB5=DB4=1
19974 $2 20_US \ wait 40 us = LCD cycle
19975 $02 TOP_LCD \ 7- send DB5=1 DB4=0
19976 $2 20_US \ wait 40 us = LCD cycle
19977 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
19978 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
19979 LCD_Clear \ 10- "LCD_Clear"
19980 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
19981 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
19982 LCD_Clear \ 10- "LCD_Clear"
19983 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
19984 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
19986 ['] CR >BODY IS CR \
19987 ['] EMIT >BODY IS EMIT \
19988 ." RC5toLCD is running. Type STOP to quit"
19989 LIT RECURSE IS WARM \ replace WARM by this START routine
19990 ABORT \ and continue with the next word after WARM...
19991 ; \ ...until interpreter falls in sleep mode within ACCEPT.
19994 CODE STOP \ stops multitasking, must to be used before downloading app
19995 \ restore default action of primary DEFERred word SLEEP, assembly version
19996 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
19997 ADD #4,X \ X = BODY of SLEEP
19998 MOV X,-2(X) \ restore the default background
20001 \ restore default action of primary DEFERred word WARM, FORTH version
20002 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
20004 COLD \ because we want to reset CPU and interrupt vectors
20009 ; downloading RC5toLCD.4th is done
20010 RST_HERE ; this app is protected against <reset>
20018 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
20020 [DEFINED] ASM [IF] \ security test
20024 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
20026 CODE MAX \ n1 n2 -- n3 signed maximum
20027 CMP @PSP,TOS \ n2-n1
20028 S< ?GOTO FW1 \ n2<n1
20034 CODE MIN \ n1 n2 -- n3 signed minimum
20035 CMP @PSP,TOS \ n2-n1
20036 S< ?GOTO BW1 \ n2<n1
20044 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
20045 : U.R \ u n -- display u unsigned in n width (n >= 2)
20047 R> OVER - 0 MAX SPACES TYPE
20052 \ CODE 20_US \ n -- n * 20 us
20053 \ BEGIN \ 3 cycles loop + 6~
20054 \ \ MOV #5,W \ 3 MCLK = 1 MHz
20055 \ \ MOV #23,W \ 3 MCLK = 4 MHz
20056 \ \ MOV #51,W \ 3 MCLK = 8 MHz
20057 \ MOV #104,W \ 3 MCLK = 16 MHz
20058 \ \ MOV #158,W \ 3 MCLK = 24 MHz
20059 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
20064 \ MOV @PSP+,TOS \ 2
20069 CODE 20_US \ n -- n * 20 us
20070 BEGIN \ here we presume that LCD_TIM_IFG = 1...
20072 BIT #1,&LCD_TIM_CTL \ 3
20073 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
20074 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
20076 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
20082 CODE TOP_LCD \ LCD Sample
20083 \ \ if write : %xxxxWWWW --
20084 \ \ if read : -- %0000RRRR
20085 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
20086 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
20087 0= IF \ write LCD bits pattern
20088 AND.B #LCD_DB,TOS \
20089 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
20090 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
20093 THEN \ read LCD bits pattern
20096 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
20097 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
20098 AND.B #LCD_DB,TOS \
20103 CODE LCD_W \ byte -- write byte to LCD
20105 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
20106 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
20107 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
20108 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
20109 COLON \ high level word starts here
20110 TOP_LCD 2 20_US \ write high nibble first
20115 CODE LCD_WrC \ char -- Write Char
20116 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
20121 CODE LCD_WrF \ func -- Write Fonction
20122 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
20128 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
20133 $02 LCD_WrF 100 20_us
20137 [UNDEFINED] OR [IF]
20139 \ https://forth-standard.org/standard/core/OR
20140 \ C OR x1 x2 -- x3 logical OR
20149 : LCD_Entry_set $04 OR LCD_WrF ;
20151 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
20153 : LCD_DSP_Shift $10 OR LCD_WrF ;
20155 : LCD_Fn_Set $20 OR LCD_WrF ;
20157 : LCD_CGRAM_Set $40 OR LCD_WrF ;
20159 : LCD_Goto $80 OR LCD_WrF ;
20161 CODE LCD_R \ -- byte read byte from LCD
20162 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
20163 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
20164 COLON \ starts a FORTH word
20165 TOP_LCD 2 20_us \ -- %0000HHHH
20166 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
20167 HI2LO \ switch from FORTH to assembler
20168 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
20169 ADD.B @PSP+,TOS \ -- %HHHHLLLL
20170 MOV @RSP+,IP \ restore IP saved by COLON
20175 CODE LCD_RdS \ -- status Read Status
20176 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
20181 CODE LCD_RdC \ -- char Read Char
20182 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
20188 \ ******************************\
20189 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
20190 \ ******************************\
20191 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
20192 BIT.B #SW2,&SW2_IN \ test switch S2
20193 0= IF \ case of switch S2 pressed
20194 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
20196 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
20199 BIT.B #SW1,&SW1_IN \ test switch S1 input
20200 0= IF \ case of Switch S1 pressed
20201 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
20203 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
20207 BW1 \ from quit on truncated RC5 message
20208 BW2 \ from repeated RC5 command
20209 BW3 \ from end of RC5_INT
20210 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
20215 \ ******************************\
20216 ASM RC5_INT \ wake up on Px.RC5 change interrupt
20217 \ ******************************\
20218 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
20219 \ ******************************\
20220 \ \ in : SR(9)=old Toggle bit memory (ADD on)
20221 \ \ SMclock = 8|16|24 MHz
20222 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
20223 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
20224 \ \ SR(9)=new Toggle bit memory (ADD on)
20225 \ ******************************\
20226 \ RC5_FirstStartBitHalfCycle: \
20227 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
20228 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
20229 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
20230 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
20231 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
20232 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
20233 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
20234 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
20235 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
20236 MOV #1778,X \ RC5_Period * 1us
20237 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
20238 MOV #14,W \ count of loop
20240 \ ******************************\
20241 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
20242 \ ******************************\ |
20243 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
20244 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
20245 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
20246 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
20247 \ RC5_Compute_3/4_Period: \ |
20248 RRUM #1,X \ X=1/2 cycle |
20251 ADD X,Y \ Y=3/4 cycle
20252 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
20254 \ ******************************\
20255 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
20256 \ ******************************\
20257 BIT.B #RC5,&IR_IN \ C_flag = IR bit
20258 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
20259 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
20260 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
20261 SUB #1,W \ decrement count loop
20262 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
20263 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
20264 0<> WHILE \ ----> out of loop ----+
20265 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
20267 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
20268 CMP Y,X \ 1 | cycle time out of bound ?
20269 U>= IF \ 2 ^ | yes:
20270 BIC #$30,&RC5_TIM_CTL \ | | stop timer
20271 GOTO BW1 \ | | quit on truncated RC5 message
20273 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
20275 REPEAT \ ----> loop back --+ | with X = new RC5_period value
20276 \ ******************************\ |
20277 \ RC5_SampleEndOf: \ <---------------------+
20278 \ ******************************\
20279 BIC #$30,&RC5_TIM_CTL \ stop timer
20280 \ ******************************\
20281 \ RC5_ComputeNewRC5word \
20282 \ ******************************\
20283 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
20284 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
20285 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
20286 \ ******************************\
20287 \ RC5_ComputeC6bit \
20288 \ ******************************\
20289 BIT #BIT14,T \ test /C6 bit in T
20290 0= IF BIS #BIT6,X \ set C6 bit in X
20291 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
20292 \ ******************************\
20293 \ RC5_CommandByteIsDone \ -- BASE RC5_code
20294 \ ******************************\
20295 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
20296 \ ******************************\
20297 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
20298 XOR @RSP,T \ (new XOR old) Toggle bits
20299 BIT #UF10,T \ repeated RC5_command ?
20300 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
20301 XOR #UF10,0(RSP) \ 5 toggle bit memory
20302 \ ******************************\
20303 \ Display IR_RC5 code \ X = RC5 code
20304 \ ******************************\
20306 MOV &BASE,2(PSP) \ save current base
20307 MOV #$10,&BASE \ set hex base
20308 MOV TOS,0(PSP) \ save TOS
20310 LO2HI \ switch from assembler to FORTH
20311 ['] LCD_CLEAR IS CR \ redirects CR
20312 ['] LCD_WrC IS EMIT \ redirects EMIT
20313 CR ." $" 2 U.R \ print IR_RC5 code
20314 ['] CR >BODY IS CR \ restore CR
20315 ['] EMIT >BODY IS EMIT \ restore EMIT
20316 HI2LO \ switch from FORTH to assembler
20317 MOV TOS,&BASE \ restore current BASE
20319 \ ******************************\
20321 \ ******************************\
20325 \ ------------------------------\
20327 \ ------------------------------\
20328 \ ... \ insert here your background task
20331 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
20332 ADD #4,X \ 1 X = BODY of SLEEP
20335 \ ------------------------------\
20339 \ ------------------------------\
20340 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
20341 \ - - \CNTL Counter lentgh \ 00 = 16 bits
20342 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
20343 \ -- \ID input divider \ 10 = /4
20344 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
20345 \ - \TBCLR TimerB Clear
20348 \ -------------------------------\
20349 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
20350 \ -- \CM Capture Mode
20355 \ --- \OUTMOD \ 011 = set/reset
20361 \ -------------------------------\
20363 \ -------------------------------\
20365 \ ------------------------------\
20366 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
20367 \ ------------------------------\
20368 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
20369 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
20370 \ ------------------------------\
20371 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
20372 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
20373 \ ------------------------------\
20374 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
20375 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
20376 \ ------------------------------\
20377 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
20378 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
20379 \ ------------------------------\
20380 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
20381 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
20382 \ ------------------------------\
20383 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
20384 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
20385 \ ------------------------------\
20386 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
20387 \ ------------------------------\
20388 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
20389 \ ------------------------------\
20390 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
20391 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
20392 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
20393 \ ------------------------------\
20394 BIS.B #LCDVo,&LCDVo_DIR \
20395 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
20396 \ ------------------------------\
20397 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
20398 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
20399 \ ------------------------------\
20400 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
20401 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
20402 \ ******************************\
20404 \ ******************************\
20405 BIS.B #RC5,&IR_IE \ enable RC5_Int
20406 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
20407 MOV #RC5_INT,&IR_Vec \ init interrupt vector
20408 \ ******************************\
20409 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
20410 \ ******************************\
20411 \ %01 0001 0100 \ TAxCTL
20412 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
20413 \ -- \ ID divided by 1
20414 \ -- \ MC MODE = up to TAxCCRn
20415 \ - \ TACLR clear timer count
20418 \ ------------------------------\
20419 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
20420 \ ------------------------------\
20422 \ --- \ TAIDEX pre divisor
20423 \ ------------------------------\
20424 \ %0000 0000 0000 0101 \ TAxCCR0
20425 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
20426 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
20427 \ ------------------------------\
20428 \ %0000 0000 0001 0000 \ TAxCCTL0
20429 \ - \ CAP capture/compare mode = compare
20432 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
20433 \ ------------------------------\
20434 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
20435 \ ------------------------------\
20436 \ define LPM mode for ACCEPT \
20437 \ ------------------------------\
20438 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
20439 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
20440 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
20442 \ ------------------------------\
20443 \ redirects to background task \
20444 \ ------------------------------\
20446 MOV #BACKGROUND,2(X) \
20447 \ ------------------------------\
20449 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
20451 \ ------------------------------\
20453 \ ------------------------------\
20454 $03E8 20_US \ 1- wait 20 ms
20455 $03 TOP_LCD \ 2- send DB5=DB4=1
20456 $CD 20_US \ 3- wait 4,1 ms
20457 $03 TOP_LCD \ 4- send again DB5=DB4=1
20458 $5 20_US \ 5- wait 0,1 ms
20459 $03 TOP_LCD \ 6- send again again DB5=DB4=1
20460 $2 20_US \ wait 40 us = LCD cycle
20461 $02 TOP_LCD \ 7- send DB5=1 DB4=0
20462 $2 20_US \ wait 40 us = LCD cycle
20463 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
20464 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
20465 LCD_Clear \ 10- "LCD_Clear"
20466 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
20467 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
20468 LCD_Clear \ 10- "LCD_Clear"
20469 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
20470 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
20472 ['] CR >BODY IS CR \
20473 ['] EMIT >BODY IS EMIT \
20474 ." RC5toLCD is running. Type STOP to quit"
20475 LIT RECURSE IS WARM \ replace WARM by this START routine
20476 ABORT \ and continue with the next word after WARM...
20477 ; \ ...until interpreter falls in sleep mode within ACCEPT.
20480 CODE STOP \ stops multitasking, must to be used before downloading app
20481 \ restore default action of primary DEFERred word SLEEP, assembly version
20482 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
20483 ADD #4,X \ X = BODY of SLEEP
20484 MOV X,-2(X) \ restore the default background
20487 \ restore default action of primary DEFERred word WARM, FORTH version
20488 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
20490 COLD \ because we want to reset CPU and interrupt vectors
20495 ; downloading RC5toLCD.4th is done
20496 RST_HERE ; this app is protected against <reset>
20504 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
20506 [DEFINED] ASM [IF] \ security test
20510 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
20512 CODE MAX \ n1 n2 -- n3 signed maximum
20513 CMP @PSP,TOS \ n2-n1
20514 S< ?GOTO FW1 \ n2<n1
20520 CODE MIN \ n1 n2 -- n3 signed minimum
20521 CMP @PSP,TOS \ n2-n1
20522 S< ?GOTO BW1 \ n2<n1
20530 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
20531 : U.R \ u n -- display u unsigned in n width (n >= 2)
20533 R> OVER - 0 MAX SPACES TYPE
20538 \ CODE 20_US \ n -- n * 20 us
20539 \ BEGIN \ 3 cycles loop + 6~
20540 \ \ MOV #5,W \ 3 MCLK = 1 MHz
20541 \ \ MOV #23,W \ 3 MCLK = 4 MHz
20542 \ \ MOV #51,W \ 3 MCLK = 8 MHz
20543 \ MOV #104,W \ 3 MCLK = 16 MHz
20544 \ \ MOV #158,W \ 3 MCLK = 24 MHz
20545 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
20550 \ MOV @PSP+,TOS \ 2
20555 CODE 20_US \ n -- n * 20 us
20556 BEGIN \ here we presume that LCD_TIM_IFG = 1...
20558 BIT #1,&LCD_TIM_CTL \ 3
20559 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
20560 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
20562 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
20568 CODE TOP_LCD \ LCD Sample
20569 \ \ if write : %xxxxWWWW --
20570 \ \ if read : -- %0000RRRR
20571 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
20572 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
20573 0= IF \ write LCD bits pattern
20574 AND.B #LCD_DB,TOS \
20575 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
20576 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
20579 THEN \ read LCD bits pattern
20582 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
20583 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
20584 AND.B #LCD_DB,TOS \
20589 CODE LCD_W \ byte -- write byte to LCD
20591 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
20592 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
20593 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
20594 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
20595 COLON \ high level word starts here
20596 TOP_LCD 2 20_US \ write high nibble first
20601 CODE LCD_WrC \ char -- Write Char
20602 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
20607 CODE LCD_WrF \ func -- Write Fonction
20608 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
20614 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
20619 $02 LCD_WrF 100 20_us
20623 [UNDEFINED] OR [IF]
20625 \ https://forth-standard.org/standard/core/OR
20626 \ C OR x1 x2 -- x3 logical OR
20635 : LCD_Entry_set $04 OR LCD_WrF ;
20637 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
20639 : LCD_DSP_Shift $10 OR LCD_WrF ;
20641 : LCD_Fn_Set $20 OR LCD_WrF ;
20643 : LCD_CGRAM_Set $40 OR LCD_WrF ;
20645 : LCD_Goto $80 OR LCD_WrF ;
20647 CODE LCD_R \ -- byte read byte from LCD
20648 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
20649 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
20650 COLON \ starts a FORTH word
20651 TOP_LCD 2 20_us \ -- %0000HHHH
20652 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
20653 HI2LO \ switch from FORTH to assembler
20654 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
20655 ADD.B @PSP+,TOS \ -- %HHHHLLLL
20656 MOV @RSP+,IP \ restore IP saved by COLON
20661 CODE LCD_RdS \ -- status Read Status
20662 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
20667 CODE LCD_RdC \ -- char Read Char
20668 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
20674 \ ******************************\
20675 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
20676 \ ******************************\
20677 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
20678 BIT.B #SW2,&SW2_IN \ test switch S2
20679 0= IF \ case of switch S2 pressed
20680 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
20682 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
20685 BIT.B #SW1,&SW1_IN \ test switch S1 input
20686 0= IF \ case of Switch S1 pressed
20687 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
20689 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
20693 BW1 \ from quit on truncated RC5 message
20694 BW2 \ from repeated RC5 command
20695 BW3 \ from end of RC5_INT
20696 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
20701 \ ******************************\
20702 ASM RC5_INT \ wake up on Px.RC5 change interrupt
20703 \ ******************************\
20704 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
20705 \ ******************************\
20706 \ \ in : SR(9)=old Toggle bit memory (ADD on)
20707 \ \ SMclock = 8|16|24 MHz
20708 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
20709 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
20710 \ \ SR(9)=new Toggle bit memory (ADD on)
20711 \ ******************************\
20712 \ RC5_FirstStartBitHalfCycle: \
20713 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
20714 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
20715 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
20716 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
20717 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
20718 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
20719 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
20720 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
20721 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
20722 MOV #1778,X \ RC5_Period * 1us
20723 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
20724 MOV #14,W \ count of loop
20726 \ ******************************\
20727 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
20728 \ ******************************\ |
20729 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
20730 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
20731 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
20732 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
20733 \ RC5_Compute_3/4_Period: \ |
20734 RRUM #1,X \ X=1/2 cycle |
20737 ADD X,Y \ Y=3/4 cycle
20738 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
20740 \ ******************************\
20741 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
20742 \ ******************************\
20743 BIT.B #RC5,&IR_IN \ C_flag = IR bit
20744 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
20745 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
20746 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
20747 SUB #1,W \ decrement count loop
20748 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
20749 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
20750 0<> WHILE \ ----> out of loop ----+
20751 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
20753 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
20754 CMP Y,X \ 1 | cycle time out of bound ?
20755 U>= IF \ 2 ^ | yes:
20756 BIC #$30,&RC5_TIM_CTL \ | | stop timer
20757 GOTO BW1 \ | | quit on truncated RC5 message
20759 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
20761 REPEAT \ ----> loop back --+ | with X = new RC5_period value
20762 \ ******************************\ |
20763 \ RC5_SampleEndOf: \ <---------------------+
20764 \ ******************************\
20765 BIC #$30,&RC5_TIM_CTL \ stop timer
20766 \ ******************************\
20767 \ RC5_ComputeNewRC5word \
20768 \ ******************************\
20769 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
20770 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
20771 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
20772 \ ******************************\
20773 \ RC5_ComputeC6bit \
20774 \ ******************************\
20775 BIT #BIT14,T \ test /C6 bit in T
20776 0= IF BIS #BIT6,X \ set C6 bit in X
20777 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
20778 \ ******************************\
20779 \ RC5_CommandByteIsDone \ -- BASE RC5_code
20780 \ ******************************\
20781 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
20782 \ ******************************\
20783 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
20784 XOR @RSP,T \ (new XOR old) Toggle bits
20785 BIT #UF10,T \ repeated RC5_command ?
20786 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
20787 XOR #UF10,0(RSP) \ 5 toggle bit memory
20788 \ ******************************\
20789 \ Display IR_RC5 code \ X = RC5 code
20790 \ ******************************\
20792 MOV &BASE,2(PSP) \ save current base
20793 MOV #$10,&BASE \ set hex base
20794 MOV TOS,0(PSP) \ save TOS
20796 LO2HI \ switch from assembler to FORTH
20797 ['] LCD_CLEAR IS CR \ redirects CR
20798 ['] LCD_WrC IS EMIT \ redirects EMIT
20799 CR ." $" 2 U.R \ print IR_RC5 code
20800 ['] CR >BODY IS CR \ restore CR
20801 ['] EMIT >BODY IS EMIT \ restore EMIT
20802 HI2LO \ switch from FORTH to assembler
20803 MOV TOS,&BASE \ restore current BASE
20805 \ ******************************\
20807 \ ******************************\
20811 \ ------------------------------\
20813 \ ------------------------------\
20814 \ ... \ insert here your background task
20817 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
20818 ADD #4,X \ 1 X = BODY of SLEEP
20821 \ ------------------------------\
20825 \ ------------------------------\
20826 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
20827 \ - - \CNTL Counter lentgh \ 00 = 16 bits
20828 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
20829 \ -- \ID input divider \ 10 = /4
20830 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
20831 \ - \TBCLR TimerB Clear
20834 \ -------------------------------\
20835 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
20836 \ -- \CM Capture Mode
20841 \ --- \OUTMOD \ 011 = set/reset
20847 \ -------------------------------\
20849 \ -------------------------------\
20851 \ ------------------------------\
20852 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
20853 \ ------------------------------\
20854 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
20855 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
20856 \ ------------------------------\
20857 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
20858 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
20859 \ ------------------------------\
20860 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
20861 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
20862 \ ------------------------------\
20863 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
20864 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
20865 \ ------------------------------\
20866 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
20867 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
20868 \ ------------------------------\
20869 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
20870 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
20871 \ ------------------------------\
20872 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
20873 \ ------------------------------\
20874 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
20875 \ ------------------------------\
20876 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
20877 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
20878 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
20879 \ ------------------------------\
20880 BIS.B #LCDVo,&LCDVo_DIR \
20881 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
20882 \ ------------------------------\
20883 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
20884 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
20885 \ ------------------------------\
20886 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
20887 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
20888 \ ******************************\
20890 \ ******************************\
20891 BIS.B #RC5,&IR_IE \ enable RC5_Int
20892 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
20893 MOV #RC5_INT,&IR_Vec \ init interrupt vector
20894 \ ******************************\
20895 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
20896 \ ******************************\
20897 \ %01 0001 0100 \ TAxCTL
20898 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
20899 \ -- \ ID divided by 1
20900 \ -- \ MC MODE = up to TAxCCRn
20901 \ - \ TACLR clear timer count
20904 \ ------------------------------\
20905 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
20906 \ ------------------------------\
20908 \ --- \ TAIDEX pre divisor
20909 \ ------------------------------\
20910 \ %0000 0000 0000 0101 \ TAxCCR0
20911 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
20912 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
20913 \ ------------------------------\
20914 \ %0000 0000 0001 0000 \ TAxCCTL0
20915 \ - \ CAP capture/compare mode = compare
20918 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
20919 \ ------------------------------\
20920 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
20921 \ ------------------------------\
20922 \ define LPM mode for ACCEPT \
20923 \ ------------------------------\
20924 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
20925 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
20926 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
20928 \ ------------------------------\
20929 \ redirects to background task \
20930 \ ------------------------------\
20932 MOV #BACKGROUND,2(X) \
20933 \ ------------------------------\
20935 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
20937 \ ------------------------------\
20939 \ ------------------------------\
20940 $03E8 20_US \ 1- wait 20 ms
20941 $03 TOP_LCD \ 2- send DB5=DB4=1
20942 $CD 20_US \ 3- wait 4,1 ms
20943 $03 TOP_LCD \ 4- send again DB5=DB4=1
20944 $5 20_US \ 5- wait 0,1 ms
20945 $03 TOP_LCD \ 6- send again again DB5=DB4=1
20946 $2 20_US \ wait 40 us = LCD cycle
20947 $02 TOP_LCD \ 7- send DB5=1 DB4=0
20948 $2 20_US \ wait 40 us = LCD cycle
20949 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
20950 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
20951 LCD_Clear \ 10- "LCD_Clear"
20952 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
20953 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
20954 LCD_Clear \ 10- "LCD_Clear"
20955 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
20956 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
20958 ['] CR >BODY IS CR \
20959 ['] EMIT >BODY IS EMIT \
20960 ." RC5toLCD is running. Type STOP to quit"
20961 LIT RECURSE IS WARM \ replace WARM by this START routine
20962 ABORT \ and continue with the next word after WARM...
20963 ; \ ...until interpreter falls in sleep mode within ACCEPT.
20966 CODE STOP \ stops multitasking, must to be used before downloading app
20967 \ restore default action of primary DEFERred word SLEEP, assembly version
20968 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
20969 ADD #4,X \ X = BODY of SLEEP
20970 MOV X,-2(X) \ restore the default background
20973 \ restore default action of primary DEFERred word WARM, FORTH version
20974 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
20976 COLD \ because we want to reset CPU and interrupt vectors
20981 ; downloading RC5toLCD.4th is done
20982 RST_HERE ; this app is protected against <reset>
20990 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
20992 [DEFINED] ASM [IF] \ security test
20996 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
20998 CODE MAX \ n1 n2 -- n3 signed maximum
20999 CMP @PSP,TOS \ n2-n1
21000 S< ?GOTO FW1 \ n2<n1
21006 CODE MIN \ n1 n2 -- n3 signed minimum
21007 CMP @PSP,TOS \ n2-n1
21008 S< ?GOTO BW1 \ n2<n1
21016 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
21017 : U.R \ u n -- display u unsigned in n width (n >= 2)
21019 R> OVER - 0 MAX SPACES TYPE
21024 \ CODE 20_US \ n -- n * 20 us
21025 \ BEGIN \ 3 cycles loop + 6~
21026 \ \ MOV #5,W \ 3 MCLK = 1 MHz
21027 \ \ MOV #23,W \ 3 MCLK = 4 MHz
21028 \ \ MOV #51,W \ 3 MCLK = 8 MHz
21029 \ MOV #104,W \ 3 MCLK = 16 MHz
21030 \ \ MOV #158,W \ 3 MCLK = 24 MHz
21031 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
21036 \ MOV @PSP+,TOS \ 2
21041 CODE 20_US \ n -- n * 20 us
21042 BEGIN \ here we presume that LCD_TIM_IFG = 1...
21044 BIT #1,&LCD_TIM_CTL \ 3
21045 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
21046 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
21048 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
21054 CODE TOP_LCD \ LCD Sample
21055 \ \ if write : %xxxxWWWW --
21056 \ \ if read : -- %0000RRRR
21057 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
21058 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
21059 0= IF \ write LCD bits pattern
21060 AND.B #LCD_DB,TOS \
21061 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
21062 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
21065 THEN \ read LCD bits pattern
21068 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
21069 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
21070 AND.B #LCD_DB,TOS \
21075 CODE LCD_W \ byte -- write byte to LCD
21077 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
21078 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
21079 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
21080 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
21081 COLON \ high level word starts here
21082 TOP_LCD 2 20_US \ write high nibble first
21087 CODE LCD_WrC \ char -- Write Char
21088 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
21093 CODE LCD_WrF \ func -- Write Fonction
21094 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
21100 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
21105 $02 LCD_WrF 100 20_us
21109 [UNDEFINED] OR [IF]
21111 \ https://forth-standard.org/standard/core/OR
21112 \ C OR x1 x2 -- x3 logical OR
21121 : LCD_Entry_set $04 OR LCD_WrF ;
21123 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
21125 : LCD_DSP_Shift $10 OR LCD_WrF ;
21127 : LCD_Fn_Set $20 OR LCD_WrF ;
21129 : LCD_CGRAM_Set $40 OR LCD_WrF ;
21131 : LCD_Goto $80 OR LCD_WrF ;
21133 CODE LCD_R \ -- byte read byte from LCD
21134 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
21135 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
21136 COLON \ starts a FORTH word
21137 TOP_LCD 2 20_us \ -- %0000HHHH
21138 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
21139 HI2LO \ switch from FORTH to assembler
21140 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
21141 ADD.B @PSP+,TOS \ -- %HHHHLLLL
21142 MOV @RSP+,IP \ restore IP saved by COLON
21147 CODE LCD_RdS \ -- status Read Status
21148 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
21153 CODE LCD_RdC \ -- char Read Char
21154 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
21160 \ ******************************\
21161 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
21162 \ ******************************\
21163 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
21164 BIT.B #SW2,&SW2_IN \ test switch S2
21165 0= IF \ case of switch S2 pressed
21166 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
21168 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
21171 BIT.B #SW1,&SW1_IN \ test switch S1 input
21172 0= IF \ case of Switch S1 pressed
21173 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
21175 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
21179 BW1 \ from quit on truncated RC5 message
21180 BW2 \ from repeated RC5 command
21181 BW3 \ from end of RC5_INT
21182 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
21187 \ ******************************\
21188 ASM RC5_INT \ wake up on Px.RC5 change interrupt
21189 \ ******************************\
21190 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
21191 \ ******************************\
21192 \ \ in : SR(9)=old Toggle bit memory (ADD on)
21193 \ \ SMclock = 8|16|24 MHz
21194 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
21195 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
21196 \ \ SR(9)=new Toggle bit memory (ADD on)
21197 \ ******************************\
21198 \ RC5_FirstStartBitHalfCycle: \
21199 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
21200 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
21201 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
21202 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
21203 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
21204 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
21205 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
21206 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
21207 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
21208 MOV #1778,X \ RC5_Period * 1us
21209 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
21210 MOV #14,W \ count of loop
21212 \ ******************************\
21213 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
21214 \ ******************************\ |
21215 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
21216 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
21217 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
21218 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
21219 \ RC5_Compute_3/4_Period: \ |
21220 RRUM #1,X \ X=1/2 cycle |
21223 ADD X,Y \ Y=3/4 cycle
21224 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
21226 \ ******************************\
21227 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
21228 \ ******************************\
21229 BIT.B #RC5,&IR_IN \ C_flag = IR bit
21230 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
21231 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
21232 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
21233 SUB #1,W \ decrement count loop
21234 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
21235 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
21236 0<> WHILE \ ----> out of loop ----+
21237 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
21239 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
21240 CMP Y,X \ 1 | cycle time out of bound ?
21241 U>= IF \ 2 ^ | yes:
21242 BIC #$30,&RC5_TIM_CTL \ | | stop timer
21243 GOTO BW1 \ | | quit on truncated RC5 message
21245 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
21247 REPEAT \ ----> loop back --+ | with X = new RC5_period value
21248 \ ******************************\ |
21249 \ RC5_SampleEndOf: \ <---------------------+
21250 \ ******************************\
21251 BIC #$30,&RC5_TIM_CTL \ stop timer
21252 \ ******************************\
21253 \ RC5_ComputeNewRC5word \
21254 \ ******************************\
21255 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
21256 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
21257 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
21258 \ ******************************\
21259 \ RC5_ComputeC6bit \
21260 \ ******************************\
21261 BIT #BIT14,T \ test /C6 bit in T
21262 0= IF BIS #BIT6,X \ set C6 bit in X
21263 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
21264 \ ******************************\
21265 \ RC5_CommandByteIsDone \ -- BASE RC5_code
21266 \ ******************************\
21267 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
21268 \ ******************************\
21269 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
21270 XOR @RSP,T \ (new XOR old) Toggle bits
21271 BIT #UF10,T \ repeated RC5_command ?
21272 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
21273 XOR #UF10,0(RSP) \ 5 toggle bit memory
21274 \ ******************************\
21275 \ Display IR_RC5 code \ X = RC5 code
21276 \ ******************************\
21278 MOV &BASE,2(PSP) \ save current base
21279 MOV #$10,&BASE \ set hex base
21280 MOV TOS,0(PSP) \ save TOS
21282 LO2HI \ switch from assembler to FORTH
21283 ['] LCD_CLEAR IS CR \ redirects CR
21284 ['] LCD_WrC IS EMIT \ redirects EMIT
21285 CR ." $" 2 U.R \ print IR_RC5 code
21286 ['] CR >BODY IS CR \ restore CR
21287 ['] EMIT >BODY IS EMIT \ restore EMIT
21288 HI2LO \ switch from FORTH to assembler
21289 MOV TOS,&BASE \ restore current BASE
21291 \ ******************************\
21293 \ ******************************\
21297 \ ------------------------------\
21299 \ ------------------------------\
21300 \ ... \ insert here your background task
21303 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
21304 ADD #4,X \ 1 X = BODY of SLEEP
21307 \ ------------------------------\
21311 \ ------------------------------\
21312 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
21313 \ - - \CNTL Counter lentgh \ 00 = 16 bits
21314 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
21315 \ -- \ID input divider \ 10 = /4
21316 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
21317 \ - \TBCLR TimerB Clear
21320 \ -------------------------------\
21321 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
21322 \ -- \CM Capture Mode
21327 \ --- \OUTMOD \ 011 = set/reset
21333 \ -------------------------------\
21335 \ -------------------------------\
21337 \ ------------------------------\
21338 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
21339 \ ------------------------------\
21340 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
21341 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
21342 \ ------------------------------\
21343 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
21344 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
21345 \ ------------------------------\
21346 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
21347 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
21348 \ ------------------------------\
21349 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
21350 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
21351 \ ------------------------------\
21352 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
21353 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
21354 \ ------------------------------\
21355 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
21356 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
21357 \ ------------------------------\
21358 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
21359 \ ------------------------------\
21360 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
21361 \ ------------------------------\
21362 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
21363 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
21364 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
21365 \ ------------------------------\
21366 BIS.B #LCDVo,&LCDVo_DIR \
21367 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
21368 \ ------------------------------\
21369 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
21370 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
21371 \ ------------------------------\
21372 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
21373 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
21374 \ ******************************\
21376 \ ******************************\
21377 BIS.B #RC5,&IR_IE \ enable RC5_Int
21378 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
21379 MOV #RC5_INT,&IR_Vec \ init interrupt vector
21380 \ ******************************\
21381 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
21382 \ ******************************\
21383 \ %01 0001 0100 \ TAxCTL
21384 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
21385 \ -- \ ID divided by 1
21386 \ -- \ MC MODE = up to TAxCCRn
21387 \ - \ TACLR clear timer count
21390 \ ------------------------------\
21391 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
21392 \ ------------------------------\
21394 \ --- \ TAIDEX pre divisor
21395 \ ------------------------------\
21396 \ %0000 0000 0000 0101 \ TAxCCR0
21397 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
21398 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
21399 \ ------------------------------\
21400 \ %0000 0000 0001 0000 \ TAxCCTL0
21401 \ - \ CAP capture/compare mode = compare
21404 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
21405 \ ------------------------------\
21406 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
21407 \ ------------------------------\
21408 \ define LPM mode for ACCEPT \
21409 \ ------------------------------\
21410 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
21411 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
21412 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
21414 \ ------------------------------\
21415 \ redirects to background task \
21416 \ ------------------------------\
21418 MOV #BACKGROUND,2(X) \
21419 \ ------------------------------\
21421 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
21423 \ ------------------------------\
21425 \ ------------------------------\
21426 $03E8 20_US \ 1- wait 20 ms
21427 $03 TOP_LCD \ 2- send DB5=DB4=1
21428 $CD 20_US \ 3- wait 4,1 ms
21429 $03 TOP_LCD \ 4- send again DB5=DB4=1
21430 $5 20_US \ 5- wait 0,1 ms
21431 $03 TOP_LCD \ 6- send again again DB5=DB4=1
21432 $2 20_US \ wait 40 us = LCD cycle
21433 $02 TOP_LCD \ 7- send DB5=1 DB4=0
21434 $2 20_US \ wait 40 us = LCD cycle
21435 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
21436 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
21437 LCD_Clear \ 10- "LCD_Clear"
21438 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
21439 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
21440 LCD_Clear \ 10- "LCD_Clear"
21441 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
21442 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
21444 ['] CR >BODY IS CR \
21445 ['] EMIT >BODY IS EMIT \
21446 ." RC5toLCD is running. Type STOP to quit"
21447 LIT RECURSE IS WARM \ replace WARM by this START routine
21448 ABORT \ and continue with the next word after WARM...
21449 ; \ ...until interpreter falls in sleep mode within ACCEPT.
21452 CODE STOP \ stops multitasking, must to be used before downloading app
21453 \ restore default action of primary DEFERred word SLEEP, assembly version
21454 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
21455 ADD #4,X \ X = BODY of SLEEP
21456 MOV X,-2(X) \ restore the default background
21459 \ restore default action of primary DEFERred word WARM, FORTH version
21460 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
21462 COLD \ because we want to reset CPU and interrupt vectors
21467 ; downloading RC5toLCD.4th is done
21468 RST_HERE ; this app is protected against <reset>
21476 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
21478 [DEFINED] ASM [IF] \ security test
21482 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
21484 CODE MAX \ n1 n2 -- n3 signed maximum
21485 CMP @PSP,TOS \ n2-n1
21486 S< ?GOTO FW1 \ n2<n1
21492 CODE MIN \ n1 n2 -- n3 signed minimum
21493 CMP @PSP,TOS \ n2-n1
21494 S< ?GOTO BW1 \ n2<n1
21502 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
21503 : U.R \ u n -- display u unsigned in n width (n >= 2)
21505 R> OVER - 0 MAX SPACES TYPE
21510 \ CODE 20_US \ n -- n * 20 us
21511 \ BEGIN \ 3 cycles loop + 6~
21512 \ \ MOV #5,W \ 3 MCLK = 1 MHz
21513 \ \ MOV #23,W \ 3 MCLK = 4 MHz
21514 \ \ MOV #51,W \ 3 MCLK = 8 MHz
21515 \ MOV #104,W \ 3 MCLK = 16 MHz
21516 \ \ MOV #158,W \ 3 MCLK = 24 MHz
21517 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
21522 \ MOV @PSP+,TOS \ 2
21527 CODE 20_US \ n -- n * 20 us
21528 BEGIN \ here we presume that LCD_TIM_IFG = 1...
21530 BIT #1,&LCD_TIM_CTL \ 3
21531 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
21532 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
21534 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
21540 CODE TOP_LCD \ LCD Sample
21541 \ \ if write : %xxxxWWWW --
21542 \ \ if read : -- %0000RRRR
21543 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
21544 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
21545 0= IF \ write LCD bits pattern
21546 AND.B #LCD_DB,TOS \
21547 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
21548 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
21551 THEN \ read LCD bits pattern
21554 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
21555 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
21556 AND.B #LCD_DB,TOS \
21561 CODE LCD_W \ byte -- write byte to LCD
21563 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
21564 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
21565 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
21566 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
21567 COLON \ high level word starts here
21568 TOP_LCD 2 20_US \ write high nibble first
21573 CODE LCD_WrC \ char -- Write Char
21574 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
21579 CODE LCD_WrF \ func -- Write Fonction
21580 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
21586 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
21591 $02 LCD_WrF 100 20_us
21595 [UNDEFINED] OR [IF]
21597 \ https://forth-standard.org/standard/core/OR
21598 \ C OR x1 x2 -- x3 logical OR
21607 : LCD_Entry_set $04 OR LCD_WrF ;
21609 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
21611 : LCD_DSP_Shift $10 OR LCD_WrF ;
21613 : LCD_Fn_Set $20 OR LCD_WrF ;
21615 : LCD_CGRAM_Set $40 OR LCD_WrF ;
21617 : LCD_Goto $80 OR LCD_WrF ;
21619 CODE LCD_R \ -- byte read byte from LCD
21620 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
21621 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
21622 COLON \ starts a FORTH word
21623 TOP_LCD 2 20_us \ -- %0000HHHH
21624 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
21625 HI2LO \ switch from FORTH to assembler
21626 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
21627 ADD.B @PSP+,TOS \ -- %HHHHLLLL
21628 MOV @RSP+,IP \ restore IP saved by COLON
21633 CODE LCD_RdS \ -- status Read Status
21634 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
21639 CODE LCD_RdC \ -- char Read Char
21640 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
21646 \ ******************************\
21647 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
21648 \ ******************************\
21649 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
21650 BIT.B #SW2,&SW2_IN \ test switch S2
21651 0= IF \ case of switch S2 pressed
21652 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
21654 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
21657 BIT.B #SW1,&SW1_IN \ test switch S1 input
21658 0= IF \ case of Switch S1 pressed
21659 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
21661 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
21665 BW1 \ from quit on truncated RC5 message
21666 BW2 \ from repeated RC5 command
21667 BW3 \ from end of RC5_INT
21668 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
21673 \ ******************************\
21674 ASM RC5_INT \ wake up on Px.RC5 change interrupt
21675 \ ******************************\
21676 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
21677 \ ******************************\
21678 \ \ in : SR(9)=old Toggle bit memory (ADD on)
21679 \ \ SMclock = 8|16|24 MHz
21680 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
21681 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
21682 \ \ SR(9)=new Toggle bit memory (ADD on)
21683 \ ******************************\
21684 \ RC5_FirstStartBitHalfCycle: \
21685 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
21686 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
21687 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
21688 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
21689 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
21690 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
21691 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
21692 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
21693 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
21694 MOV #1778,X \ RC5_Period * 1us
21695 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
21696 MOV #14,W \ count of loop
21698 \ ******************************\
21699 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
21700 \ ******************************\ |
21701 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
21702 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
21703 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
21704 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
21705 \ RC5_Compute_3/4_Period: \ |
21706 RRUM #1,X \ X=1/2 cycle |
21709 ADD X,Y \ Y=3/4 cycle
21710 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
21712 \ ******************************\
21713 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
21714 \ ******************************\
21715 BIT.B #RC5,&IR_IN \ C_flag = IR bit
21716 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
21717 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
21718 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
21719 SUB #1,W \ decrement count loop
21720 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
21721 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
21722 0<> WHILE \ ----> out of loop ----+
21723 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
21725 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
21726 CMP Y,X \ 1 | cycle time out of bound ?
21727 U>= IF \ 2 ^ | yes:
21728 BIC #$30,&RC5_TIM_CTL \ | | stop timer
21729 GOTO BW1 \ | | quit on truncated RC5 message
21731 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
21733 REPEAT \ ----> loop back --+ | with X = new RC5_period value
21734 \ ******************************\ |
21735 \ RC5_SampleEndOf: \ <---------------------+
21736 \ ******************************\
21737 BIC #$30,&RC5_TIM_CTL \ stop timer
21738 \ ******************************\
21739 \ RC5_ComputeNewRC5word \
21740 \ ******************************\
21741 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
21742 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
21743 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
21744 \ ******************************\
21745 \ RC5_ComputeC6bit \
21746 \ ******************************\
21747 BIT #BIT14,T \ test /C6 bit in T
21748 0= IF BIS #BIT6,X \ set C6 bit in X
21749 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
21750 \ ******************************\
21751 \ RC5_CommandByteIsDone \ -- BASE RC5_code
21752 \ ******************************\
21753 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
21754 \ ******************************\
21755 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
21756 XOR @RSP,T \ (new XOR old) Toggle bits
21757 BIT #UF10,T \ repeated RC5_command ?
21758 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
21759 XOR #UF10,0(RSP) \ 5 toggle bit memory
21760 \ ******************************\
21761 \ Display IR_RC5 code \ X = RC5 code
21762 \ ******************************\
21764 MOV &BASE,2(PSP) \ save current base
21765 MOV #$10,&BASE \ set hex base
21766 MOV TOS,0(PSP) \ save TOS
21768 LO2HI \ switch from assembler to FORTH
21769 ['] LCD_CLEAR IS CR \ redirects CR
21770 ['] LCD_WrC IS EMIT \ redirects EMIT
21771 CR ." $" 2 U.R \ print IR_RC5 code
21772 ['] CR >BODY IS CR \ restore CR
21773 ['] EMIT >BODY IS EMIT \ restore EMIT
21774 HI2LO \ switch from FORTH to assembler
21775 MOV TOS,&BASE \ restore current BASE
21777 \ ******************************\
21779 \ ******************************\
21783 \ ------------------------------\
21785 \ ------------------------------\
21786 \ ... \ insert here your background task
21789 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
21790 ADD #4,X \ 1 X = BODY of SLEEP
21793 \ ------------------------------\
21797 \ ------------------------------\
21798 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
21799 \ - - \CNTL Counter lentgh \ 00 = 16 bits
21800 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
21801 \ -- \ID input divider \ 10 = /4
21802 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
21803 \ - \TBCLR TimerB Clear
21806 \ -------------------------------\
21807 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
21808 \ -- \CM Capture Mode
21813 \ --- \OUTMOD \ 011 = set/reset
21819 \ -------------------------------\
21821 \ -------------------------------\
21823 \ ------------------------------\
21824 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
21825 \ ------------------------------\
21826 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
21827 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
21828 \ ------------------------------\
21829 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
21830 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
21831 \ ------------------------------\
21832 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
21833 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
21834 \ ------------------------------\
21835 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
21836 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
21837 \ ------------------------------\
21838 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
21839 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
21840 \ ------------------------------\
21841 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
21842 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
21843 \ ------------------------------\
21844 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
21845 \ ------------------------------\
21846 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
21847 \ ------------------------------\
21848 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
21849 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
21850 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
21851 \ ------------------------------\
21852 BIS.B #LCDVo,&LCDVo_DIR \
21853 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
21854 \ ------------------------------\
21855 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
21856 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
21857 \ ------------------------------\
21858 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
21859 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
21860 \ ******************************\
21862 \ ******************************\
21863 BIS.B #RC5,&IR_IE \ enable RC5_Int
21864 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
21865 MOV #RC5_INT,&IR_Vec \ init interrupt vector
21866 \ ******************************\
21867 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
21868 \ ******************************\
21869 \ %01 0001 0100 \ TAxCTL
21870 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
21871 \ -- \ ID divided by 1
21872 \ -- \ MC MODE = up to TAxCCRn
21873 \ - \ TACLR clear timer count
21876 \ ------------------------------\
21877 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
21878 \ ------------------------------\
21880 \ --- \ TAIDEX pre divisor
21881 \ ------------------------------\
21882 \ %0000 0000 0000 0101 \ TAxCCR0
21883 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
21884 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
21885 \ ------------------------------\
21886 \ %0000 0000 0001 0000 \ TAxCCTL0
21887 \ - \ CAP capture/compare mode = compare
21890 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
21891 \ ------------------------------\
21892 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
21893 \ ------------------------------\
21894 \ define LPM mode for ACCEPT \
21895 \ ------------------------------\
21896 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
21897 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
21898 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
21900 \ ------------------------------\
21901 \ redirects to background task \
21902 \ ------------------------------\
21904 MOV #BACKGROUND,2(X) \
21905 \ ------------------------------\
21907 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
21909 \ ------------------------------\
21911 \ ------------------------------\
21912 $03E8 20_US \ 1- wait 20 ms
21913 $03 TOP_LCD \ 2- send DB5=DB4=1
21914 $CD 20_US \ 3- wait 4,1 ms
21915 $03 TOP_LCD \ 4- send again DB5=DB4=1
21916 $5 20_US \ 5- wait 0,1 ms
21917 $03 TOP_LCD \ 6- send again again DB5=DB4=1
21918 $2 20_US \ wait 40 us = LCD cycle
21919 $02 TOP_LCD \ 7- send DB5=1 DB4=0
21920 $2 20_US \ wait 40 us = LCD cycle
21921 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
21922 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
21923 LCD_Clear \ 10- "LCD_Clear"
21924 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
21925 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
21926 LCD_Clear \ 10- "LCD_Clear"
21927 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
21928 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
21930 ['] CR >BODY IS CR \
21931 ['] EMIT >BODY IS EMIT \
21932 ." RC5toLCD is running. Type STOP to quit"
21933 LIT RECURSE IS WARM \ replace WARM by this START routine
21934 ABORT \ and continue with the next word after WARM...
21935 ; \ ...until interpreter falls in sleep mode within ACCEPT.
21938 CODE STOP \ stops multitasking, must to be used before downloading app
21939 \ restore default action of primary DEFERred word SLEEP, assembly version
21940 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
21941 ADD #4,X \ X = BODY of SLEEP
21942 MOV X,-2(X) \ restore the default background
21945 \ restore default action of primary DEFERred word WARM, FORTH version
21946 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
21948 COLD \ because we want to reset CPU and interrupt vectors
21953 ; downloading RC5toLCD.4th is done
21954 RST_HERE ; this app is protected against <reset>
21962 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
21964 [DEFINED] ASM [IF] \ security test
21968 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
21970 CODE MAX \ n1 n2 -- n3 signed maximum
21971 CMP @PSP,TOS \ n2-n1
21972 S< ?GOTO FW1 \ n2<n1
21978 CODE MIN \ n1 n2 -- n3 signed minimum
21979 CMP @PSP,TOS \ n2-n1
21980 S< ?GOTO BW1 \ n2<n1
21988 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
21989 : U.R \ u n -- display u unsigned in n width (n >= 2)
21991 R> OVER - 0 MAX SPACES TYPE
21996 \ CODE 20_US \ n -- n * 20 us
21997 \ BEGIN \ 3 cycles loop + 6~
21998 \ \ MOV #5,W \ 3 MCLK = 1 MHz
21999 \ \ MOV #23,W \ 3 MCLK = 4 MHz
22000 \ \ MOV #51,W \ 3 MCLK = 8 MHz
22001 \ MOV #104,W \ 3 MCLK = 16 MHz
22002 \ \ MOV #158,W \ 3 MCLK = 24 MHz
22003 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
22008 \ MOV @PSP+,TOS \ 2
22013 CODE 20_US \ n -- n * 20 us
22014 BEGIN \ here we presume that LCD_TIM_IFG = 1...
22016 BIT #1,&LCD_TIM_CTL \ 3
22017 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
22018 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
22020 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
22026 CODE TOP_LCD \ LCD Sample
22027 \ \ if write : %xxxxWWWW --
22028 \ \ if read : -- %0000RRRR
22029 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
22030 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
22031 0= IF \ write LCD bits pattern
22032 AND.B #LCD_DB,TOS \
22033 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
22034 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
22037 THEN \ read LCD bits pattern
22040 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
22041 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
22042 AND.B #LCD_DB,TOS \
22047 CODE LCD_W \ byte -- write byte to LCD
22049 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
22050 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
22051 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
22052 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
22053 COLON \ high level word starts here
22054 TOP_LCD 2 20_US \ write high nibble first
22059 CODE LCD_WrC \ char -- Write Char
22060 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
22065 CODE LCD_WrF \ func -- Write Fonction
22066 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
22072 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
22077 $02 LCD_WrF 100 20_us
22081 [UNDEFINED] OR [IF]
22083 \ https://forth-standard.org/standard/core/OR
22084 \ C OR x1 x2 -- x3 logical OR
22093 : LCD_Entry_set $04 OR LCD_WrF ;
22095 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
22097 : LCD_DSP_Shift $10 OR LCD_WrF ;
22099 : LCD_Fn_Set $20 OR LCD_WrF ;
22101 : LCD_CGRAM_Set $40 OR LCD_WrF ;
22103 : LCD_Goto $80 OR LCD_WrF ;
22105 CODE LCD_R \ -- byte read byte from LCD
22106 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
22107 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
22108 COLON \ starts a FORTH word
22109 TOP_LCD 2 20_us \ -- %0000HHHH
22110 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
22111 HI2LO \ switch from FORTH to assembler
22112 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
22113 ADD.B @PSP+,TOS \ -- %HHHHLLLL
22114 MOV @RSP+,IP \ restore IP saved by COLON
22119 CODE LCD_RdS \ -- status Read Status
22120 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
22125 CODE LCD_RdC \ -- char Read Char
22126 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
22132 \ ******************************\
22133 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
22134 \ ******************************\
22135 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
22136 BIT.B #SW2,&SW2_IN \ test switch S2
22137 0= IF \ case of switch S2 pressed
22138 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
22140 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
22143 BIT.B #SW1,&SW1_IN \ test switch S1 input
22144 0= IF \ case of Switch S1 pressed
22145 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
22147 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
22151 BW1 \ from quit on truncated RC5 message
22152 BW2 \ from repeated RC5 command
22153 BW3 \ from end of RC5_INT
22154 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
22159 \ ******************************\
22160 ASM RC5_INT \ wake up on Px.RC5 change interrupt
22161 \ ******************************\
22162 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
22163 \ ******************************\
22164 \ \ in : SR(9)=old Toggle bit memory (ADD on)
22165 \ \ SMclock = 8|16|24 MHz
22166 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
22167 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
22168 \ \ SR(9)=new Toggle bit memory (ADD on)
22169 \ ******************************\
22170 \ RC5_FirstStartBitHalfCycle: \
22171 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
22172 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
22173 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
22174 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
22175 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
22176 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
22177 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
22178 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
22179 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
22180 MOV #1778,X \ RC5_Period * 1us
22181 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
22182 MOV #14,W \ count of loop
22184 \ ******************************\
22185 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
22186 \ ******************************\ |
22187 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
22188 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
22189 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
22190 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
22191 \ RC5_Compute_3/4_Period: \ |
22192 RRUM #1,X \ X=1/2 cycle |
22195 ADD X,Y \ Y=3/4 cycle
22196 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
22198 \ ******************************\
22199 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
22200 \ ******************************\
22201 BIT.B #RC5,&IR_IN \ C_flag = IR bit
22202 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
22203 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
22204 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
22205 SUB #1,W \ decrement count loop
22206 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
22207 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
22208 0<> WHILE \ ----> out of loop ----+
22209 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
22211 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
22212 CMP Y,X \ 1 | cycle time out of bound ?
22213 U>= IF \ 2 ^ | yes:
22214 BIC #$30,&RC5_TIM_CTL \ | | stop timer
22215 GOTO BW1 \ | | quit on truncated RC5 message
22217 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
22219 REPEAT \ ----> loop back --+ | with X = new RC5_period value
22220 \ ******************************\ |
22221 \ RC5_SampleEndOf: \ <---------------------+
22222 \ ******************************\
22223 BIC #$30,&RC5_TIM_CTL \ stop timer
22224 \ ******************************\
22225 \ RC5_ComputeNewRC5word \
22226 \ ******************************\
22227 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
22228 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
22229 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
22230 \ ******************************\
22231 \ RC5_ComputeC6bit \
22232 \ ******************************\
22233 BIT #BIT14,T \ test /C6 bit in T
22234 0= IF BIS #BIT6,X \ set C6 bit in X
22235 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
22236 \ ******************************\
22237 \ RC5_CommandByteIsDone \ -- BASE RC5_code
22238 \ ******************************\
22239 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
22240 \ ******************************\
22241 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
22242 XOR @RSP,T \ (new XOR old) Toggle bits
22243 BIT #UF10,T \ repeated RC5_command ?
22244 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
22245 XOR #UF10,0(RSP) \ 5 toggle bit memory
22246 \ ******************************\
22247 \ Display IR_RC5 code \ X = RC5 code
22248 \ ******************************\
22250 MOV &BASE,2(PSP) \ save current base
22251 MOV #$10,&BASE \ set hex base
22252 MOV TOS,0(PSP) \ save TOS
22254 LO2HI \ switch from assembler to FORTH
22255 ['] LCD_CLEAR IS CR \ redirects CR
22256 ['] LCD_WrC IS EMIT \ redirects EMIT
22257 CR ." $" 2 U.R \ print IR_RC5 code
22258 ['] CR >BODY IS CR \ restore CR
22259 ['] EMIT >BODY IS EMIT \ restore EMIT
22260 HI2LO \ switch from FORTH to assembler
22261 MOV TOS,&BASE \ restore current BASE
22263 \ ******************************\
22265 \ ******************************\
22269 \ ------------------------------\
22271 \ ------------------------------\
22272 \ ... \ insert here your background task
22275 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
22276 ADD #4,X \ 1 X = BODY of SLEEP
22279 \ ------------------------------\
22283 \ ------------------------------\
22284 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
22285 \ - - \CNTL Counter lentgh \ 00 = 16 bits
22286 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
22287 \ -- \ID input divider \ 10 = /4
22288 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
22289 \ - \TBCLR TimerB Clear
22292 \ -------------------------------\
22293 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
22294 \ -- \CM Capture Mode
22299 \ --- \OUTMOD \ 011 = set/reset
22305 \ -------------------------------\
22307 \ -------------------------------\
22309 \ ------------------------------\
22310 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
22311 \ ------------------------------\
22312 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
22313 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
22314 \ ------------------------------\
22315 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
22316 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
22317 \ ------------------------------\
22318 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
22319 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
22320 \ ------------------------------\
22321 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
22322 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
22323 \ ------------------------------\
22324 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
22325 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
22326 \ ------------------------------\
22327 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
22328 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
22329 \ ------------------------------\
22330 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
22331 \ ------------------------------\
22332 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
22333 \ ------------------------------\
22334 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
22335 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
22336 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
22337 \ ------------------------------\
22338 BIS.B #LCDVo,&LCDVo_DIR \
22339 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
22340 \ ------------------------------\
22341 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
22342 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
22343 \ ------------------------------\
22344 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
22345 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
22346 \ ******************************\
22348 \ ******************************\
22349 BIS.B #RC5,&IR_IE \ enable RC5_Int
22350 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
22351 MOV #RC5_INT,&IR_Vec \ init interrupt vector
22352 \ ******************************\
22353 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
22354 \ ******************************\
22355 \ %01 0001 0100 \ TAxCTL
22356 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
22357 \ -- \ ID divided by 1
22358 \ -- \ MC MODE = up to TAxCCRn
22359 \ - \ TACLR clear timer count
22362 \ ------------------------------\
22363 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
22364 \ ------------------------------\
22366 \ --- \ TAIDEX pre divisor
22367 \ ------------------------------\
22368 \ %0000 0000 0000 0101 \ TAxCCR0
22369 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
22370 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
22371 \ ------------------------------\
22372 \ %0000 0000 0001 0000 \ TAxCCTL0
22373 \ - \ CAP capture/compare mode = compare
22376 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
22377 \ ------------------------------\
22378 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
22379 \ ------------------------------\
22380 \ define LPM mode for ACCEPT \
22381 \ ------------------------------\
22382 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
22383 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
22384 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
22386 \ ------------------------------\
22387 \ redirects to background task \
22388 \ ------------------------------\
22390 MOV #BACKGROUND,2(X) \
22391 \ ------------------------------\
22393 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
22395 \ ------------------------------\
22397 \ ------------------------------\
22398 $03E8 20_US \ 1- wait 20 ms
22399 $03 TOP_LCD \ 2- send DB5=DB4=1
22400 $CD 20_US \ 3- wait 4,1 ms
22401 $03 TOP_LCD \ 4- send again DB5=DB4=1
22402 $5 20_US \ 5- wait 0,1 ms
22403 $03 TOP_LCD \ 6- send again again DB5=DB4=1
22404 $2 20_US \ wait 40 us = LCD cycle
22405 $02 TOP_LCD \ 7- send DB5=1 DB4=0
22406 $2 20_US \ wait 40 us = LCD cycle
22407 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
22408 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
22409 LCD_Clear \ 10- "LCD_Clear"
22410 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
22411 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
22412 LCD_Clear \ 10- "LCD_Clear"
22413 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
22414 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
22416 ['] CR >BODY IS CR \
22417 ['] EMIT >BODY IS EMIT \
22418 ." RC5toLCD is running. Type STOP to quit"
22419 LIT RECURSE IS WARM \ replace WARM by this START routine
22420 ABORT \ and continue with the next word after WARM...
22421 ; \ ...until interpreter falls in sleep mode within ACCEPT.
22424 CODE STOP \ stops multitasking, must to be used before downloading app
22425 \ restore default action of primary DEFERred word SLEEP, assembly version
22426 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
22427 ADD #4,X \ X = BODY of SLEEP
22428 MOV X,-2(X) \ restore the default background
22431 \ restore default action of primary DEFERred word WARM, FORTH version
22432 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
22434 COLD \ because we want to reset CPU and interrupt vectors
22439 ; downloading RC5toLCD.4th is done
22440 RST_HERE ; this app is protected against <reset>
22448 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
22450 [DEFINED] ASM [IF] \ security test
22454 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
22456 CODE MAX \ n1 n2 -- n3 signed maximum
22457 CMP @PSP,TOS \ n2-n1
22458 S< ?GOTO FW1 \ n2<n1
22464 CODE MIN \ n1 n2 -- n3 signed minimum
22465 CMP @PSP,TOS \ n2-n1
22466 S< ?GOTO BW1 \ n2<n1
22474 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
22475 : U.R \ u n -- display u unsigned in n width (n >= 2)
22477 R> OVER - 0 MAX SPACES TYPE
22482 \ CODE 20_US \ n -- n * 20 us
22483 \ BEGIN \ 3 cycles loop + 6~
22484 \ \ MOV #5,W \ 3 MCLK = 1 MHz
22485 \ \ MOV #23,W \ 3 MCLK = 4 MHz
22486 \ \ MOV #51,W \ 3 MCLK = 8 MHz
22487 \ MOV #104,W \ 3 MCLK = 16 MHz
22488 \ \ MOV #158,W \ 3 MCLK = 24 MHz
22489 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
22494 \ MOV @PSP+,TOS \ 2
22499 CODE 20_US \ n -- n * 20 us
22500 BEGIN \ here we presume that LCD_TIM_IFG = 1...
22502 BIT #1,&LCD_TIM_CTL \ 3
22503 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
22504 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
22506 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
22512 CODE TOP_LCD \ LCD Sample
22513 \ \ if write : %xxxxWWWW --
22514 \ \ if read : -- %0000RRRR
22515 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
22516 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
22517 0= IF \ write LCD bits pattern
22518 AND.B #LCD_DB,TOS \
22519 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
22520 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
22523 THEN \ read LCD bits pattern
22526 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
22527 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
22528 AND.B #LCD_DB,TOS \
22533 CODE LCD_W \ byte -- write byte to LCD
22535 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
22536 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
22537 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
22538 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
22539 COLON \ high level word starts here
22540 TOP_LCD 2 20_US \ write high nibble first
22545 CODE LCD_WrC \ char -- Write Char
22546 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
22551 CODE LCD_WrF \ func -- Write Fonction
22552 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
22558 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
22563 $02 LCD_WrF 100 20_us
22567 [UNDEFINED] OR [IF]
22569 \ https://forth-standard.org/standard/core/OR
22570 \ C OR x1 x2 -- x3 logical OR
22579 : LCD_Entry_set $04 OR LCD_WrF ;
22581 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
22583 : LCD_DSP_Shift $10 OR LCD_WrF ;
22585 : LCD_Fn_Set $20 OR LCD_WrF ;
22587 : LCD_CGRAM_Set $40 OR LCD_WrF ;
22589 : LCD_Goto $80 OR LCD_WrF ;
22591 CODE LCD_R \ -- byte read byte from LCD
22592 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
22593 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
22594 COLON \ starts a FORTH word
22595 TOP_LCD 2 20_us \ -- %0000HHHH
22596 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
22597 HI2LO \ switch from FORTH to assembler
22598 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
22599 ADD.B @PSP+,TOS \ -- %HHHHLLLL
22600 MOV @RSP+,IP \ restore IP saved by COLON
22605 CODE LCD_RdS \ -- status Read Status
22606 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
22611 CODE LCD_RdC \ -- char Read Char
22612 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
22618 \ ******************************\
22619 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
22620 \ ******************************\
22621 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
22622 BIT.B #SW2,&SW2_IN \ test switch S2
22623 0= IF \ case of switch S2 pressed
22624 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
22626 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
22629 BIT.B #SW1,&SW1_IN \ test switch S1 input
22630 0= IF \ case of Switch S1 pressed
22631 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
22633 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
22637 BW1 \ from quit on truncated RC5 message
22638 BW2 \ from repeated RC5 command
22639 BW3 \ from end of RC5_INT
22640 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
22645 \ ******************************\
22646 ASM RC5_INT \ wake up on Px.RC5 change interrupt
22647 \ ******************************\
22648 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
22649 \ ******************************\
22650 \ \ in : SR(9)=old Toggle bit memory (ADD on)
22651 \ \ SMclock = 8|16|24 MHz
22652 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
22653 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
22654 \ \ SR(9)=new Toggle bit memory (ADD on)
22655 \ ******************************\
22656 \ RC5_FirstStartBitHalfCycle: \
22657 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
22658 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
22659 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
22660 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
22661 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
22662 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
22663 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
22664 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
22665 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
22666 MOV #1778,X \ RC5_Period * 1us
22667 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
22668 MOV #14,W \ count of loop
22670 \ ******************************\
22671 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
22672 \ ******************************\ |
22673 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
22674 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
22675 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
22676 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
22677 \ RC5_Compute_3/4_Period: \ |
22678 RRUM #1,X \ X=1/2 cycle |
22681 ADD X,Y \ Y=3/4 cycle
22682 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
22684 \ ******************************\
22685 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
22686 \ ******************************\
22687 BIT.B #RC5,&IR_IN \ C_flag = IR bit
22688 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
22689 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
22690 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
22691 SUB #1,W \ decrement count loop
22692 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
22693 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
22694 0<> WHILE \ ----> out of loop ----+
22695 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
22697 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
22698 CMP Y,X \ 1 | cycle time out of bound ?
22699 U>= IF \ 2 ^ | yes:
22700 BIC #$30,&RC5_TIM_CTL \ | | stop timer
22701 GOTO BW1 \ | | quit on truncated RC5 message
22703 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
22705 REPEAT \ ----> loop back --+ | with X = new RC5_period value
22706 \ ******************************\ |
22707 \ RC5_SampleEndOf: \ <---------------------+
22708 \ ******************************\
22709 BIC #$30,&RC5_TIM_CTL \ stop timer
22710 \ ******************************\
22711 \ RC5_ComputeNewRC5word \
22712 \ ******************************\
22713 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
22714 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
22715 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
22716 \ ******************************\
22717 \ RC5_ComputeC6bit \
22718 \ ******************************\
22719 BIT #BIT14,T \ test /C6 bit in T
22720 0= IF BIS #BIT6,X \ set C6 bit in X
22721 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
22722 \ ******************************\
22723 \ RC5_CommandByteIsDone \ -- BASE RC5_code
22724 \ ******************************\
22725 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
22726 \ ******************************\
22727 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
22728 XOR @RSP,T \ (new XOR old) Toggle bits
22729 BIT #UF10,T \ repeated RC5_command ?
22730 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
22731 XOR #UF10,0(RSP) \ 5 toggle bit memory
22732 \ ******************************\
22733 \ Display IR_RC5 code \ X = RC5 code
22734 \ ******************************\
22736 MOV &BASE,2(PSP) \ save current base
22737 MOV #$10,&BASE \ set hex base
22738 MOV TOS,0(PSP) \ save TOS
22740 LO2HI \ switch from assembler to FORTH
22741 ['] LCD_CLEAR IS CR \ redirects CR
22742 ['] LCD_WrC IS EMIT \ redirects EMIT
22743 CR ." $" 2 U.R \ print IR_RC5 code
22744 ['] CR >BODY IS CR \ restore CR
22745 ['] EMIT >BODY IS EMIT \ restore EMIT
22746 HI2LO \ switch from FORTH to assembler
22747 MOV TOS,&BASE \ restore current BASE
22749 \ ******************************\
22751 \ ******************************\
22755 \ ------------------------------\
22757 \ ------------------------------\
22758 \ ... \ insert here your background task
22761 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
22762 ADD #4,X \ 1 X = BODY of SLEEP
22765 \ ------------------------------\
22769 \ ------------------------------\
22770 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
22771 \ - - \CNTL Counter lentgh \ 00 = 16 bits
22772 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
22773 \ -- \ID input divider \ 10 = /4
22774 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
22775 \ - \TBCLR TimerB Clear
22778 \ -------------------------------\
22779 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
22780 \ -- \CM Capture Mode
22785 \ --- \OUTMOD \ 011 = set/reset
22791 \ -------------------------------\
22793 \ -------------------------------\
22795 \ ------------------------------\
22796 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
22797 \ ------------------------------\
22798 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
22799 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
22800 \ ------------------------------\
22801 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
22802 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
22803 \ ------------------------------\
22804 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
22805 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
22806 \ ------------------------------\
22807 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
22808 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
22809 \ ------------------------------\
22810 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
22811 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
22812 \ ------------------------------\
22813 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
22814 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
22815 \ ------------------------------\
22816 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
22817 \ ------------------------------\
22818 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
22819 \ ------------------------------\
22820 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
22821 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
22822 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
22823 \ ------------------------------\
22824 BIS.B #LCDVo,&LCDVo_DIR \
22825 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
22826 \ ------------------------------\
22827 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
22828 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
22829 \ ------------------------------\
22830 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
22831 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
22832 \ ******************************\
22834 \ ******************************\
22835 BIS.B #RC5,&IR_IE \ enable RC5_Int
22836 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
22837 MOV #RC5_INT,&IR_Vec \ init interrupt vector
22838 \ ******************************\
22839 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
22840 \ ******************************\
22841 \ %01 0001 0100 \ TAxCTL
22842 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
22843 \ -- \ ID divided by 1
22844 \ -- \ MC MODE = up to TAxCCRn
22845 \ - \ TACLR clear timer count
22848 \ ------------------------------\
22849 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
22850 \ ------------------------------\
22852 \ --- \ TAIDEX pre divisor
22853 \ ------------------------------\
22854 \ %0000 0000 0000 0101 \ TAxCCR0
22855 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
22856 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
22857 \ ------------------------------\
22858 \ %0000 0000 0001 0000 \ TAxCCTL0
22859 \ - \ CAP capture/compare mode = compare
22862 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
22863 \ ------------------------------\
22864 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
22865 \ ------------------------------\
22866 \ define LPM mode for ACCEPT \
22867 \ ------------------------------\
22868 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
22869 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
22870 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
22872 \ ------------------------------\
22873 \ redirects to background task \
22874 \ ------------------------------\
22876 MOV #BACKGROUND,2(X) \
22877 \ ------------------------------\
22879 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
22881 \ ------------------------------\
22883 \ ------------------------------\
22884 $03E8 20_US \ 1- wait 20 ms
22885 $03 TOP_LCD \ 2- send DB5=DB4=1
22886 $CD 20_US \ 3- wait 4,1 ms
22887 $03 TOP_LCD \ 4- send again DB5=DB4=1
22888 $5 20_US \ 5- wait 0,1 ms
22889 $03 TOP_LCD \ 6- send again again DB5=DB4=1
22890 $2 20_US \ wait 40 us = LCD cycle
22891 $02 TOP_LCD \ 7- send DB5=1 DB4=0
22892 $2 20_US \ wait 40 us = LCD cycle
22893 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
22894 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
22895 LCD_Clear \ 10- "LCD_Clear"
22896 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
22897 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
22898 LCD_Clear \ 10- "LCD_Clear"
22899 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
22900 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
22902 ['] CR >BODY IS CR \
22903 ['] EMIT >BODY IS EMIT \
22904 ." RC5toLCD is running. Type STOP to quit"
22905 LIT RECURSE IS WARM \ replace WARM by this START routine
22906 ABORT \ and continue with the next word after WARM...
22907 ; \ ...until interpreter falls in sleep mode within ACCEPT.
22910 CODE STOP \ stops multitasking, must to be used before downloading app
22911 \ restore default action of primary DEFERred word SLEEP, assembly version
22912 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
22913 ADD #4,X \ X = BODY of SLEEP
22914 MOV X,-2(X) \ restore the default background
22917 \ restore default action of primary DEFERred word WARM, FORTH version
22918 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
22920 COLD \ because we want to reset CPU and interrupt vectors
22925 ; downloading RC5toLCD.4th is done
22926 RST_HERE ; this app is protected against <reset>
22934 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
22936 [DEFINED] ASM [IF] \ security test
22940 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
22942 CODE MAX \ n1 n2 -- n3 signed maximum
22943 CMP @PSP,TOS \ n2-n1
22944 S< ?GOTO FW1 \ n2<n1
22950 CODE MIN \ n1 n2 -- n3 signed minimum
22951 CMP @PSP,TOS \ n2-n1
22952 S< ?GOTO BW1 \ n2<n1
22960 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
22961 : U.R \ u n -- display u unsigned in n width (n >= 2)
22963 R> OVER - 0 MAX SPACES TYPE
22968 \ CODE 20_US \ n -- n * 20 us
22969 \ BEGIN \ 3 cycles loop + 6~
22970 \ \ MOV #5,W \ 3 MCLK = 1 MHz
22971 \ \ MOV #23,W \ 3 MCLK = 4 MHz
22972 \ \ MOV #51,W \ 3 MCLK = 8 MHz
22973 \ MOV #104,W \ 3 MCLK = 16 MHz
22974 \ \ MOV #158,W \ 3 MCLK = 24 MHz
22975 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
22980 \ MOV @PSP+,TOS \ 2
22985 CODE 20_US \ n -- n * 20 us
22986 BEGIN \ here we presume that LCD_TIM_IFG = 1...
22988 BIT #1,&LCD_TIM_CTL \ 3
22989 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
22990 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
22992 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
22998 CODE TOP_LCD \ LCD Sample
22999 \ \ if write : %xxxxWWWW --
23000 \ \ if read : -- %0000RRRR
23001 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
23002 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
23003 0= IF \ write LCD bits pattern
23004 AND.B #LCD_DB,TOS \
23005 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
23006 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
23009 THEN \ read LCD bits pattern
23012 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
23013 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
23014 AND.B #LCD_DB,TOS \
23019 CODE LCD_W \ byte -- write byte to LCD
23021 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
23022 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
23023 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
23024 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
23025 COLON \ high level word starts here
23026 TOP_LCD 2 20_US \ write high nibble first
23031 CODE LCD_WrC \ char -- Write Char
23032 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
23037 CODE LCD_WrF \ func -- Write Fonction
23038 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
23044 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
23049 $02 LCD_WrF 100 20_us
23053 [UNDEFINED] OR [IF]
23055 \ https://forth-standard.org/standard/core/OR
23056 \ C OR x1 x2 -- x3 logical OR
23065 : LCD_Entry_set $04 OR LCD_WrF ;
23067 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
23069 : LCD_DSP_Shift $10 OR LCD_WrF ;
23071 : LCD_Fn_Set $20 OR LCD_WrF ;
23073 : LCD_CGRAM_Set $40 OR LCD_WrF ;
23075 : LCD_Goto $80 OR LCD_WrF ;
23077 CODE LCD_R \ -- byte read byte from LCD
23078 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
23079 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
23080 COLON \ starts a FORTH word
23081 TOP_LCD 2 20_us \ -- %0000HHHH
23082 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
23083 HI2LO \ switch from FORTH to assembler
23084 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
23085 ADD.B @PSP+,TOS \ -- %HHHHLLLL
23086 MOV @RSP+,IP \ restore IP saved by COLON
23091 CODE LCD_RdS \ -- status Read Status
23092 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
23097 CODE LCD_RdC \ -- char Read Char
23098 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
23104 \ ******************************\
23105 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
23106 \ ******************************\
23107 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
23108 BIT.B #SW2,&SW2_IN \ test switch S2
23109 0= IF \ case of switch S2 pressed
23110 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
23112 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
23115 BIT.B #SW1,&SW1_IN \ test switch S1 input
23116 0= IF \ case of Switch S1 pressed
23117 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
23119 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
23123 BW1 \ from quit on truncated RC5 message
23124 BW2 \ from repeated RC5 command
23125 BW3 \ from end of RC5_INT
23126 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
23131 \ ******************************\
23132 ASM RC5_INT \ wake up on Px.RC5 change interrupt
23133 \ ******************************\
23134 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
23135 \ ******************************\
23136 \ \ in : SR(9)=old Toggle bit memory (ADD on)
23137 \ \ SMclock = 8|16|24 MHz
23138 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
23139 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
23140 \ \ SR(9)=new Toggle bit memory (ADD on)
23141 \ ******************************\
23142 \ RC5_FirstStartBitHalfCycle: \
23143 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
23144 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
23145 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
23146 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
23147 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
23148 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
23149 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
23150 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
23151 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
23152 MOV #1778,X \ RC5_Period * 1us
23153 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
23154 MOV #14,W \ count of loop
23156 \ ******************************\
23157 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
23158 \ ******************************\ |
23159 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
23160 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
23161 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
23162 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
23163 \ RC5_Compute_3/4_Period: \ |
23164 RRUM #1,X \ X=1/2 cycle |
23167 ADD X,Y \ Y=3/4 cycle
23168 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
23170 \ ******************************\
23171 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
23172 \ ******************************\
23173 BIT.B #RC5,&IR_IN \ C_flag = IR bit
23174 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
23175 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
23176 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
23177 SUB #1,W \ decrement count loop
23178 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
23179 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
23180 0<> WHILE \ ----> out of loop ----+
23181 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
23183 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
23184 CMP Y,X \ 1 | cycle time out of bound ?
23185 U>= IF \ 2 ^ | yes:
23186 BIC #$30,&RC5_TIM_CTL \ | | stop timer
23187 GOTO BW1 \ | | quit on truncated RC5 message
23189 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
23191 REPEAT \ ----> loop back --+ | with X = new RC5_period value
23192 \ ******************************\ |
23193 \ RC5_SampleEndOf: \ <---------------------+
23194 \ ******************************\
23195 BIC #$30,&RC5_TIM_CTL \ stop timer
23196 \ ******************************\
23197 \ RC5_ComputeNewRC5word \
23198 \ ******************************\
23199 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
23200 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
23201 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
23202 \ ******************************\
23203 \ RC5_ComputeC6bit \
23204 \ ******************************\
23205 BIT #BIT14,T \ test /C6 bit in T
23206 0= IF BIS #BIT6,X \ set C6 bit in X
23207 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
23208 \ ******************************\
23209 \ RC5_CommandByteIsDone \ -- BASE RC5_code
23210 \ ******************************\
23211 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
23212 \ ******************************\
23213 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
23214 XOR @RSP,T \ (new XOR old) Toggle bits
23215 BIT #UF10,T \ repeated RC5_command ?
23216 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
23217 XOR #UF10,0(RSP) \ 5 toggle bit memory
23218 \ ******************************\
23219 \ Display IR_RC5 code \ X = RC5 code
23220 \ ******************************\
23222 MOV &BASE,2(PSP) \ save current base
23223 MOV #$10,&BASE \ set hex base
23224 MOV TOS,0(PSP) \ save TOS
23226 LO2HI \ switch from assembler to FORTH
23227 ['] LCD_CLEAR IS CR \ redirects CR
23228 ['] LCD_WrC IS EMIT \ redirects EMIT
23229 CR ." $" 2 U.R \ print IR_RC5 code
23230 ['] CR >BODY IS CR \ restore CR
23231 ['] EMIT >BODY IS EMIT \ restore EMIT
23232 HI2LO \ switch from FORTH to assembler
23233 MOV TOS,&BASE \ restore current BASE
23235 \ ******************************\
23237 \ ******************************\
23241 \ ------------------------------\
23243 \ ------------------------------\
23244 \ ... \ insert here your background task
23247 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
23248 ADD #4,X \ 1 X = BODY of SLEEP
23251 \ ------------------------------\
23255 \ ------------------------------\
23256 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
23257 \ - - \CNTL Counter lentgh \ 00 = 16 bits
23258 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
23259 \ -- \ID input divider \ 10 = /4
23260 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
23261 \ - \TBCLR TimerB Clear
23264 \ -------------------------------\
23265 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
23266 \ -- \CM Capture Mode
23271 \ --- \OUTMOD \ 011 = set/reset
23277 \ -------------------------------\
23279 \ -------------------------------\
23281 \ ------------------------------\
23282 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
23283 \ ------------------------------\
23284 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
23285 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
23286 \ ------------------------------\
23287 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
23288 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
23289 \ ------------------------------\
23290 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
23291 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
23292 \ ------------------------------\
23293 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
23294 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
23295 \ ------------------------------\
23296 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
23297 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
23298 \ ------------------------------\
23299 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
23300 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
23301 \ ------------------------------\
23302 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
23303 \ ------------------------------\
23304 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
23305 \ ------------------------------\
23306 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
23307 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
23308 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
23309 \ ------------------------------\
23310 BIS.B #LCDVo,&LCDVo_DIR \
23311 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
23312 \ ------------------------------\
23313 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
23314 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
23315 \ ------------------------------\
23316 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
23317 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
23318 \ ******************************\
23320 \ ******************************\
23321 BIS.B #RC5,&IR_IE \ enable RC5_Int
23322 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
23323 MOV #RC5_INT,&IR_Vec \ init interrupt vector
23324 \ ******************************\
23325 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
23326 \ ******************************\
23327 \ %01 0001 0100 \ TAxCTL
23328 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
23329 \ -- \ ID divided by 1
23330 \ -- \ MC MODE = up to TAxCCRn
23331 \ - \ TACLR clear timer count
23334 \ ------------------------------\
23335 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
23336 \ ------------------------------\
23338 \ --- \ TAIDEX pre divisor
23339 \ ------------------------------\
23340 \ %0000 0000 0000 0101 \ TAxCCR0
23341 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
23342 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
23343 \ ------------------------------\
23344 \ %0000 0000 0001 0000 \ TAxCCTL0
23345 \ - \ CAP capture/compare mode = compare
23348 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
23349 \ ------------------------------\
23350 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
23351 \ ------------------------------\
23352 \ define LPM mode for ACCEPT \
23353 \ ------------------------------\
23354 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
23355 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
23356 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
23358 \ ------------------------------\
23359 \ redirects to background task \
23360 \ ------------------------------\
23362 MOV #BACKGROUND,2(X) \
23363 \ ------------------------------\
23365 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
23367 \ ------------------------------\
23369 \ ------------------------------\
23370 $03E8 20_US \ 1- wait 20 ms
23371 $03 TOP_LCD \ 2- send DB5=DB4=1
23372 $CD 20_US \ 3- wait 4,1 ms
23373 $03 TOP_LCD \ 4- send again DB5=DB4=1
23374 $5 20_US \ 5- wait 0,1 ms
23375 $03 TOP_LCD \ 6- send again again DB5=DB4=1
23376 $2 20_US \ wait 40 us = LCD cycle
23377 $02 TOP_LCD \ 7- send DB5=1 DB4=0
23378 $2 20_US \ wait 40 us = LCD cycle
23379 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
23380 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
23381 LCD_Clear \ 10- "LCD_Clear"
23382 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
23383 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
23384 LCD_Clear \ 10- "LCD_Clear"
23385 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
23386 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
23388 ['] CR >BODY IS CR \
23389 ['] EMIT >BODY IS EMIT \
23390 ." RC5toLCD is running. Type STOP to quit"
23391 LIT RECURSE IS WARM \ replace WARM by this START routine
23392 ABORT \ and continue with the next word after WARM...
23393 ; \ ...until interpreter falls in sleep mode within ACCEPT.
23396 CODE STOP \ stops multitasking, must to be used before downloading app
23397 \ restore default action of primary DEFERred word SLEEP, assembly version
23398 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
23399 ADD #4,X \ X = BODY of SLEEP
23400 MOV X,-2(X) \ restore the default background
23403 \ restore default action of primary DEFERred word WARM, FORTH version
23404 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
23406 COLD \ because we want to reset CPU and interrupt vectors
23411 ; downloading RC5toLCD.4th is done
23412 RST_HERE ; this app is protected against <reset>
23420 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
23422 [DEFINED] ASM [IF] \ security test
23426 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
23428 CODE MAX \ n1 n2 -- n3 signed maximum
23429 CMP @PSP,TOS \ n2-n1
23430 S< ?GOTO FW1 \ n2<n1
23436 CODE MIN \ n1 n2 -- n3 signed minimum
23437 CMP @PSP,TOS \ n2-n1
23438 S< ?GOTO BW1 \ n2<n1
23446 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
23447 : U.R \ u n -- display u unsigned in n width (n >= 2)
23449 R> OVER - 0 MAX SPACES TYPE
23454 \ CODE 20_US \ n -- n * 20 us
23455 \ BEGIN \ 3 cycles loop + 6~
23456 \ \ MOV #5,W \ 3 MCLK = 1 MHz
23457 \ \ MOV #23,W \ 3 MCLK = 4 MHz
23458 \ \ MOV #51,W \ 3 MCLK = 8 MHz
23459 \ MOV #104,W \ 3 MCLK = 16 MHz
23460 \ \ MOV #158,W \ 3 MCLK = 24 MHz
23461 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
23466 \ MOV @PSP+,TOS \ 2
23471 CODE 20_US \ n -- n * 20 us
23472 BEGIN \ here we presume that LCD_TIM_IFG = 1...
23474 BIT #1,&LCD_TIM_CTL \ 3
23475 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
23476 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
23478 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
23484 CODE TOP_LCD \ LCD Sample
23485 \ \ if write : %xxxxWWWW --
23486 \ \ if read : -- %0000RRRR
23487 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
23488 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
23489 0= IF \ write LCD bits pattern
23490 AND.B #LCD_DB,TOS \
23491 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
23492 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
23495 THEN \ read LCD bits pattern
23498 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
23499 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
23500 AND.B #LCD_DB,TOS \
23505 CODE LCD_W \ byte -- write byte to LCD
23507 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
23508 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
23509 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
23510 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
23511 COLON \ high level word starts here
23512 TOP_LCD 2 20_US \ write high nibble first
23517 CODE LCD_WrC \ char -- Write Char
23518 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
23523 CODE LCD_WrF \ func -- Write Fonction
23524 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
23530 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
23535 $02 LCD_WrF 100 20_us
23539 [UNDEFINED] OR [IF]
23541 \ https://forth-standard.org/standard/core/OR
23542 \ C OR x1 x2 -- x3 logical OR
23551 : LCD_Entry_set $04 OR LCD_WrF ;
23553 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
23555 : LCD_DSP_Shift $10 OR LCD_WrF ;
23557 : LCD_Fn_Set $20 OR LCD_WrF ;
23559 : LCD_CGRAM_Set $40 OR LCD_WrF ;
23561 : LCD_Goto $80 OR LCD_WrF ;
23563 CODE LCD_R \ -- byte read byte from LCD
23564 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
23565 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
23566 COLON \ starts a FORTH word
23567 TOP_LCD 2 20_us \ -- %0000HHHH
23568 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
23569 HI2LO \ switch from FORTH to assembler
23570 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
23571 ADD.B @PSP+,TOS \ -- %HHHHLLLL
23572 MOV @RSP+,IP \ restore IP saved by COLON
23577 CODE LCD_RdS \ -- status Read Status
23578 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
23583 CODE LCD_RdC \ -- char Read Char
23584 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
23590 \ ******************************\
23591 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
23592 \ ******************************\
23593 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
23594 BIT.B #SW2,&SW2_IN \ test switch S2
23595 0= IF \ case of switch S2 pressed
23596 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
23598 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
23601 BIT.B #SW1,&SW1_IN \ test switch S1 input
23602 0= IF \ case of Switch S1 pressed
23603 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
23605 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
23609 BW1 \ from quit on truncated RC5 message
23610 BW2 \ from repeated RC5 command
23611 BW3 \ from end of RC5_INT
23612 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
23617 \ ******************************\
23618 ASM RC5_INT \ wake up on Px.RC5 change interrupt
23619 \ ******************************\
23620 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
23621 \ ******************************\
23622 \ \ in : SR(9)=old Toggle bit memory (ADD on)
23623 \ \ SMclock = 8|16|24 MHz
23624 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
23625 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
23626 \ \ SR(9)=new Toggle bit memory (ADD on)
23627 \ ******************************\
23628 \ RC5_FirstStartBitHalfCycle: \
23629 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
23630 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
23631 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
23632 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
23633 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
23634 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
23635 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
23636 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
23637 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
23638 MOV #1778,X \ RC5_Period * 1us
23639 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
23640 MOV #14,W \ count of loop
23642 \ ******************************\
23643 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
23644 \ ******************************\ |
23645 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
23646 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
23647 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
23648 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
23649 \ RC5_Compute_3/4_Period: \ |
23650 RRUM #1,X \ X=1/2 cycle |
23653 ADD X,Y \ Y=3/4 cycle
23654 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
23656 \ ******************************\
23657 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
23658 \ ******************************\
23659 BIT.B #RC5,&IR_IN \ C_flag = IR bit
23660 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
23661 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
23662 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
23663 SUB #1,W \ decrement count loop
23664 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
23665 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
23666 0<> WHILE \ ----> out of loop ----+
23667 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
23669 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
23670 CMP Y,X \ 1 | cycle time out of bound ?
23671 U>= IF \ 2 ^ | yes:
23672 BIC #$30,&RC5_TIM_CTL \ | | stop timer
23673 GOTO BW1 \ | | quit on truncated RC5 message
23675 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
23677 REPEAT \ ----> loop back --+ | with X = new RC5_period value
23678 \ ******************************\ |
23679 \ RC5_SampleEndOf: \ <---------------------+
23680 \ ******************************\
23681 BIC #$30,&RC5_TIM_CTL \ stop timer
23682 \ ******************************\
23683 \ RC5_ComputeNewRC5word \
23684 \ ******************************\
23685 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
23686 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
23687 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
23688 \ ******************************\
23689 \ RC5_ComputeC6bit \
23690 \ ******************************\
23691 BIT #BIT14,T \ test /C6 bit in T
23692 0= IF BIS #BIT6,X \ set C6 bit in X
23693 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
23694 \ ******************************\
23695 \ RC5_CommandByteIsDone \ -- BASE RC5_code
23696 \ ******************************\
23697 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
23698 \ ******************************\
23699 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
23700 XOR @RSP,T \ (new XOR old) Toggle bits
23701 BIT #UF10,T \ repeated RC5_command ?
23702 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
23703 XOR #UF10,0(RSP) \ 5 toggle bit memory
23704 \ ******************************\
23705 \ Display IR_RC5 code \ X = RC5 code
23706 \ ******************************\
23708 MOV &BASE,2(PSP) \ save current base
23709 MOV #$10,&BASE \ set hex base
23710 MOV TOS,0(PSP) \ save TOS
23712 LO2HI \ switch from assembler to FORTH
23713 ['] LCD_CLEAR IS CR \ redirects CR
23714 ['] LCD_WrC IS EMIT \ redirects EMIT
23715 CR ." $" 2 U.R \ print IR_RC5 code
23716 ['] CR >BODY IS CR \ restore CR
23717 ['] EMIT >BODY IS EMIT \ restore EMIT
23718 HI2LO \ switch from FORTH to assembler
23719 MOV TOS,&BASE \ restore current BASE
23721 \ ******************************\
23723 \ ******************************\
23727 \ ------------------------------\
23729 \ ------------------------------\
23730 \ ... \ insert here your background task
23733 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
23734 ADD #4,X \ 1 X = BODY of SLEEP
23737 \ ------------------------------\
23741 \ ------------------------------\
23742 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
23743 \ - - \CNTL Counter lentgh \ 00 = 16 bits
23744 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
23745 \ -- \ID input divider \ 10 = /4
23746 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
23747 \ - \TBCLR TimerB Clear
23750 \ -------------------------------\
23751 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
23752 \ -- \CM Capture Mode
23757 \ --- \OUTMOD \ 011 = set/reset
23763 \ -------------------------------\
23765 \ -------------------------------\
23767 \ ------------------------------\
23768 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
23769 \ ------------------------------\
23770 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
23771 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
23772 \ ------------------------------\
23773 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
23774 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
23775 \ ------------------------------\
23776 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
23777 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
23778 \ ------------------------------\
23779 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
23780 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
23781 \ ------------------------------\
23782 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
23783 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
23784 \ ------------------------------\
23785 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
23786 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
23787 \ ------------------------------\
23788 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
23789 \ ------------------------------\
23790 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
23791 \ ------------------------------\
23792 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
23793 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
23794 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
23795 \ ------------------------------\
23796 BIS.B #LCDVo,&LCDVo_DIR \
23797 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
23798 \ ------------------------------\
23799 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
23800 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
23801 \ ------------------------------\
23802 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
23803 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
23804 \ ******************************\
23806 \ ******************************\
23807 BIS.B #RC5,&IR_IE \ enable RC5_Int
23808 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
23809 MOV #RC5_INT,&IR_Vec \ init interrupt vector
23810 \ ******************************\
23811 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
23812 \ ******************************\
23813 \ %01 0001 0100 \ TAxCTL
23814 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
23815 \ -- \ ID divided by 1
23816 \ -- \ MC MODE = up to TAxCCRn
23817 \ - \ TACLR clear timer count
23820 \ ------------------------------\
23821 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
23822 \ ------------------------------\
23824 \ --- \ TAIDEX pre divisor
23825 \ ------------------------------\
23826 \ %0000 0000 0000 0101 \ TAxCCR0
23827 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
23828 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
23829 \ ------------------------------\
23830 \ %0000 0000 0001 0000 \ TAxCCTL0
23831 \ - \ CAP capture/compare mode = compare
23834 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
23835 \ ------------------------------\
23836 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
23837 \ ------------------------------\
23838 \ define LPM mode for ACCEPT \
23839 \ ------------------------------\
23840 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
23841 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
23842 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
23844 \ ------------------------------\
23845 \ redirects to background task \
23846 \ ------------------------------\
23848 MOV #BACKGROUND,2(X) \
23849 \ ------------------------------\
23851 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
23853 \ ------------------------------\
23855 \ ------------------------------\
23856 $03E8 20_US \ 1- wait 20 ms
23857 $03 TOP_LCD \ 2- send DB5=DB4=1
23858 $CD 20_US \ 3- wait 4,1 ms
23859 $03 TOP_LCD \ 4- send again DB5=DB4=1
23860 $5 20_US \ 5- wait 0,1 ms
23861 $03 TOP_LCD \ 6- send again again DB5=DB4=1
23862 $2 20_US \ wait 40 us = LCD cycle
23863 $02 TOP_LCD \ 7- send DB5=1 DB4=0
23864 $2 20_US \ wait 40 us = LCD cycle
23865 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
23866 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
23867 LCD_Clear \ 10- "LCD_Clear"
23868 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
23869 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
23870 LCD_Clear \ 10- "LCD_Clear"
23871 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
23872 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
23874 ['] CR >BODY IS CR \
23875 ['] EMIT >BODY IS EMIT \
23876 ." RC5toLCD is running. Type STOP to quit"
23877 LIT RECURSE IS WARM \ replace WARM by this START routine
23878 ABORT \ and continue with the next word after WARM...
23879 ; \ ...until interpreter falls in sleep mode within ACCEPT.
23882 CODE STOP \ stops multitasking, must to be used before downloading app
23883 \ restore default action of primary DEFERred word SLEEP, assembly version
23884 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
23885 ADD #4,X \ X = BODY of SLEEP
23886 MOV X,-2(X) \ restore the default background
23889 \ restore default action of primary DEFERred word WARM, FORTH version
23890 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
23892 COLD \ because we want to reset CPU and interrupt vectors
23897 ; downloading RC5toLCD.4th is done
23898 RST_HERE ; this app is protected against <reset>
23906 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
23908 [DEFINED] ASM [IF] \ security test
23912 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
23914 CODE MAX \ n1 n2 -- n3 signed maximum
23915 CMP @PSP,TOS \ n2-n1
23916 S< ?GOTO FW1 \ n2<n1
23922 CODE MIN \ n1 n2 -- n3 signed minimum
23923 CMP @PSP,TOS \ n2-n1
23924 S< ?GOTO BW1 \ n2<n1
23932 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
23933 : U.R \ u n -- display u unsigned in n width (n >= 2)
23935 R> OVER - 0 MAX SPACES TYPE
23940 \ CODE 20_US \ n -- n * 20 us
23941 \ BEGIN \ 3 cycles loop + 6~
23942 \ \ MOV #5,W \ 3 MCLK = 1 MHz
23943 \ \ MOV #23,W \ 3 MCLK = 4 MHz
23944 \ \ MOV #51,W \ 3 MCLK = 8 MHz
23945 \ MOV #104,W \ 3 MCLK = 16 MHz
23946 \ \ MOV #158,W \ 3 MCLK = 24 MHz
23947 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
23952 \ MOV @PSP+,TOS \ 2
23957 CODE 20_US \ n -- n * 20 us
23958 BEGIN \ here we presume that LCD_TIM_IFG = 1...
23960 BIT #1,&LCD_TIM_CTL \ 3
23961 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
23962 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
23964 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
23970 CODE TOP_LCD \ LCD Sample
23971 \ \ if write : %xxxxWWWW --
23972 \ \ if read : -- %0000RRRR
23973 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
23974 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
23975 0= IF \ write LCD bits pattern
23976 AND.B #LCD_DB,TOS \
23977 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
23978 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
23981 THEN \ read LCD bits pattern
23984 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
23985 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
23986 AND.B #LCD_DB,TOS \
23991 CODE LCD_W \ byte -- write byte to LCD
23993 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
23994 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
23995 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
23996 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
23997 COLON \ high level word starts here
23998 TOP_LCD 2 20_US \ write high nibble first
24003 CODE LCD_WrC \ char -- Write Char
24004 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
24009 CODE LCD_WrF \ func -- Write Fonction
24010 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
24016 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
24021 $02 LCD_WrF 100 20_us
24025 [UNDEFINED] OR [IF]
24027 \ https://forth-standard.org/standard/core/OR
24028 \ C OR x1 x2 -- x3 logical OR
24037 : LCD_Entry_set $04 OR LCD_WrF ;
24039 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
24041 : LCD_DSP_Shift $10 OR LCD_WrF ;
24043 : LCD_Fn_Set $20 OR LCD_WrF ;
24045 : LCD_CGRAM_Set $40 OR LCD_WrF ;
24047 : LCD_Goto $80 OR LCD_WrF ;
24049 CODE LCD_R \ -- byte read byte from LCD
24050 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
24051 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
24052 COLON \ starts a FORTH word
24053 TOP_LCD 2 20_us \ -- %0000HHHH
24054 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
24055 HI2LO \ switch from FORTH to assembler
24056 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
24057 ADD.B @PSP+,TOS \ -- %HHHHLLLL
24058 MOV @RSP+,IP \ restore IP saved by COLON
24063 CODE LCD_RdS \ -- status Read Status
24064 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
24069 CODE LCD_RdC \ -- char Read Char
24070 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
24076 \ ******************************\
24077 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
24078 \ ******************************\
24079 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
24080 BIT.B #SW2,&SW2_IN \ test switch S2
24081 0= IF \ case of switch S2 pressed
24082 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
24084 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
24087 BIT.B #SW1,&SW1_IN \ test switch S1 input
24088 0= IF \ case of Switch S1 pressed
24089 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
24091 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
24095 BW1 \ from quit on truncated RC5 message
24096 BW2 \ from repeated RC5 command
24097 BW3 \ from end of RC5_INT
24098 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
24103 \ ******************************\
24104 ASM RC5_INT \ wake up on Px.RC5 change interrupt
24105 \ ******************************\
24106 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
24107 \ ******************************\
24108 \ \ in : SR(9)=old Toggle bit memory (ADD on)
24109 \ \ SMclock = 8|16|24 MHz
24110 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
24111 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
24112 \ \ SR(9)=new Toggle bit memory (ADD on)
24113 \ ******************************\
24114 \ RC5_FirstStartBitHalfCycle: \
24115 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
24116 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
24117 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
24118 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
24119 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
24120 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
24121 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
24122 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
24123 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
24124 MOV #1778,X \ RC5_Period * 1us
24125 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
24126 MOV #14,W \ count of loop
24128 \ ******************************\
24129 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
24130 \ ******************************\ |
24131 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
24132 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
24133 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
24134 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
24135 \ RC5_Compute_3/4_Period: \ |
24136 RRUM #1,X \ X=1/2 cycle |
24139 ADD X,Y \ Y=3/4 cycle
24140 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
24142 \ ******************************\
24143 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
24144 \ ******************************\
24145 BIT.B #RC5,&IR_IN \ C_flag = IR bit
24146 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
24147 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
24148 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
24149 SUB #1,W \ decrement count loop
24150 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
24151 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
24152 0<> WHILE \ ----> out of loop ----+
24153 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
24155 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
24156 CMP Y,X \ 1 | cycle time out of bound ?
24157 U>= IF \ 2 ^ | yes:
24158 BIC #$30,&RC5_TIM_CTL \ | | stop timer
24159 GOTO BW1 \ | | quit on truncated RC5 message
24161 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
24163 REPEAT \ ----> loop back --+ | with X = new RC5_period value
24164 \ ******************************\ |
24165 \ RC5_SampleEndOf: \ <---------------------+
24166 \ ******************************\
24167 BIC #$30,&RC5_TIM_CTL \ stop timer
24168 \ ******************************\
24169 \ RC5_ComputeNewRC5word \
24170 \ ******************************\
24171 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
24172 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
24173 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
24174 \ ******************************\
24175 \ RC5_ComputeC6bit \
24176 \ ******************************\
24177 BIT #BIT14,T \ test /C6 bit in T
24178 0= IF BIS #BIT6,X \ set C6 bit in X
24179 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
24180 \ ******************************\
24181 \ RC5_CommandByteIsDone \ -- BASE RC5_code
24182 \ ******************************\
24183 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
24184 \ ******************************\
24185 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
24186 XOR @RSP,T \ (new XOR old) Toggle bits
24187 BIT #UF10,T \ repeated RC5_command ?
24188 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
24189 XOR #UF10,0(RSP) \ 5 toggle bit memory
24190 \ ******************************\
24191 \ Display IR_RC5 code \ X = RC5 code
24192 \ ******************************\
24194 MOV &BASE,2(PSP) \ save current base
24195 MOV #$10,&BASE \ set hex base
24196 MOV TOS,0(PSP) \ save TOS
24198 LO2HI \ switch from assembler to FORTH
24199 ['] LCD_CLEAR IS CR \ redirects CR
24200 ['] LCD_WrC IS EMIT \ redirects EMIT
24201 CR ." $" 2 U.R \ print IR_RC5 code
24202 ['] CR >BODY IS CR \ restore CR
24203 ['] EMIT >BODY IS EMIT \ restore EMIT
24204 HI2LO \ switch from FORTH to assembler
24205 MOV TOS,&BASE \ restore current BASE
24207 \ ******************************\
24209 \ ******************************\
24213 \ ------------------------------\
24215 \ ------------------------------\
24216 \ ... \ insert here your background task
24219 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
24220 ADD #4,X \ 1 X = BODY of SLEEP
24223 \ ------------------------------\
24227 \ ------------------------------\
24228 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
24229 \ - - \CNTL Counter lentgh \ 00 = 16 bits
24230 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
24231 \ -- \ID input divider \ 10 = /4
24232 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
24233 \ - \TBCLR TimerB Clear
24236 \ -------------------------------\
24237 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
24238 \ -- \CM Capture Mode
24243 \ --- \OUTMOD \ 011 = set/reset
24249 \ -------------------------------\
24251 \ -------------------------------\
24253 \ ------------------------------\
24254 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
24255 \ ------------------------------\
24256 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
24257 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
24258 \ ------------------------------\
24259 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
24260 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
24261 \ ------------------------------\
24262 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
24263 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
24264 \ ------------------------------\
24265 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
24266 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
24267 \ ------------------------------\
24268 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
24269 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
24270 \ ------------------------------\
24271 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
24272 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
24273 \ ------------------------------\
24274 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
24275 \ ------------------------------\
24276 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
24277 \ ------------------------------\
24278 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
24279 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
24280 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
24281 \ ------------------------------\
24282 BIS.B #LCDVo,&LCDVo_DIR \
24283 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
24284 \ ------------------------------\
24285 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
24286 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
24287 \ ------------------------------\
24288 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
24289 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
24290 \ ******************************\
24292 \ ******************************\
24293 BIS.B #RC5,&IR_IE \ enable RC5_Int
24294 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
24295 MOV #RC5_INT,&IR_Vec \ init interrupt vector
24296 \ ******************************\
24297 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
24298 \ ******************************\
24299 \ %01 0001 0100 \ TAxCTL
24300 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
24301 \ -- \ ID divided by 1
24302 \ -- \ MC MODE = up to TAxCCRn
24303 \ - \ TACLR clear timer count
24306 \ ------------------------------\
24307 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
24308 \ ------------------------------\
24310 \ --- \ TAIDEX pre divisor
24311 \ ------------------------------\
24312 \ %0000 0000 0000 0101 \ TAxCCR0
24313 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
24314 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
24315 \ ------------------------------\
24316 \ %0000 0000 0001 0000 \ TAxCCTL0
24317 \ - \ CAP capture/compare mode = compare
24320 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
24321 \ ------------------------------\
24322 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
24323 \ ------------------------------\
24324 \ define LPM mode for ACCEPT \
24325 \ ------------------------------\
24326 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
24327 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
24328 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
24330 \ ------------------------------\
24331 \ redirects to background task \
24332 \ ------------------------------\
24334 MOV #BACKGROUND,2(X) \
24335 \ ------------------------------\
24337 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
24339 \ ------------------------------\
24341 \ ------------------------------\
24342 $03E8 20_US \ 1- wait 20 ms
24343 $03 TOP_LCD \ 2- send DB5=DB4=1
24344 $CD 20_US \ 3- wait 4,1 ms
24345 $03 TOP_LCD \ 4- send again DB5=DB4=1
24346 $5 20_US \ 5- wait 0,1 ms
24347 $03 TOP_LCD \ 6- send again again DB5=DB4=1
24348 $2 20_US \ wait 40 us = LCD cycle
24349 $02 TOP_LCD \ 7- send DB5=1 DB4=0
24350 $2 20_US \ wait 40 us = LCD cycle
24351 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
24352 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
24353 LCD_Clear \ 10- "LCD_Clear"
24354 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
24355 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
24356 LCD_Clear \ 10- "LCD_Clear"
24357 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
24358 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
24360 ['] CR >BODY IS CR \
24361 ['] EMIT >BODY IS EMIT \
24362 ." RC5toLCD is running. Type STOP to quit"
24363 LIT RECURSE IS WARM \ replace WARM by this START routine
24364 ABORT \ and continue with the next word after WARM...
24365 ; \ ...until interpreter falls in sleep mode within ACCEPT.
24368 CODE STOP \ stops multitasking, must to be used before downloading app
24369 \ restore default action of primary DEFERred word SLEEP, assembly version
24370 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
24371 ADD #4,X \ X = BODY of SLEEP
24372 MOV X,-2(X) \ restore the default background
24375 \ restore default action of primary DEFERred word WARM, FORTH version
24376 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
24378 COLD \ because we want to reset CPU and interrupt vectors
24383 ; downloading RC5toLCD.4th is done
24384 RST_HERE ; this app is protected against <reset>
24392 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
24394 [DEFINED] ASM [IF] \ security test
24398 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
24400 CODE MAX \ n1 n2 -- n3 signed maximum
24401 CMP @PSP,TOS \ n2-n1
24402 S< ?GOTO FW1 \ n2<n1
24408 CODE MIN \ n1 n2 -- n3 signed minimum
24409 CMP @PSP,TOS \ n2-n1
24410 S< ?GOTO BW1 \ n2<n1
24418 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
24419 : U.R \ u n -- display u unsigned in n width (n >= 2)
24421 R> OVER - 0 MAX SPACES TYPE
24426 \ CODE 20_US \ n -- n * 20 us
24427 \ BEGIN \ 3 cycles loop + 6~
24428 \ \ MOV #5,W \ 3 MCLK = 1 MHz
24429 \ \ MOV #23,W \ 3 MCLK = 4 MHz
24430 \ \ MOV #51,W \ 3 MCLK = 8 MHz
24431 \ MOV #104,W \ 3 MCLK = 16 MHz
24432 \ \ MOV #158,W \ 3 MCLK = 24 MHz
24433 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
24438 \ MOV @PSP+,TOS \ 2
24443 CODE 20_US \ n -- n * 20 us
24444 BEGIN \ here we presume that LCD_TIM_IFG = 1...
24446 BIT #1,&LCD_TIM_CTL \ 3
24447 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
24448 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
24450 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
24456 CODE TOP_LCD \ LCD Sample
24457 \ \ if write : %xxxxWWWW --
24458 \ \ if read : -- %0000RRRR
24459 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
24460 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
24461 0= IF \ write LCD bits pattern
24462 AND.B #LCD_DB,TOS \
24463 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
24464 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
24467 THEN \ read LCD bits pattern
24470 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
24471 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
24472 AND.B #LCD_DB,TOS \
24477 CODE LCD_W \ byte -- write byte to LCD
24479 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
24480 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
24481 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
24482 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
24483 COLON \ high level word starts here
24484 TOP_LCD 2 20_US \ write high nibble first
24489 CODE LCD_WrC \ char -- Write Char
24490 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
24495 CODE LCD_WrF \ func -- Write Fonction
24496 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
24502 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
24507 $02 LCD_WrF 100 20_us
24511 [UNDEFINED] OR [IF]
24513 \ https://forth-standard.org/standard/core/OR
24514 \ C OR x1 x2 -- x3 logical OR
24523 : LCD_Entry_set $04 OR LCD_WrF ;
24525 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
24527 : LCD_DSP_Shift $10 OR LCD_WrF ;
24529 : LCD_Fn_Set $20 OR LCD_WrF ;
24531 : LCD_CGRAM_Set $40 OR LCD_WrF ;
24533 : LCD_Goto $80 OR LCD_WrF ;
24535 CODE LCD_R \ -- byte read byte from LCD
24536 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
24537 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
24538 COLON \ starts a FORTH word
24539 TOP_LCD 2 20_us \ -- %0000HHHH
24540 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
24541 HI2LO \ switch from FORTH to assembler
24542 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
24543 ADD.B @PSP+,TOS \ -- %HHHHLLLL
24544 MOV @RSP+,IP \ restore IP saved by COLON
24549 CODE LCD_RdS \ -- status Read Status
24550 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
24555 CODE LCD_RdC \ -- char Read Char
24556 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
24562 \ ******************************\
24563 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
24564 \ ******************************\
24565 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
24566 BIT.B #SW2,&SW2_IN \ test switch S2
24567 0= IF \ case of switch S2 pressed
24568 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
24570 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
24573 BIT.B #SW1,&SW1_IN \ test switch S1 input
24574 0= IF \ case of Switch S1 pressed
24575 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
24577 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
24581 BW1 \ from quit on truncated RC5 message
24582 BW2 \ from repeated RC5 command
24583 BW3 \ from end of RC5_INT
24584 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
24589 \ ******************************\
24590 ASM RC5_INT \ wake up on Px.RC5 change interrupt
24591 \ ******************************\
24592 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
24593 \ ******************************\
24594 \ \ in : SR(9)=old Toggle bit memory (ADD on)
24595 \ \ SMclock = 8|16|24 MHz
24596 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
24597 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
24598 \ \ SR(9)=new Toggle bit memory (ADD on)
24599 \ ******************************\
24600 \ RC5_FirstStartBitHalfCycle: \
24601 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
24602 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
24603 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
24604 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
24605 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
24606 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
24607 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
24608 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
24609 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
24610 MOV #1778,X \ RC5_Period * 1us
24611 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
24612 MOV #14,W \ count of loop
24614 \ ******************************\
24615 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
24616 \ ******************************\ |
24617 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
24618 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
24619 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
24620 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
24621 \ RC5_Compute_3/4_Period: \ |
24622 RRUM #1,X \ X=1/2 cycle |
24625 ADD X,Y \ Y=3/4 cycle
24626 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
24628 \ ******************************\
24629 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
24630 \ ******************************\
24631 BIT.B #RC5,&IR_IN \ C_flag = IR bit
24632 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
24633 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
24634 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
24635 SUB #1,W \ decrement count loop
24636 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
24637 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
24638 0<> WHILE \ ----> out of loop ----+
24639 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
24641 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
24642 CMP Y,X \ 1 | cycle time out of bound ?
24643 U>= IF \ 2 ^ | yes:
24644 BIC #$30,&RC5_TIM_CTL \ | | stop timer
24645 GOTO BW1 \ | | quit on truncated RC5 message
24647 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
24649 REPEAT \ ----> loop back --+ | with X = new RC5_period value
24650 \ ******************************\ |
24651 \ RC5_SampleEndOf: \ <---------------------+
24652 \ ******************************\
24653 BIC #$30,&RC5_TIM_CTL \ stop timer
24654 \ ******************************\
24655 \ RC5_ComputeNewRC5word \
24656 \ ******************************\
24657 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
24658 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
24659 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
24660 \ ******************************\
24661 \ RC5_ComputeC6bit \
24662 \ ******************************\
24663 BIT #BIT14,T \ test /C6 bit in T
24664 0= IF BIS #BIT6,X \ set C6 bit in X
24665 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
24666 \ ******************************\
24667 \ RC5_CommandByteIsDone \ -- BASE RC5_code
24668 \ ******************************\
24669 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
24670 \ ******************************\
24671 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
24672 XOR @RSP,T \ (new XOR old) Toggle bits
24673 BIT #UF10,T \ repeated RC5_command ?
24674 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
24675 XOR #UF10,0(RSP) \ 5 toggle bit memory
24676 \ ******************************\
24677 \ Display IR_RC5 code \ X = RC5 code
24678 \ ******************************\
24680 MOV &BASE,2(PSP) \ save current base
24681 MOV #$10,&BASE \ set hex base
24682 MOV TOS,0(PSP) \ save TOS
24684 LO2HI \ switch from assembler to FORTH
24685 ['] LCD_CLEAR IS CR \ redirects CR
24686 ['] LCD_WrC IS EMIT \ redirects EMIT
24687 CR ." $" 2 U.R \ print IR_RC5 code
24688 ['] CR >BODY IS CR \ restore CR
24689 ['] EMIT >BODY IS EMIT \ restore EMIT
24690 HI2LO \ switch from FORTH to assembler
24691 MOV TOS,&BASE \ restore current BASE
24693 \ ******************************\
24695 \ ******************************\
24699 \ ------------------------------\
24701 \ ------------------------------\
24702 \ ... \ insert here your background task
24705 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
24706 ADD #4,X \ 1 X = BODY of SLEEP
24709 \ ------------------------------\
24713 \ ------------------------------\
24714 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
24715 \ - - \CNTL Counter lentgh \ 00 = 16 bits
24716 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
24717 \ -- \ID input divider \ 10 = /4
24718 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
24719 \ - \TBCLR TimerB Clear
24722 \ -------------------------------\
24723 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
24724 \ -- \CM Capture Mode
24729 \ --- \OUTMOD \ 011 = set/reset
24735 \ -------------------------------\
24737 \ -------------------------------\
24739 \ ------------------------------\
24740 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
24741 \ ------------------------------\
24742 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
24743 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
24744 \ ------------------------------\
24745 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
24746 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
24747 \ ------------------------------\
24748 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
24749 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
24750 \ ------------------------------\
24751 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
24752 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
24753 \ ------------------------------\
24754 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
24755 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
24756 \ ------------------------------\
24757 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
24758 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
24759 \ ------------------------------\
24760 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
24761 \ ------------------------------\
24762 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
24763 \ ------------------------------\
24764 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
24765 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
24766 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
24767 \ ------------------------------\
24768 BIS.B #LCDVo,&LCDVo_DIR \
24769 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
24770 \ ------------------------------\
24771 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
24772 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
24773 \ ------------------------------\
24774 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
24775 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
24776 \ ******************************\
24778 \ ******************************\
24779 BIS.B #RC5,&IR_IE \ enable RC5_Int
24780 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
24781 MOV #RC5_INT,&IR_Vec \ init interrupt vector
24782 \ ******************************\
24783 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
24784 \ ******************************\
24785 \ %01 0001 0100 \ TAxCTL
24786 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
24787 \ -- \ ID divided by 1
24788 \ -- \ MC MODE = up to TAxCCRn
24789 \ - \ TACLR clear timer count
24792 \ ------------------------------\
24793 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
24794 \ ------------------------------\
24796 \ --- \ TAIDEX pre divisor
24797 \ ------------------------------\
24798 \ %0000 0000 0000 0101 \ TAxCCR0
24799 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
24800 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
24801 \ ------------------------------\
24802 \ %0000 0000 0001 0000 \ TAxCCTL0
24803 \ - \ CAP capture/compare mode = compare
24806 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
24807 \ ------------------------------\
24808 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
24809 \ ------------------------------\
24810 \ define LPM mode for ACCEPT \
24811 \ ------------------------------\
24812 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
24813 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
24814 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
24816 \ ------------------------------\
24817 \ redirects to background task \
24818 \ ------------------------------\
24820 MOV #BACKGROUND,2(X) \
24821 \ ------------------------------\
24823 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
24825 \ ------------------------------\
24827 \ ------------------------------\
24828 $03E8 20_US \ 1- wait 20 ms
24829 $03 TOP_LCD \ 2- send DB5=DB4=1
24830 $CD 20_US \ 3- wait 4,1 ms
24831 $03 TOP_LCD \ 4- send again DB5=DB4=1
24832 $5 20_US \ 5- wait 0,1 ms
24833 $03 TOP_LCD \ 6- send again again DB5=DB4=1
24834 $2 20_US \ wait 40 us = LCD cycle
24835 $02 TOP_LCD \ 7- send DB5=1 DB4=0
24836 $2 20_US \ wait 40 us = LCD cycle
24837 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
24838 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
24839 LCD_Clear \ 10- "LCD_Clear"
24840 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
24841 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
24842 LCD_Clear \ 10- "LCD_Clear"
24843 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
24844 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
24846 ['] CR >BODY IS CR \
24847 ['] EMIT >BODY IS EMIT \
24848 ." RC5toLCD is running. Type STOP to quit"
24849 LIT RECURSE IS WARM \ replace WARM by this START routine
24850 ABORT \ and continue with the next word after WARM...
24851 ; \ ...until interpreter falls in sleep mode within ACCEPT.
24854 CODE STOP \ stops multitasking, must to be used before downloading app
24855 \ restore default action of primary DEFERred word SLEEP, assembly version
24856 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
24857 ADD #4,X \ X = BODY of SLEEP
24858 MOV X,-2(X) \ restore the default background
24861 \ restore default action of primary DEFERred word WARM, FORTH version
24862 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
24864 COLD \ because we want to reset CPU and interrupt vectors
24869 ; downloading RC5toLCD.4th is done
24870 RST_HERE ; this app is protected against <reset>
24878 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
24880 [DEFINED] ASM [IF] \ security test
24884 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
24886 CODE MAX \ n1 n2 -- n3 signed maximum
24887 CMP @PSP,TOS \ n2-n1
24888 S< ?GOTO FW1 \ n2<n1
24894 CODE MIN \ n1 n2 -- n3 signed minimum
24895 CMP @PSP,TOS \ n2-n1
24896 S< ?GOTO BW1 \ n2<n1
24904 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
24905 : U.R \ u n -- display u unsigned in n width (n >= 2)
24907 R> OVER - 0 MAX SPACES TYPE
24912 \ CODE 20_US \ n -- n * 20 us
24913 \ BEGIN \ 3 cycles loop + 6~
24914 \ \ MOV #5,W \ 3 MCLK = 1 MHz
24915 \ \ MOV #23,W \ 3 MCLK = 4 MHz
24916 \ \ MOV #51,W \ 3 MCLK = 8 MHz
24917 \ MOV #104,W \ 3 MCLK = 16 MHz
24918 \ \ MOV #158,W \ 3 MCLK = 24 MHz
24919 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
24924 \ MOV @PSP+,TOS \ 2
24929 CODE 20_US \ n -- n * 20 us
24930 BEGIN \ here we presume that LCD_TIM_IFG = 1...
24932 BIT #1,&LCD_TIM_CTL \ 3
24933 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
24934 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
24936 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
24942 CODE TOP_LCD \ LCD Sample
24943 \ \ if write : %xxxxWWWW --
24944 \ \ if read : -- %0000RRRR
24945 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
24946 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
24947 0= IF \ write LCD bits pattern
24948 AND.B #LCD_DB,TOS \
24949 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
24950 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
24953 THEN \ read LCD bits pattern
24956 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
24957 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
24958 AND.B #LCD_DB,TOS \
24963 CODE LCD_W \ byte -- write byte to LCD
24965 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
24966 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
24967 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
24968 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
24969 COLON \ high level word starts here
24970 TOP_LCD 2 20_US \ write high nibble first
24975 CODE LCD_WrC \ char -- Write Char
24976 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
24981 CODE LCD_WrF \ func -- Write Fonction
24982 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
24988 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
24993 $02 LCD_WrF 100 20_us
24997 [UNDEFINED] OR [IF]
24999 \ https://forth-standard.org/standard/core/OR
25000 \ C OR x1 x2 -- x3 logical OR
25009 : LCD_Entry_set $04 OR LCD_WrF ;
25011 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
25013 : LCD_DSP_Shift $10 OR LCD_WrF ;
25015 : LCD_Fn_Set $20 OR LCD_WrF ;
25017 : LCD_CGRAM_Set $40 OR LCD_WrF ;
25019 : LCD_Goto $80 OR LCD_WrF ;
25021 CODE LCD_R \ -- byte read byte from LCD
25022 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
25023 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
25024 COLON \ starts a FORTH word
25025 TOP_LCD 2 20_us \ -- %0000HHHH
25026 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
25027 HI2LO \ switch from FORTH to assembler
25028 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
25029 ADD.B @PSP+,TOS \ -- %HHHHLLLL
25030 MOV @RSP+,IP \ restore IP saved by COLON
25035 CODE LCD_RdS \ -- status Read Status
25036 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
25041 CODE LCD_RdC \ -- char Read Char
25042 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
25048 \ ******************************\
25049 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
25050 \ ******************************\
25051 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
25052 BIT.B #SW2,&SW2_IN \ test switch S2
25053 0= IF \ case of switch S2 pressed
25054 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
25056 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
25059 BIT.B #SW1,&SW1_IN \ test switch S1 input
25060 0= IF \ case of Switch S1 pressed
25061 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
25063 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
25067 BW1 \ from quit on truncated RC5 message
25068 BW2 \ from repeated RC5 command
25069 BW3 \ from end of RC5_INT
25070 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
25075 \ ******************************\
25076 ASM RC5_INT \ wake up on Px.RC5 change interrupt
25077 \ ******************************\
25078 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
25079 \ ******************************\
25080 \ \ in : SR(9)=old Toggle bit memory (ADD on)
25081 \ \ SMclock = 8|16|24 MHz
25082 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
25083 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
25084 \ \ SR(9)=new Toggle bit memory (ADD on)
25085 \ ******************************\
25086 \ RC5_FirstStartBitHalfCycle: \
25087 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
25088 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
25089 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
25090 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
25091 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
25092 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
25093 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
25094 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
25095 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
25096 MOV #1778,X \ RC5_Period * 1us
25097 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
25098 MOV #14,W \ count of loop
25100 \ ******************************\
25101 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
25102 \ ******************************\ |
25103 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
25104 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
25105 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
25106 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
25107 \ RC5_Compute_3/4_Period: \ |
25108 RRUM #1,X \ X=1/2 cycle |
25111 ADD X,Y \ Y=3/4 cycle
25112 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
25114 \ ******************************\
25115 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
25116 \ ******************************\
25117 BIT.B #RC5,&IR_IN \ C_flag = IR bit
25118 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
25119 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
25120 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
25121 SUB #1,W \ decrement count loop
25122 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
25123 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
25124 0<> WHILE \ ----> out of loop ----+
25125 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
25127 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
25128 CMP Y,X \ 1 | cycle time out of bound ?
25129 U>= IF \ 2 ^ | yes:
25130 BIC #$30,&RC5_TIM_CTL \ | | stop timer
25131 GOTO BW1 \ | | quit on truncated RC5 message
25133 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
25135 REPEAT \ ----> loop back --+ | with X = new RC5_period value
25136 \ ******************************\ |
25137 \ RC5_SampleEndOf: \ <---------------------+
25138 \ ******************************\
25139 BIC #$30,&RC5_TIM_CTL \ stop timer
25140 \ ******************************\
25141 \ RC5_ComputeNewRC5word \
25142 \ ******************************\
25143 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
25144 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
25145 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
25146 \ ******************************\
25147 \ RC5_ComputeC6bit \
25148 \ ******************************\
25149 BIT #BIT14,T \ test /C6 bit in T
25150 0= IF BIS #BIT6,X \ set C6 bit in X
25151 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
25152 \ ******************************\
25153 \ RC5_CommandByteIsDone \ -- BASE RC5_code
25154 \ ******************************\
25155 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
25156 \ ******************************\
25157 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
25158 XOR @RSP,T \ (new XOR old) Toggle bits
25159 BIT #UF10,T \ repeated RC5_command ?
25160 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
25161 XOR #UF10,0(RSP) \ 5 toggle bit memory
25162 \ ******************************\
25163 \ Display IR_RC5 code \ X = RC5 code
25164 \ ******************************\
25166 MOV &BASE,2(PSP) \ save current base
25167 MOV #$10,&BASE \ set hex base
25168 MOV TOS,0(PSP) \ save TOS
25170 LO2HI \ switch from assembler to FORTH
25171 ['] LCD_CLEAR IS CR \ redirects CR
25172 ['] LCD_WrC IS EMIT \ redirects EMIT
25173 CR ." $" 2 U.R \ print IR_RC5 code
25174 ['] CR >BODY IS CR \ restore CR
25175 ['] EMIT >BODY IS EMIT \ restore EMIT
25176 HI2LO \ switch from FORTH to assembler
25177 MOV TOS,&BASE \ restore current BASE
25179 \ ******************************\
25181 \ ******************************\
25185 \ ------------------------------\
25187 \ ------------------------------\
25188 \ ... \ insert here your background task
25191 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
25192 ADD #4,X \ 1 X = BODY of SLEEP
25195 \ ------------------------------\
25199 \ ------------------------------\
25200 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
25201 \ - - \CNTL Counter lentgh \ 00 = 16 bits
25202 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
25203 \ -- \ID input divider \ 10 = /4
25204 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
25205 \ - \TBCLR TimerB Clear
25208 \ -------------------------------\
25209 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
25210 \ -- \CM Capture Mode
25215 \ --- \OUTMOD \ 011 = set/reset
25221 \ -------------------------------\
25223 \ -------------------------------\
25225 \ ------------------------------\
25226 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
25227 \ ------------------------------\
25228 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
25229 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
25230 \ ------------------------------\
25231 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
25232 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
25233 \ ------------------------------\
25234 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
25235 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
25236 \ ------------------------------\
25237 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
25238 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
25239 \ ------------------------------\
25240 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
25241 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
25242 \ ------------------------------\
25243 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
25244 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
25245 \ ------------------------------\
25246 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
25247 \ ------------------------------\
25248 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
25249 \ ------------------------------\
25250 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
25251 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
25252 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
25253 \ ------------------------------\
25254 BIS.B #LCDVo,&LCDVo_DIR \
25255 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
25256 \ ------------------------------\
25257 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
25258 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
25259 \ ------------------------------\
25260 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
25261 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
25262 \ ******************************\
25264 \ ******************************\
25265 BIS.B #RC5,&IR_IE \ enable RC5_Int
25266 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
25267 MOV #RC5_INT,&IR_Vec \ init interrupt vector
25268 \ ******************************\
25269 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
25270 \ ******************************\
25271 \ %01 0001 0100 \ TAxCTL
25272 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
25273 \ -- \ ID divided by 1
25274 \ -- \ MC MODE = up to TAxCCRn
25275 \ - \ TACLR clear timer count
25278 \ ------------------------------\
25279 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
25280 \ ------------------------------\
25282 \ --- \ TAIDEX pre divisor
25283 \ ------------------------------\
25284 \ %0000 0000 0000 0101 \ TAxCCR0
25285 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
25286 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
25287 \ ------------------------------\
25288 \ %0000 0000 0001 0000 \ TAxCCTL0
25289 \ - \ CAP capture/compare mode = compare
25292 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
25293 \ ------------------------------\
25294 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
25295 \ ------------------------------\
25296 \ define LPM mode for ACCEPT \
25297 \ ------------------------------\
25298 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
25299 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
25300 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
25302 \ ------------------------------\
25303 \ redirects to background task \
25304 \ ------------------------------\
25306 MOV #BACKGROUND,2(X) \
25307 \ ------------------------------\
25309 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
25311 \ ------------------------------\
25313 \ ------------------------------\
25314 $03E8 20_US \ 1- wait 20 ms
25315 $03 TOP_LCD \ 2- send DB5=DB4=1
25316 $CD 20_US \ 3- wait 4,1 ms
25317 $03 TOP_LCD \ 4- send again DB5=DB4=1
25318 $5 20_US \ 5- wait 0,1 ms
25319 $03 TOP_LCD \ 6- send again again DB5=DB4=1
25320 $2 20_US \ wait 40 us = LCD cycle
25321 $02 TOP_LCD \ 7- send DB5=1 DB4=0
25322 $2 20_US \ wait 40 us = LCD cycle
25323 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
25324 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
25325 LCD_Clear \ 10- "LCD_Clear"
25326 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
25327 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
25328 LCD_Clear \ 10- "LCD_Clear"
25329 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
25330 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
25332 ['] CR >BODY IS CR \
25333 ['] EMIT >BODY IS EMIT \
25334 ." RC5toLCD is running. Type STOP to quit"
25335 LIT RECURSE IS WARM \ replace WARM by this START routine
25336 ABORT \ and continue with the next word after WARM...
25337 ; \ ...until interpreter falls in sleep mode within ACCEPT.
25340 CODE STOP \ stops multitasking, must to be used before downloading app
25341 \ restore default action of primary DEFERred word SLEEP, assembly version
25342 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
25343 ADD #4,X \ X = BODY of SLEEP
25344 MOV X,-2(X) \ restore the default background
25347 \ restore default action of primary DEFERred word WARM, FORTH version
25348 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
25350 COLD \ because we want to reset CPU and interrupt vectors
25355 ; downloading RC5toLCD.4th is done
25356 RST_HERE ; this app is protected against <reset>
25364 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
25366 [DEFINED] ASM [IF] \ security test
25370 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
25372 CODE MAX \ n1 n2 -- n3 signed maximum
25373 CMP @PSP,TOS \ n2-n1
25374 S< ?GOTO FW1 \ n2<n1
25380 CODE MIN \ n1 n2 -- n3 signed minimum
25381 CMP @PSP,TOS \ n2-n1
25382 S< ?GOTO BW1 \ n2<n1
25390 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
25391 : U.R \ u n -- display u unsigned in n width (n >= 2)
25393 R> OVER - 0 MAX SPACES TYPE
25398 \ CODE 20_US \ n -- n * 20 us
25399 \ BEGIN \ 3 cycles loop + 6~
25400 \ \ MOV #5,W \ 3 MCLK = 1 MHz
25401 \ \ MOV #23,W \ 3 MCLK = 4 MHz
25402 \ \ MOV #51,W \ 3 MCLK = 8 MHz
25403 \ MOV #104,W \ 3 MCLK = 16 MHz
25404 \ \ MOV #158,W \ 3 MCLK = 24 MHz
25405 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
25410 \ MOV @PSP+,TOS \ 2
25415 CODE 20_US \ n -- n * 20 us
25416 BEGIN \ here we presume that LCD_TIM_IFG = 1...
25418 BIT #1,&LCD_TIM_CTL \ 3
25419 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
25420 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
25422 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
25428 CODE TOP_LCD \ LCD Sample
25429 \ \ if write : %xxxxWWWW --
25430 \ \ if read : -- %0000RRRR
25431 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
25432 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
25433 0= IF \ write LCD bits pattern
25434 AND.B #LCD_DB,TOS \
25435 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
25436 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
25439 THEN \ read LCD bits pattern
25442 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
25443 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
25444 AND.B #LCD_DB,TOS \
25449 CODE LCD_W \ byte -- write byte to LCD
25451 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
25452 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
25453 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
25454 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
25455 COLON \ high level word starts here
25456 TOP_LCD 2 20_US \ write high nibble first
25461 CODE LCD_WrC \ char -- Write Char
25462 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
25467 CODE LCD_WrF \ func -- Write Fonction
25468 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
25474 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
25479 $02 LCD_WrF 100 20_us
25483 [UNDEFINED] OR [IF]
25485 \ https://forth-standard.org/standard/core/OR
25486 \ C OR x1 x2 -- x3 logical OR
25495 : LCD_Entry_set $04 OR LCD_WrF ;
25497 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
25499 : LCD_DSP_Shift $10 OR LCD_WrF ;
25501 : LCD_Fn_Set $20 OR LCD_WrF ;
25503 : LCD_CGRAM_Set $40 OR LCD_WrF ;
25505 : LCD_Goto $80 OR LCD_WrF ;
25507 CODE LCD_R \ -- byte read byte from LCD
25508 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
25509 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
25510 COLON \ starts a FORTH word
25511 TOP_LCD 2 20_us \ -- %0000HHHH
25512 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
25513 HI2LO \ switch from FORTH to assembler
25514 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
25515 ADD.B @PSP+,TOS \ -- %HHHHLLLL
25516 MOV @RSP+,IP \ restore IP saved by COLON
25521 CODE LCD_RdS \ -- status Read Status
25522 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
25527 CODE LCD_RdC \ -- char Read Char
25528 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
25534 \ ******************************\
25535 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
25536 \ ******************************\
25537 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
25538 BIT.B #SW2,&SW2_IN \ test switch S2
25539 0= IF \ case of switch S2 pressed
25540 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
25542 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
25545 BIT.B #SW1,&SW1_IN \ test switch S1 input
25546 0= IF \ case of Switch S1 pressed
25547 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
25549 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
25553 BW1 \ from quit on truncated RC5 message
25554 BW2 \ from repeated RC5 command
25555 BW3 \ from end of RC5_INT
25556 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
25561 \ ******************************\
25562 ASM RC5_INT \ wake up on Px.RC5 change interrupt
25563 \ ******************************\
25564 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
25565 \ ******************************\
25566 \ \ in : SR(9)=old Toggle bit memory (ADD on)
25567 \ \ SMclock = 8|16|24 MHz
25568 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
25569 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
25570 \ \ SR(9)=new Toggle bit memory (ADD on)
25571 \ ******************************\
25572 \ RC5_FirstStartBitHalfCycle: \
25573 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
25574 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
25575 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
25576 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
25577 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
25578 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
25579 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
25580 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
25581 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
25582 MOV #1778,X \ RC5_Period * 1us
25583 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
25584 MOV #14,W \ count of loop
25586 \ ******************************\
25587 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
25588 \ ******************************\ |
25589 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
25590 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
25591 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
25592 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
25593 \ RC5_Compute_3/4_Period: \ |
25594 RRUM #1,X \ X=1/2 cycle |
25597 ADD X,Y \ Y=3/4 cycle
25598 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
25600 \ ******************************\
25601 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
25602 \ ******************************\
25603 BIT.B #RC5,&IR_IN \ C_flag = IR bit
25604 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
25605 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
25606 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
25607 SUB #1,W \ decrement count loop
25608 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
25609 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
25610 0<> WHILE \ ----> out of loop ----+
25611 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
25613 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
25614 CMP Y,X \ 1 | cycle time out of bound ?
25615 U>= IF \ 2 ^ | yes:
25616 BIC #$30,&RC5_TIM_CTL \ | | stop timer
25617 GOTO BW1 \ | | quit on truncated RC5 message
25619 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
25621 REPEAT \ ----> loop back --+ | with X = new RC5_period value
25622 \ ******************************\ |
25623 \ RC5_SampleEndOf: \ <---------------------+
25624 \ ******************************\
25625 BIC #$30,&RC5_TIM_CTL \ stop timer
25626 \ ******************************\
25627 \ RC5_ComputeNewRC5word \
25628 \ ******************************\
25629 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
25630 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
25631 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
25632 \ ******************************\
25633 \ RC5_ComputeC6bit \
25634 \ ******************************\
25635 BIT #BIT14,T \ test /C6 bit in T
25636 0= IF BIS #BIT6,X \ set C6 bit in X
25637 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
25638 \ ******************************\
25639 \ RC5_CommandByteIsDone \ -- BASE RC5_code
25640 \ ******************************\
25641 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
25642 \ ******************************\
25643 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
25644 XOR @RSP,T \ (new XOR old) Toggle bits
25645 BIT #UF10,T \ repeated RC5_command ?
25646 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
25647 XOR #UF10,0(RSP) \ 5 toggle bit memory
25648 \ ******************************\
25649 \ Display IR_RC5 code \ X = RC5 code
25650 \ ******************************\
25652 MOV &BASE,2(PSP) \ save current base
25653 MOV #$10,&BASE \ set hex base
25654 MOV TOS,0(PSP) \ save TOS
25656 LO2HI \ switch from assembler to FORTH
25657 ['] LCD_CLEAR IS CR \ redirects CR
25658 ['] LCD_WrC IS EMIT \ redirects EMIT
25659 CR ." $" 2 U.R \ print IR_RC5 code
25660 ['] CR >BODY IS CR \ restore CR
25661 ['] EMIT >BODY IS EMIT \ restore EMIT
25662 HI2LO \ switch from FORTH to assembler
25663 MOV TOS,&BASE \ restore current BASE
25665 \ ******************************\
25667 \ ******************************\
25671 \ ------------------------------\
25673 \ ------------------------------\
25674 \ ... \ insert here your background task
25677 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
25678 ADD #4,X \ 1 X = BODY of SLEEP
25681 \ ------------------------------\
25685 \ ------------------------------\
25686 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
25687 \ - - \CNTL Counter lentgh \ 00 = 16 bits
25688 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
25689 \ -- \ID input divider \ 10 = /4
25690 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
25691 \ - \TBCLR TimerB Clear
25694 \ -------------------------------\
25695 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
25696 \ -- \CM Capture Mode
25701 \ --- \OUTMOD \ 011 = set/reset
25707 \ -------------------------------\
25709 \ -------------------------------\
25711 \ ------------------------------\
25712 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
25713 \ ------------------------------\
25714 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
25715 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
25716 \ ------------------------------\
25717 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
25718 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
25719 \ ------------------------------\
25720 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
25721 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
25722 \ ------------------------------\
25723 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
25724 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
25725 \ ------------------------------\
25726 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
25727 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
25728 \ ------------------------------\
25729 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
25730 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
25731 \ ------------------------------\
25732 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
25733 \ ------------------------------\
25734 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
25735 \ ------------------------------\
25736 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
25737 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
25738 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
25739 \ ------------------------------\
25740 BIS.B #LCDVo,&LCDVo_DIR \
25741 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
25742 \ ------------------------------\
25743 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
25744 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
25745 \ ------------------------------\
25746 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
25747 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
25748 \ ******************************\
25750 \ ******************************\
25751 BIS.B #RC5,&IR_IE \ enable RC5_Int
25752 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
25753 MOV #RC5_INT,&IR_Vec \ init interrupt vector
25754 \ ******************************\
25755 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
25756 \ ******************************\
25757 \ %01 0001 0100 \ TAxCTL
25758 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
25759 \ -- \ ID divided by 1
25760 \ -- \ MC MODE = up to TAxCCRn
25761 \ - \ TACLR clear timer count
25764 \ ------------------------------\
25765 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
25766 \ ------------------------------\
25768 \ --- \ TAIDEX pre divisor
25769 \ ------------------------------\
25770 \ %0000 0000 0000 0101 \ TAxCCR0
25771 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
25772 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
25773 \ ------------------------------\
25774 \ %0000 0000 0001 0000 \ TAxCCTL0
25775 \ - \ CAP capture/compare mode = compare
25778 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
25779 \ ------------------------------\
25780 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
25781 \ ------------------------------\
25782 \ define LPM mode for ACCEPT \
25783 \ ------------------------------\
25784 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
25785 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
25786 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
25788 \ ------------------------------\
25789 \ redirects to background task \
25790 \ ------------------------------\
25792 MOV #BACKGROUND,2(X) \
25793 \ ------------------------------\
25795 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
25797 \ ------------------------------\
25799 \ ------------------------------\
25800 $03E8 20_US \ 1- wait 20 ms
25801 $03 TOP_LCD \ 2- send DB5=DB4=1
25802 $CD 20_US \ 3- wait 4,1 ms
25803 $03 TOP_LCD \ 4- send again DB5=DB4=1
25804 $5 20_US \ 5- wait 0,1 ms
25805 $03 TOP_LCD \ 6- send again again DB5=DB4=1
25806 $2 20_US \ wait 40 us = LCD cycle
25807 $02 TOP_LCD \ 7- send DB5=1 DB4=0
25808 $2 20_US \ wait 40 us = LCD cycle
25809 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
25810 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
25811 LCD_Clear \ 10- "LCD_Clear"
25812 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
25813 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
25814 LCD_Clear \ 10- "LCD_Clear"
25815 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
25816 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
25818 ['] CR >BODY IS CR \
25819 ['] EMIT >BODY IS EMIT \
25820 ." RC5toLCD is running. Type STOP to quit"
25821 LIT RECURSE IS WARM \ replace WARM by this START routine
25822 ABORT \ and continue with the next word after WARM...
25823 ; \ ...until interpreter falls in sleep mode within ACCEPT.
25826 CODE STOP \ stops multitasking, must to be used before downloading app
25827 \ restore default action of primary DEFERred word SLEEP, assembly version
25828 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
25829 ADD #4,X \ X = BODY of SLEEP
25830 MOV X,-2(X) \ restore the default background
25833 \ restore default action of primary DEFERred word WARM, FORTH version
25834 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
25836 COLD \ because we want to reset CPU and interrupt vectors
25841 ; downloading RC5toLCD.4th is done
25842 RST_HERE ; this app is protected against <reset>
25850 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
25852 [DEFINED] ASM [IF] \ security test
25856 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
25858 CODE MAX \ n1 n2 -- n3 signed maximum
25859 CMP @PSP,TOS \ n2-n1
25860 S< ?GOTO FW1 \ n2<n1
25866 CODE MIN \ n1 n2 -- n3 signed minimum
25867 CMP @PSP,TOS \ n2-n1
25868 S< ?GOTO BW1 \ n2<n1
25876 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
25877 : U.R \ u n -- display u unsigned in n width (n >= 2)
25879 R> OVER - 0 MAX SPACES TYPE
25884 \ CODE 20_US \ n -- n * 20 us
25885 \ BEGIN \ 3 cycles loop + 6~
25886 \ \ MOV #5,W \ 3 MCLK = 1 MHz
25887 \ \ MOV #23,W \ 3 MCLK = 4 MHz
25888 \ \ MOV #51,W \ 3 MCLK = 8 MHz
25889 \ MOV #104,W \ 3 MCLK = 16 MHz
25890 \ \ MOV #158,W \ 3 MCLK = 24 MHz
25891 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
25896 \ MOV @PSP+,TOS \ 2
25901 CODE 20_US \ n -- n * 20 us
25902 BEGIN \ here we presume that LCD_TIM_IFG = 1...
25904 BIT #1,&LCD_TIM_CTL \ 3
25905 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
25906 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
25908 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
25914 CODE TOP_LCD \ LCD Sample
25915 \ \ if write : %xxxxWWWW --
25916 \ \ if read : -- %0000RRRR
25917 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
25918 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
25919 0= IF \ write LCD bits pattern
25920 AND.B #LCD_DB,TOS \
25921 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
25922 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
25925 THEN \ read LCD bits pattern
25928 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
25929 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
25930 AND.B #LCD_DB,TOS \
25935 CODE LCD_W \ byte -- write byte to LCD
25937 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
25938 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
25939 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
25940 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
25941 COLON \ high level word starts here
25942 TOP_LCD 2 20_US \ write high nibble first
25947 CODE LCD_WrC \ char -- Write Char
25948 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
25953 CODE LCD_WrF \ func -- Write Fonction
25954 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
25960 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
25965 $02 LCD_WrF 100 20_us
25969 [UNDEFINED] OR [IF]
25971 \ https://forth-standard.org/standard/core/OR
25972 \ C OR x1 x2 -- x3 logical OR
25981 : LCD_Entry_set $04 OR LCD_WrF ;
25983 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
25985 : LCD_DSP_Shift $10 OR LCD_WrF ;
25987 : LCD_Fn_Set $20 OR LCD_WrF ;
25989 : LCD_CGRAM_Set $40 OR LCD_WrF ;
25991 : LCD_Goto $80 OR LCD_WrF ;
25993 CODE LCD_R \ -- byte read byte from LCD
25994 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
25995 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
25996 COLON \ starts a FORTH word
25997 TOP_LCD 2 20_us \ -- %0000HHHH
25998 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
25999 HI2LO \ switch from FORTH to assembler
26000 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
26001 ADD.B @PSP+,TOS \ -- %HHHHLLLL
26002 MOV @RSP+,IP \ restore IP saved by COLON
26007 CODE LCD_RdS \ -- status Read Status
26008 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
26013 CODE LCD_RdC \ -- char Read Char
26014 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
26020 \ ******************************\
26021 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
26022 \ ******************************\
26023 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
26024 BIT.B #SW2,&SW2_IN \ test switch S2
26025 0= IF \ case of switch S2 pressed
26026 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
26028 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
26031 BIT.B #SW1,&SW1_IN \ test switch S1 input
26032 0= IF \ case of Switch S1 pressed
26033 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
26035 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
26039 BW1 \ from quit on truncated RC5 message
26040 BW2 \ from repeated RC5 command
26041 BW3 \ from end of RC5_INT
26042 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
26047 \ ******************************\
26048 ASM RC5_INT \ wake up on Px.RC5 change interrupt
26049 \ ******************************\
26050 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
26051 \ ******************************\
26052 \ \ in : SR(9)=old Toggle bit memory (ADD on)
26053 \ \ SMclock = 8|16|24 MHz
26054 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
26055 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
26056 \ \ SR(9)=new Toggle bit memory (ADD on)
26057 \ ******************************\
26058 \ RC5_FirstStartBitHalfCycle: \
26059 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
26060 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
26061 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
26062 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
26063 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
26064 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
26065 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
26066 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
26067 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
26068 MOV #1778,X \ RC5_Period * 1us
26069 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
26070 MOV #14,W \ count of loop
26072 \ ******************************\
26073 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
26074 \ ******************************\ |
26075 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
26076 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
26077 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
26078 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
26079 \ RC5_Compute_3/4_Period: \ |
26080 RRUM #1,X \ X=1/2 cycle |
26083 ADD X,Y \ Y=3/4 cycle
26084 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
26086 \ ******************************\
26087 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
26088 \ ******************************\
26089 BIT.B #RC5,&IR_IN \ C_flag = IR bit
26090 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
26091 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
26092 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
26093 SUB #1,W \ decrement count loop
26094 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
26095 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
26096 0<> WHILE \ ----> out of loop ----+
26097 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
26099 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
26100 CMP Y,X \ 1 | cycle time out of bound ?
26101 U>= IF \ 2 ^ | yes:
26102 BIC #$30,&RC5_TIM_CTL \ | | stop timer
26103 GOTO BW1 \ | | quit on truncated RC5 message
26105 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
26107 REPEAT \ ----> loop back --+ | with X = new RC5_period value
26108 \ ******************************\ |
26109 \ RC5_SampleEndOf: \ <---------------------+
26110 \ ******************************\
26111 BIC #$30,&RC5_TIM_CTL \ stop timer
26112 \ ******************************\
26113 \ RC5_ComputeNewRC5word \
26114 \ ******************************\
26115 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
26116 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
26117 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
26118 \ ******************************\
26119 \ RC5_ComputeC6bit \
26120 \ ******************************\
26121 BIT #BIT14,T \ test /C6 bit in T
26122 0= IF BIS #BIT6,X \ set C6 bit in X
26123 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
26124 \ ******************************\
26125 \ RC5_CommandByteIsDone \ -- BASE RC5_code
26126 \ ******************************\
26127 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
26128 \ ******************************\
26129 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
26130 XOR @RSP,T \ (new XOR old) Toggle bits
26131 BIT #UF10,T \ repeated RC5_command ?
26132 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
26133 XOR #UF10,0(RSP) \ 5 toggle bit memory
26134 \ ******************************\
26135 \ Display IR_RC5 code \ X = RC5 code
26136 \ ******************************\
26138 MOV &BASE,2(PSP) \ save current base
26139 MOV #$10,&BASE \ set hex base
26140 MOV TOS,0(PSP) \ save TOS
26142 LO2HI \ switch from assembler to FORTH
26143 ['] LCD_CLEAR IS CR \ redirects CR
26144 ['] LCD_WrC IS EMIT \ redirects EMIT
26145 CR ." $" 2 U.R \ print IR_RC5 code
26146 ['] CR >BODY IS CR \ restore CR
26147 ['] EMIT >BODY IS EMIT \ restore EMIT
26148 HI2LO \ switch from FORTH to assembler
26149 MOV TOS,&BASE \ restore current BASE
26151 \ ******************************\
26153 \ ******************************\
26157 \ ------------------------------\
26159 \ ------------------------------\
26160 \ ... \ insert here your background task
26163 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
26164 ADD #4,X \ 1 X = BODY of SLEEP
26167 \ ------------------------------\
26171 \ ------------------------------\
26172 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
26173 \ - - \CNTL Counter lentgh \ 00 = 16 bits
26174 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
26175 \ -- \ID input divider \ 10 = /4
26176 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
26177 \ - \TBCLR TimerB Clear
26180 \ -------------------------------\
26181 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
26182 \ -- \CM Capture Mode
26187 \ --- \OUTMOD \ 011 = set/reset
26193 \ -------------------------------\
26195 \ -------------------------------\
26197 \ ------------------------------\
26198 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
26199 \ ------------------------------\
26200 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
26201 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
26202 \ ------------------------------\
26203 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
26204 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
26205 \ ------------------------------\
26206 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
26207 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
26208 \ ------------------------------\
26209 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
26210 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
26211 \ ------------------------------\
26212 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
26213 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
26214 \ ------------------------------\
26215 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
26216 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
26217 \ ------------------------------\
26218 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
26219 \ ------------------------------\
26220 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
26221 \ ------------------------------\
26222 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
26223 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
26224 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
26225 \ ------------------------------\
26226 BIS.B #LCDVo,&LCDVo_DIR \
26227 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
26228 \ ------------------------------\
26229 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
26230 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
26231 \ ------------------------------\
26232 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
26233 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
26234 \ ******************************\
26236 \ ******************************\
26237 BIS.B #RC5,&IR_IE \ enable RC5_Int
26238 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
26239 MOV #RC5_INT,&IR_Vec \ init interrupt vector
26240 \ ******************************\
26241 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
26242 \ ******************************\
26243 \ %01 0001 0100 \ TAxCTL
26244 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
26245 \ -- \ ID divided by 1
26246 \ -- \ MC MODE = up to TAxCCRn
26247 \ - \ TACLR clear timer count
26250 \ ------------------------------\
26251 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
26252 \ ------------------------------\
26254 \ --- \ TAIDEX pre divisor
26255 \ ------------------------------\
26256 \ %0000 0000 0000 0101 \ TAxCCR0
26257 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
26258 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
26259 \ ------------------------------\
26260 \ %0000 0000 0001 0000 \ TAxCCTL0
26261 \ - \ CAP capture/compare mode = compare
26264 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
26265 \ ------------------------------\
26266 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
26267 \ ------------------------------\
26268 \ define LPM mode for ACCEPT \
26269 \ ------------------------------\
26270 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
26271 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
26272 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
26274 \ ------------------------------\
26275 \ redirects to background task \
26276 \ ------------------------------\
26278 MOV #BACKGROUND,2(X) \
26279 \ ------------------------------\
26281 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
26283 \ ------------------------------\
26285 \ ------------------------------\
26286 $03E8 20_US \ 1- wait 20 ms
26287 $03 TOP_LCD \ 2- send DB5=DB4=1
26288 $CD 20_US \ 3- wait 4,1 ms
26289 $03 TOP_LCD \ 4- send again DB5=DB4=1
26290 $5 20_US \ 5- wait 0,1 ms
26291 $03 TOP_LCD \ 6- send again again DB5=DB4=1
26292 $2 20_US \ wait 40 us = LCD cycle
26293 $02 TOP_LCD \ 7- send DB5=1 DB4=0
26294 $2 20_US \ wait 40 us = LCD cycle
26295 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
26296 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
26297 LCD_Clear \ 10- "LCD_Clear"
26298 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
26299 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
26300 LCD_Clear \ 10- "LCD_Clear"
26301 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
26302 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
26304 ['] CR >BODY IS CR \
26305 ['] EMIT >BODY IS EMIT \
26306 ." RC5toLCD is running. Type STOP to quit"
26307 LIT RECURSE IS WARM \ replace WARM by this START routine
26308 ABORT \ and continue with the next word after WARM...
26309 ; \ ...until interpreter falls in sleep mode within ACCEPT.
26312 CODE STOP \ stops multitasking, must to be used before downloading app
26313 \ restore default action of primary DEFERred word SLEEP, assembly version
26314 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
26315 ADD #4,X \ X = BODY of SLEEP
26316 MOV X,-2(X) \ restore the default background
26319 \ restore default action of primary DEFERred word WARM, FORTH version
26320 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
26322 COLD \ because we want to reset CPU and interrupt vectors
26327 ; downloading RC5toLCD.4th is done
26328 RST_HERE ; this app is protected against <reset>
26336 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
26338 [DEFINED] ASM [IF] \ security test
26342 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
26344 CODE MAX \ n1 n2 -- n3 signed maximum
26345 CMP @PSP,TOS \ n2-n1
26346 S< ?GOTO FW1 \ n2<n1
26352 CODE MIN \ n1 n2 -- n3 signed minimum
26353 CMP @PSP,TOS \ n2-n1
26354 S< ?GOTO BW1 \ n2<n1
26362 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
26363 : U.R \ u n -- display u unsigned in n width (n >= 2)
26365 R> OVER - 0 MAX SPACES TYPE
26370 \ CODE 20_US \ n -- n * 20 us
26371 \ BEGIN \ 3 cycles loop + 6~
26372 \ \ MOV #5,W \ 3 MCLK = 1 MHz
26373 \ \ MOV #23,W \ 3 MCLK = 4 MHz
26374 \ \ MOV #51,W \ 3 MCLK = 8 MHz
26375 \ MOV #104,W \ 3 MCLK = 16 MHz
26376 \ \ MOV #158,W \ 3 MCLK = 24 MHz
26377 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
26382 \ MOV @PSP+,TOS \ 2
26387 CODE 20_US \ n -- n * 20 us
26388 BEGIN \ here we presume that LCD_TIM_IFG = 1...
26390 BIT #1,&LCD_TIM_CTL \ 3
26391 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
26392 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
26394 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
26400 CODE TOP_LCD \ LCD Sample
26401 \ \ if write : %xxxxWWWW --
26402 \ \ if read : -- %0000RRRR
26403 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
26404 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
26405 0= IF \ write LCD bits pattern
26406 AND.B #LCD_DB,TOS \
26407 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
26408 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
26411 THEN \ read LCD bits pattern
26414 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
26415 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
26416 AND.B #LCD_DB,TOS \
26421 CODE LCD_W \ byte -- write byte to LCD
26423 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
26424 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
26425 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
26426 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
26427 COLON \ high level word starts here
26428 TOP_LCD 2 20_US \ write high nibble first
26433 CODE LCD_WrC \ char -- Write Char
26434 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
26439 CODE LCD_WrF \ func -- Write Fonction
26440 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
26446 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
26451 $02 LCD_WrF 100 20_us
26455 [UNDEFINED] OR [IF]
26457 \ https://forth-standard.org/standard/core/OR
26458 \ C OR x1 x2 -- x3 logical OR
26467 : LCD_Entry_set $04 OR LCD_WrF ;
26469 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
26471 : LCD_DSP_Shift $10 OR LCD_WrF ;
26473 : LCD_Fn_Set $20 OR LCD_WrF ;
26475 : LCD_CGRAM_Set $40 OR LCD_WrF ;
26477 : LCD_Goto $80 OR LCD_WrF ;
26479 CODE LCD_R \ -- byte read byte from LCD
26480 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
26481 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
26482 COLON \ starts a FORTH word
26483 TOP_LCD 2 20_us \ -- %0000HHHH
26484 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
26485 HI2LO \ switch from FORTH to assembler
26486 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
26487 ADD.B @PSP+,TOS \ -- %HHHHLLLL
26488 MOV @RSP+,IP \ restore IP saved by COLON
26493 CODE LCD_RdS \ -- status Read Status
26494 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
26499 CODE LCD_RdC \ -- char Read Char
26500 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
26506 \ ******************************\
26507 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
26508 \ ******************************\
26509 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
26510 BIT.B #SW2,&SW2_IN \ test switch S2
26511 0= IF \ case of switch S2 pressed
26512 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
26514 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
26517 BIT.B #SW1,&SW1_IN \ test switch S1 input
26518 0= IF \ case of Switch S1 pressed
26519 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
26521 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
26525 BW1 \ from quit on truncated RC5 message
26526 BW2 \ from repeated RC5 command
26527 BW3 \ from end of RC5_INT
26528 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
26533 \ ******************************\
26534 ASM RC5_INT \ wake up on Px.RC5 change interrupt
26535 \ ******************************\
26536 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
26537 \ ******************************\
26538 \ \ in : SR(9)=old Toggle bit memory (ADD on)
26539 \ \ SMclock = 8|16|24 MHz
26540 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
26541 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
26542 \ \ SR(9)=new Toggle bit memory (ADD on)
26543 \ ******************************\
26544 \ RC5_FirstStartBitHalfCycle: \
26545 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
26546 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
26547 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
26548 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
26549 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
26550 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
26551 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
26552 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
26553 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
26554 MOV #1778,X \ RC5_Period * 1us
26555 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
26556 MOV #14,W \ count of loop
26558 \ ******************************\
26559 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
26560 \ ******************************\ |
26561 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
26562 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
26563 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
26564 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
26565 \ RC5_Compute_3/4_Period: \ |
26566 RRUM #1,X \ X=1/2 cycle |
26569 ADD X,Y \ Y=3/4 cycle
26570 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
26572 \ ******************************\
26573 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
26574 \ ******************************\
26575 BIT.B #RC5,&IR_IN \ C_flag = IR bit
26576 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
26577 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
26578 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
26579 SUB #1,W \ decrement count loop
26580 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
26581 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
26582 0<> WHILE \ ----> out of loop ----+
26583 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
26585 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
26586 CMP Y,X \ 1 | cycle time out of bound ?
26587 U>= IF \ 2 ^ | yes:
26588 BIC #$30,&RC5_TIM_CTL \ | | stop timer
26589 GOTO BW1 \ | | quit on truncated RC5 message
26591 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
26593 REPEAT \ ----> loop back --+ | with X = new RC5_period value
26594 \ ******************************\ |
26595 \ RC5_SampleEndOf: \ <---------------------+
26596 \ ******************************\
26597 BIC #$30,&RC5_TIM_CTL \ stop timer
26598 \ ******************************\
26599 \ RC5_ComputeNewRC5word \
26600 \ ******************************\
26601 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
26602 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
26603 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
26604 \ ******************************\
26605 \ RC5_ComputeC6bit \
26606 \ ******************************\
26607 BIT #BIT14,T \ test /C6 bit in T
26608 0= IF BIS #BIT6,X \ set C6 bit in X
26609 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
26610 \ ******************************\
26611 \ RC5_CommandByteIsDone \ -- BASE RC5_code
26612 \ ******************************\
26613 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
26614 \ ******************************\
26615 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
26616 XOR @RSP,T \ (new XOR old) Toggle bits
26617 BIT #UF10,T \ repeated RC5_command ?
26618 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
26619 XOR #UF10,0(RSP) \ 5 toggle bit memory
26620 \ ******************************\
26621 \ Display IR_RC5 code \ X = RC5 code
26622 \ ******************************\
26624 MOV &BASE,2(PSP) \ save current base
26625 MOV #$10,&BASE \ set hex base
26626 MOV TOS,0(PSP) \ save TOS
26628 LO2HI \ switch from assembler to FORTH
26629 ['] LCD_CLEAR IS CR \ redirects CR
26630 ['] LCD_WrC IS EMIT \ redirects EMIT
26631 CR ." $" 2 U.R \ print IR_RC5 code
26632 ['] CR >BODY IS CR \ restore CR
26633 ['] EMIT >BODY IS EMIT \ restore EMIT
26634 HI2LO \ switch from FORTH to assembler
26635 MOV TOS,&BASE \ restore current BASE
26637 \ ******************************\
26639 \ ******************************\
26643 \ ------------------------------\
26645 \ ------------------------------\
26646 \ ... \ insert here your background task
26649 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
26650 ADD #4,X \ 1 X = BODY of SLEEP
26653 \ ------------------------------\
26657 \ ------------------------------\
26658 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
26659 \ - - \CNTL Counter lentgh \ 00 = 16 bits
26660 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
26661 \ -- \ID input divider \ 10 = /4
26662 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
26663 \ - \TBCLR TimerB Clear
26666 \ -------------------------------\
26667 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
26668 \ -- \CM Capture Mode
26673 \ --- \OUTMOD \ 011 = set/reset
26679 \ -------------------------------\
26681 \ -------------------------------\
26683 \ ------------------------------\
26684 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
26685 \ ------------------------------\
26686 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
26687 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
26688 \ ------------------------------\
26689 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
26690 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
26691 \ ------------------------------\
26692 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
26693 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
26694 \ ------------------------------\
26695 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
26696 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
26697 \ ------------------------------\
26698 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
26699 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
26700 \ ------------------------------\
26701 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
26702 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
26703 \ ------------------------------\
26704 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
26705 \ ------------------------------\
26706 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
26707 \ ------------------------------\
26708 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
26709 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
26710 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
26711 \ ------------------------------\
26712 BIS.B #LCDVo,&LCDVo_DIR \
26713 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
26714 \ ------------------------------\
26715 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
26716 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
26717 \ ------------------------------\
26718 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
26719 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
26720 \ ******************************\
26722 \ ******************************\
26723 BIS.B #RC5,&IR_IE \ enable RC5_Int
26724 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
26725 MOV #RC5_INT,&IR_Vec \ init interrupt vector
26726 \ ******************************\
26727 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
26728 \ ******************************\
26729 \ %01 0001 0100 \ TAxCTL
26730 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
26731 \ -- \ ID divided by 1
26732 \ -- \ MC MODE = up to TAxCCRn
26733 \ - \ TACLR clear timer count
26736 \ ------------------------------\
26737 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
26738 \ ------------------------------\
26740 \ --- \ TAIDEX pre divisor
26741 \ ------------------------------\
26742 \ %0000 0000 0000 0101 \ TAxCCR0
26743 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
26744 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
26745 \ ------------------------------\
26746 \ %0000 0000 0001 0000 \ TAxCCTL0
26747 \ - \ CAP capture/compare mode = compare
26750 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
26751 \ ------------------------------\
26752 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
26753 \ ------------------------------\
26754 \ define LPM mode for ACCEPT \
26755 \ ------------------------------\
26756 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
26757 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
26758 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
26760 \ ------------------------------\
26761 \ redirects to background task \
26762 \ ------------------------------\
26764 MOV #BACKGROUND,2(X) \
26765 \ ------------------------------\
26767 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
26769 \ ------------------------------\
26771 \ ------------------------------\
26772 $03E8 20_US \ 1- wait 20 ms
26773 $03 TOP_LCD \ 2- send DB5=DB4=1
26774 $CD 20_US \ 3- wait 4,1 ms
26775 $03 TOP_LCD \ 4- send again DB5=DB4=1
26776 $5 20_US \ 5- wait 0,1 ms
26777 $03 TOP_LCD \ 6- send again again DB5=DB4=1
26778 $2 20_US \ wait 40 us = LCD cycle
26779 $02 TOP_LCD \ 7- send DB5=1 DB4=0
26780 $2 20_US \ wait 40 us = LCD cycle
26781 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
26782 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
26783 LCD_Clear \ 10- "LCD_Clear"
26784 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
26785 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
26786 LCD_Clear \ 10- "LCD_Clear"
26787 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
26788 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
26790 ['] CR >BODY IS CR \
26791 ['] EMIT >BODY IS EMIT \
26792 ." RC5toLCD is running. Type STOP to quit"
26793 LIT RECURSE IS WARM \ replace WARM by this START routine
26794 ABORT \ and continue with the next word after WARM...
26795 ; \ ...until interpreter falls in sleep mode within ACCEPT.
26798 CODE STOP \ stops multitasking, must to be used before downloading app
26799 \ restore default action of primary DEFERred word SLEEP, assembly version
26800 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
26801 ADD #4,X \ X = BODY of SLEEP
26802 MOV X,-2(X) \ restore the default background
26805 \ restore default action of primary DEFERred word WARM, FORTH version
26806 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
26808 COLD \ because we want to reset CPU and interrupt vectors
26813 ; downloading RC5toLCD.4th is done
26814 RST_HERE ; this app is protected against <reset>
26822 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
26824 [DEFINED] ASM [IF] \ security test
26828 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
26830 CODE MAX \ n1 n2 -- n3 signed maximum
26831 CMP @PSP,TOS \ n2-n1
26832 S< ?GOTO FW1 \ n2<n1
26838 CODE MIN \ n1 n2 -- n3 signed minimum
26839 CMP @PSP,TOS \ n2-n1
26840 S< ?GOTO BW1 \ n2<n1
26848 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
26849 : U.R \ u n -- display u unsigned in n width (n >= 2)
26851 R> OVER - 0 MAX SPACES TYPE
26856 \ CODE 20_US \ n -- n * 20 us
26857 \ BEGIN \ 3 cycles loop + 6~
26858 \ \ MOV #5,W \ 3 MCLK = 1 MHz
26859 \ \ MOV #23,W \ 3 MCLK = 4 MHz
26860 \ \ MOV #51,W \ 3 MCLK = 8 MHz
26861 \ MOV #104,W \ 3 MCLK = 16 MHz
26862 \ \ MOV #158,W \ 3 MCLK = 24 MHz
26863 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
26868 \ MOV @PSP+,TOS \ 2
26873 CODE 20_US \ n -- n * 20 us
26874 BEGIN \ here we presume that LCD_TIM_IFG = 1...
26876 BIT #1,&LCD_TIM_CTL \ 3
26877 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
26878 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
26880 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
26886 CODE TOP_LCD \ LCD Sample
26887 \ \ if write : %xxxxWWWW --
26888 \ \ if read : -- %0000RRRR
26889 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
26890 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
26891 0= IF \ write LCD bits pattern
26892 AND.B #LCD_DB,TOS \
26893 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
26894 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
26897 THEN \ read LCD bits pattern
26900 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
26901 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
26902 AND.B #LCD_DB,TOS \
26907 CODE LCD_W \ byte -- write byte to LCD
26909 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
26910 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
26911 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
26912 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
26913 COLON \ high level word starts here
26914 TOP_LCD 2 20_US \ write high nibble first
26919 CODE LCD_WrC \ char -- Write Char
26920 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
26925 CODE LCD_WrF \ func -- Write Fonction
26926 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
26932 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
26937 $02 LCD_WrF 100 20_us
26941 [UNDEFINED] OR [IF]
26943 \ https://forth-standard.org/standard/core/OR
26944 \ C OR x1 x2 -- x3 logical OR
26953 : LCD_Entry_set $04 OR LCD_WrF ;
26955 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
26957 : LCD_DSP_Shift $10 OR LCD_WrF ;
26959 : LCD_Fn_Set $20 OR LCD_WrF ;
26961 : LCD_CGRAM_Set $40 OR LCD_WrF ;
26963 : LCD_Goto $80 OR LCD_WrF ;
26965 CODE LCD_R \ -- byte read byte from LCD
26966 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
26967 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
26968 COLON \ starts a FORTH word
26969 TOP_LCD 2 20_us \ -- %0000HHHH
26970 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
26971 HI2LO \ switch from FORTH to assembler
26972 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
26973 ADD.B @PSP+,TOS \ -- %HHHHLLLL
26974 MOV @RSP+,IP \ restore IP saved by COLON
26979 CODE LCD_RdS \ -- status Read Status
26980 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
26985 CODE LCD_RdC \ -- char Read Char
26986 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
26992 \ ******************************\
26993 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
26994 \ ******************************\
26995 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
26996 BIT.B #SW2,&SW2_IN \ test switch S2
26997 0= IF \ case of switch S2 pressed
26998 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
27000 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
27003 BIT.B #SW1,&SW1_IN \ test switch S1 input
27004 0= IF \ case of Switch S1 pressed
27005 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
27007 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
27011 BW1 \ from quit on truncated RC5 message
27012 BW2 \ from repeated RC5 command
27013 BW3 \ from end of RC5_INT
27014 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
27019 \ ******************************\
27020 ASM RC5_INT \ wake up on Px.RC5 change interrupt
27021 \ ******************************\
27022 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
27023 \ ******************************\
27024 \ \ in : SR(9)=old Toggle bit memory (ADD on)
27025 \ \ SMclock = 8|16|24 MHz
27026 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
27027 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
27028 \ \ SR(9)=new Toggle bit memory (ADD on)
27029 \ ******************************\
27030 \ RC5_FirstStartBitHalfCycle: \
27031 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
27032 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
27033 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
27034 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
27035 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
27036 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
27037 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
27038 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
27039 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
27040 MOV #1778,X \ RC5_Period * 1us
27041 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
27042 MOV #14,W \ count of loop
27044 \ ******************************\
27045 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
27046 \ ******************************\ |
27047 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
27048 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
27049 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
27050 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
27051 \ RC5_Compute_3/4_Period: \ |
27052 RRUM #1,X \ X=1/2 cycle |
27055 ADD X,Y \ Y=3/4 cycle
27056 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
27058 \ ******************************\
27059 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
27060 \ ******************************\
27061 BIT.B #RC5,&IR_IN \ C_flag = IR bit
27062 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
27063 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
27064 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
27065 SUB #1,W \ decrement count loop
27066 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
27067 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
27068 0<> WHILE \ ----> out of loop ----+
27069 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
27071 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
27072 CMP Y,X \ 1 | cycle time out of bound ?
27073 U>= IF \ 2 ^ | yes:
27074 BIC #$30,&RC5_TIM_CTL \ | | stop timer
27075 GOTO BW1 \ | | quit on truncated RC5 message
27077 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
27079 REPEAT \ ----> loop back --+ | with X = new RC5_period value
27080 \ ******************************\ |
27081 \ RC5_SampleEndOf: \ <---------------------+
27082 \ ******************************\
27083 BIC #$30,&RC5_TIM_CTL \ stop timer
27084 \ ******************************\
27085 \ RC5_ComputeNewRC5word \
27086 \ ******************************\
27087 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
27088 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
27089 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
27090 \ ******************************\
27091 \ RC5_ComputeC6bit \
27092 \ ******************************\
27093 BIT #BIT14,T \ test /C6 bit in T
27094 0= IF BIS #BIT6,X \ set C6 bit in X
27095 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
27096 \ ******************************\
27097 \ RC5_CommandByteIsDone \ -- BASE RC5_code
27098 \ ******************************\
27099 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
27100 \ ******************************\
27101 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
27102 XOR @RSP,T \ (new XOR old) Toggle bits
27103 BIT #UF10,T \ repeated RC5_command ?
27104 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
27105 XOR #UF10,0(RSP) \ 5 toggle bit memory
27106 \ ******************************\
27107 \ Display IR_RC5 code \ X = RC5 code
27108 \ ******************************\
27110 MOV &BASE,2(PSP) \ save current base
27111 MOV #$10,&BASE \ set hex base
27112 MOV TOS,0(PSP) \ save TOS
27114 LO2HI \ switch from assembler to FORTH
27115 ['] LCD_CLEAR IS CR \ redirects CR
27116 ['] LCD_WrC IS EMIT \ redirects EMIT
27117 CR ." $" 2 U.R \ print IR_RC5 code
27118 ['] CR >BODY IS CR \ restore CR
27119 ['] EMIT >BODY IS EMIT \ restore EMIT
27120 HI2LO \ switch from FORTH to assembler
27121 MOV TOS,&BASE \ restore current BASE
27123 \ ******************************\
27125 \ ******************************\
27129 \ ------------------------------\
27131 \ ------------------------------\
27132 \ ... \ insert here your background task
27135 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
27136 ADD #4,X \ 1 X = BODY of SLEEP
27139 \ ------------------------------\
27143 \ ------------------------------\
27144 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
27145 \ - - \CNTL Counter lentgh \ 00 = 16 bits
27146 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
27147 \ -- \ID input divider \ 10 = /4
27148 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
27149 \ - \TBCLR TimerB Clear
27152 \ -------------------------------\
27153 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
27154 \ -- \CM Capture Mode
27159 \ --- \OUTMOD \ 011 = set/reset
27165 \ -------------------------------\
27167 \ -------------------------------\
27169 \ ------------------------------\
27170 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
27171 \ ------------------------------\
27172 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
27173 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
27174 \ ------------------------------\
27175 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
27176 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
27177 \ ------------------------------\
27178 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
27179 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
27180 \ ------------------------------\
27181 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
27182 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
27183 \ ------------------------------\
27184 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
27185 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
27186 \ ------------------------------\
27187 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
27188 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
27189 \ ------------------------------\
27190 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
27191 \ ------------------------------\
27192 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
27193 \ ------------------------------\
27194 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
27195 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
27196 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
27197 \ ------------------------------\
27198 BIS.B #LCDVo,&LCDVo_DIR \
27199 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
27200 \ ------------------------------\
27201 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
27202 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
27203 \ ------------------------------\
27204 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
27205 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
27206 \ ******************************\
27208 \ ******************************\
27209 BIS.B #RC5,&IR_IE \ enable RC5_Int
27210 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
27211 MOV #RC5_INT,&IR_Vec \ init interrupt vector
27212 \ ******************************\
27213 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
27214 \ ******************************\
27215 \ %01 0001 0100 \ TAxCTL
27216 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
27217 \ -- \ ID divided by 1
27218 \ -- \ MC MODE = up to TAxCCRn
27219 \ - \ TACLR clear timer count
27222 \ ------------------------------\
27223 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
27224 \ ------------------------------\
27226 \ --- \ TAIDEX pre divisor
27227 \ ------------------------------\
27228 \ %0000 0000 0000 0101 \ TAxCCR0
27229 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
27230 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
27231 \ ------------------------------\
27232 \ %0000 0000 0001 0000 \ TAxCCTL0
27233 \ - \ CAP capture/compare mode = compare
27236 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
27237 \ ------------------------------\
27238 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
27239 \ ------------------------------\
27240 \ define LPM mode for ACCEPT \
27241 \ ------------------------------\
27242 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
27243 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
27244 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
27246 \ ------------------------------\
27247 \ redirects to background task \
27248 \ ------------------------------\
27250 MOV #BACKGROUND,2(X) \
27251 \ ------------------------------\
27253 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
27255 \ ------------------------------\
27257 \ ------------------------------\
27258 $03E8 20_US \ 1- wait 20 ms
27259 $03 TOP_LCD \ 2- send DB5=DB4=1
27260 $CD 20_US \ 3- wait 4,1 ms
27261 $03 TOP_LCD \ 4- send again DB5=DB4=1
27262 $5 20_US \ 5- wait 0,1 ms
27263 $03 TOP_LCD \ 6- send again again DB5=DB4=1
27264 $2 20_US \ wait 40 us = LCD cycle
27265 $02 TOP_LCD \ 7- send DB5=1 DB4=0
27266 $2 20_US \ wait 40 us = LCD cycle
27267 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
27268 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
27269 LCD_Clear \ 10- "LCD_Clear"
27270 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
27271 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
27272 LCD_Clear \ 10- "LCD_Clear"
27273 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
27274 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
27276 ['] CR >BODY IS CR \
27277 ['] EMIT >BODY IS EMIT \
27278 ." RC5toLCD is running. Type STOP to quit"
27279 LIT RECURSE IS WARM \ replace WARM by this START routine
27280 ABORT \ and continue with the next word after WARM...
27281 ; \ ...until interpreter falls in sleep mode within ACCEPT.
27284 CODE STOP \ stops multitasking, must to be used before downloading app
27285 \ restore default action of primary DEFERred word SLEEP, assembly version
27286 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
27287 ADD #4,X \ X = BODY of SLEEP
27288 MOV X,-2(X) \ restore the default background
27291 \ restore default action of primary DEFERred word WARM, FORTH version
27292 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
27294 COLD \ because we want to reset CPU and interrupt vectors
27299 ; downloading RC5toLCD.4th is done
27300 RST_HERE ; this app is protected against <reset>
27308 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
27310 [DEFINED] ASM [IF] \ security test
27314 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
27316 CODE MAX \ n1 n2 -- n3 signed maximum
27317 CMP @PSP,TOS \ n2-n1
27318 S< ?GOTO FW1 \ n2<n1
27324 CODE MIN \ n1 n2 -- n3 signed minimum
27325 CMP @PSP,TOS \ n2-n1
27326 S< ?GOTO BW1 \ n2<n1
27334 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
27335 : U.R \ u n -- display u unsigned in n width (n >= 2)
27337 R> OVER - 0 MAX SPACES TYPE
27342 \ CODE 20_US \ n -- n * 20 us
27343 \ BEGIN \ 3 cycles loop + 6~
27344 \ \ MOV #5,W \ 3 MCLK = 1 MHz
27345 \ \ MOV #23,W \ 3 MCLK = 4 MHz
27346 \ \ MOV #51,W \ 3 MCLK = 8 MHz
27347 \ MOV #104,W \ 3 MCLK = 16 MHz
27348 \ \ MOV #158,W \ 3 MCLK = 24 MHz
27349 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
27354 \ MOV @PSP+,TOS \ 2
27359 CODE 20_US \ n -- n * 20 us
27360 BEGIN \ here we presume that LCD_TIM_IFG = 1...
27362 BIT #1,&LCD_TIM_CTL \ 3
27363 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
27364 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
27366 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
27372 CODE TOP_LCD \ LCD Sample
27373 \ \ if write : %xxxxWWWW --
27374 \ \ if read : -- %0000RRRR
27375 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
27376 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
27377 0= IF \ write LCD bits pattern
27378 AND.B #LCD_DB,TOS \
27379 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
27380 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
27383 THEN \ read LCD bits pattern
27386 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
27387 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
27388 AND.B #LCD_DB,TOS \
27393 CODE LCD_W \ byte -- write byte to LCD
27395 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
27396 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
27397 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
27398 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
27399 COLON \ high level word starts here
27400 TOP_LCD 2 20_US \ write high nibble first
27405 CODE LCD_WrC \ char -- Write Char
27406 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
27411 CODE LCD_WrF \ func -- Write Fonction
27412 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
27418 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
27423 $02 LCD_WrF 100 20_us
27427 [UNDEFINED] OR [IF]
27429 \ https://forth-standard.org/standard/core/OR
27430 \ C OR x1 x2 -- x3 logical OR
27439 : LCD_Entry_set $04 OR LCD_WrF ;
27441 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
27443 : LCD_DSP_Shift $10 OR LCD_WrF ;
27445 : LCD_Fn_Set $20 OR LCD_WrF ;
27447 : LCD_CGRAM_Set $40 OR LCD_WrF ;
27449 : LCD_Goto $80 OR LCD_WrF ;
27451 CODE LCD_R \ -- byte read byte from LCD
27452 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
27453 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
27454 COLON \ starts a FORTH word
27455 TOP_LCD 2 20_us \ -- %0000HHHH
27456 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
27457 HI2LO \ switch from FORTH to assembler
27458 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
27459 ADD.B @PSP+,TOS \ -- %HHHHLLLL
27460 MOV @RSP+,IP \ restore IP saved by COLON
27465 CODE LCD_RdS \ -- status Read Status
27466 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
27471 CODE LCD_RdC \ -- char Read Char
27472 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
27478 \ ******************************\
27479 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
27480 \ ******************************\
27481 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
27482 BIT.B #SW2,&SW2_IN \ test switch S2
27483 0= IF \ case of switch S2 pressed
27484 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
27486 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
27489 BIT.B #SW1,&SW1_IN \ test switch S1 input
27490 0= IF \ case of Switch S1 pressed
27491 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
27493 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
27497 BW1 \ from quit on truncated RC5 message
27498 BW2 \ from repeated RC5 command
27499 BW3 \ from end of RC5_INT
27500 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
27505 \ ******************************\
27506 ASM RC5_INT \ wake up on Px.RC5 change interrupt
27507 \ ******************************\
27508 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
27509 \ ******************************\
27510 \ \ in : SR(9)=old Toggle bit memory (ADD on)
27511 \ \ SMclock = 8|16|24 MHz
27512 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
27513 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
27514 \ \ SR(9)=new Toggle bit memory (ADD on)
27515 \ ******************************\
27516 \ RC5_FirstStartBitHalfCycle: \
27517 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
27518 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
27519 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
27520 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
27521 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
27522 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
27523 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
27524 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
27525 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
27526 MOV #1778,X \ RC5_Period * 1us
27527 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
27528 MOV #14,W \ count of loop
27530 \ ******************************\
27531 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
27532 \ ******************************\ |
27533 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
27534 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
27535 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
27536 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
27537 \ RC5_Compute_3/4_Period: \ |
27538 RRUM #1,X \ X=1/2 cycle |
27541 ADD X,Y \ Y=3/4 cycle
27542 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
27544 \ ******************************\
27545 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
27546 \ ******************************\
27547 BIT.B #RC5,&IR_IN \ C_flag = IR bit
27548 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
27549 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
27550 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
27551 SUB #1,W \ decrement count loop
27552 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
27553 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
27554 0<> WHILE \ ----> out of loop ----+
27555 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
27557 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
27558 CMP Y,X \ 1 | cycle time out of bound ?
27559 U>= IF \ 2 ^ | yes:
27560 BIC #$30,&RC5_TIM_CTL \ | | stop timer
27561 GOTO BW1 \ | | quit on truncated RC5 message
27563 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
27565 REPEAT \ ----> loop back --+ | with X = new RC5_period value
27566 \ ******************************\ |
27567 \ RC5_SampleEndOf: \ <---------------------+
27568 \ ******************************\
27569 BIC #$30,&RC5_TIM_CTL \ stop timer
27570 \ ******************************\
27571 \ RC5_ComputeNewRC5word \
27572 \ ******************************\
27573 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
27574 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
27575 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
27576 \ ******************************\
27577 \ RC5_ComputeC6bit \
27578 \ ******************************\
27579 BIT #BIT14,T \ test /C6 bit in T
27580 0= IF BIS #BIT6,X \ set C6 bit in X
27581 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
27582 \ ******************************\
27583 \ RC5_CommandByteIsDone \ -- BASE RC5_code
27584 \ ******************************\
27585 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
27586 \ ******************************\
27587 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
27588 XOR @RSP,T \ (new XOR old) Toggle bits
27589 BIT #UF10,T \ repeated RC5_command ?
27590 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
27591 XOR #UF10,0(RSP) \ 5 toggle bit memory
27592 \ ******************************\
27593 \ Display IR_RC5 code \ X = RC5 code
27594 \ ******************************\
27596 MOV &BASE,2(PSP) \ save current base
27597 MOV #$10,&BASE \ set hex base
27598 MOV TOS,0(PSP) \ save TOS
27600 LO2HI \ switch from assembler to FORTH
27601 ['] LCD_CLEAR IS CR \ redirects CR
27602 ['] LCD_WrC IS EMIT \ redirects EMIT
27603 CR ." $" 2 U.R \ print IR_RC5 code
27604 ['] CR >BODY IS CR \ restore CR
27605 ['] EMIT >BODY IS EMIT \ restore EMIT
27606 HI2LO \ switch from FORTH to assembler
27607 MOV TOS,&BASE \ restore current BASE
27609 \ ******************************\
27611 \ ******************************\
27615 \ ------------------------------\
27617 \ ------------------------------\
27618 \ ... \ insert here your background task
27621 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
27622 ADD #4,X \ 1 X = BODY of SLEEP
27625 \ ------------------------------\
27629 \ ------------------------------\
27630 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
27631 \ - - \CNTL Counter lentgh \ 00 = 16 bits
27632 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
27633 \ -- \ID input divider \ 10 = /4
27634 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
27635 \ - \TBCLR TimerB Clear
27638 \ -------------------------------\
27639 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
27640 \ -- \CM Capture Mode
27645 \ --- \OUTMOD \ 011 = set/reset
27651 \ -------------------------------\
27653 \ -------------------------------\
27655 \ ------------------------------\
27656 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
27657 \ ------------------------------\
27658 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
27659 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
27660 \ ------------------------------\
27661 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
27662 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
27663 \ ------------------------------\
27664 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
27665 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
27666 \ ------------------------------\
27667 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
27668 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
27669 \ ------------------------------\
27670 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
27671 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
27672 \ ------------------------------\
27673 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
27674 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
27675 \ ------------------------------\
27676 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
27677 \ ------------------------------\
27678 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
27679 \ ------------------------------\
27680 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
27681 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
27682 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
27683 \ ------------------------------\
27684 BIS.B #LCDVo,&LCDVo_DIR \
27685 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
27686 \ ------------------------------\
27687 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
27688 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
27689 \ ------------------------------\
27690 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
27691 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
27692 \ ******************************\
27694 \ ******************************\
27695 BIS.B #RC5,&IR_IE \ enable RC5_Int
27696 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
27697 MOV #RC5_INT,&IR_Vec \ init interrupt vector
27698 \ ******************************\
27699 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
27700 \ ******************************\
27701 \ %01 0001 0100 \ TAxCTL
27702 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
27703 \ -- \ ID divided by 1
27704 \ -- \ MC MODE = up to TAxCCRn
27705 \ - \ TACLR clear timer count
27708 \ ------------------------------\
27709 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
27710 \ ------------------------------\
27712 \ --- \ TAIDEX pre divisor
27713 \ ------------------------------\
27714 \ %0000 0000 0000 0101 \ TAxCCR0
27715 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
27716 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
27717 \ ------------------------------\
27718 \ %0000 0000 0001 0000 \ TAxCCTL0
27719 \ - \ CAP capture/compare mode = compare
27722 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
27723 \ ------------------------------\
27724 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
27725 \ ------------------------------\
27726 \ define LPM mode for ACCEPT \
27727 \ ------------------------------\
27728 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
27729 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
27730 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
27732 \ ------------------------------\
27733 \ redirects to background task \
27734 \ ------------------------------\
27736 MOV #BACKGROUND,2(X) \
27737 \ ------------------------------\
27739 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
27741 \ ------------------------------\
27743 \ ------------------------------\
27744 $03E8 20_US \ 1- wait 20 ms
27745 $03 TOP_LCD \ 2- send DB5=DB4=1
27746 $CD 20_US \ 3- wait 4,1 ms
27747 $03 TOP_LCD \ 4- send again DB5=DB4=1
27748 $5 20_US \ 5- wait 0,1 ms
27749 $03 TOP_LCD \ 6- send again again DB5=DB4=1
27750 $2 20_US \ wait 40 us = LCD cycle
27751 $02 TOP_LCD \ 7- send DB5=1 DB4=0
27752 $2 20_US \ wait 40 us = LCD cycle
27753 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
27754 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
27755 LCD_Clear \ 10- "LCD_Clear"
27756 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
27757 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
27758 LCD_Clear \ 10- "LCD_Clear"
27759 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
27760 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
27762 ['] CR >BODY IS CR \
27763 ['] EMIT >BODY IS EMIT \
27764 ." RC5toLCD is running. Type STOP to quit"
27765 LIT RECURSE IS WARM \ replace WARM by this START routine
27766 ABORT \ and continue with the next word after WARM...
27767 ; \ ...until interpreter falls in sleep mode within ACCEPT.
27770 CODE STOP \ stops multitasking, must to be used before downloading app
27771 \ restore default action of primary DEFERred word SLEEP, assembly version
27772 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
27773 ADD #4,X \ X = BODY of SLEEP
27774 MOV X,-2(X) \ restore the default background
27777 \ restore default action of primary DEFERred word WARM, FORTH version
27778 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
27780 COLD \ because we want to reset CPU and interrupt vectors
27785 ; downloading RC5toLCD.4th is done
27786 RST_HERE ; this app is protected against <reset>
27794 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
27796 [DEFINED] ASM [IF] \ security test
27800 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
27802 CODE MAX \ n1 n2 -- n3 signed maximum
27803 CMP @PSP,TOS \ n2-n1
27804 S< ?GOTO FW1 \ n2<n1
27810 CODE MIN \ n1 n2 -- n3 signed minimum
27811 CMP @PSP,TOS \ n2-n1
27812 S< ?GOTO BW1 \ n2<n1
27820 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
27821 : U.R \ u n -- display u unsigned in n width (n >= 2)
27823 R> OVER - 0 MAX SPACES TYPE
27828 \ CODE 20_US \ n -- n * 20 us
27829 \ BEGIN \ 3 cycles loop + 6~
27830 \ \ MOV #5,W \ 3 MCLK = 1 MHz
27831 \ \ MOV #23,W \ 3 MCLK = 4 MHz
27832 \ \ MOV #51,W \ 3 MCLK = 8 MHz
27833 \ MOV #104,W \ 3 MCLK = 16 MHz
27834 \ \ MOV #158,W \ 3 MCLK = 24 MHz
27835 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
27840 \ MOV @PSP+,TOS \ 2
27845 CODE 20_US \ n -- n * 20 us
27846 BEGIN \ here we presume that LCD_TIM_IFG = 1...
27848 BIT #1,&LCD_TIM_CTL \ 3
27849 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
27850 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
27852 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
27858 CODE TOP_LCD \ LCD Sample
27859 \ \ if write : %xxxxWWWW --
27860 \ \ if read : -- %0000RRRR
27861 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
27862 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
27863 0= IF \ write LCD bits pattern
27864 AND.B #LCD_DB,TOS \
27865 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
27866 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
27869 THEN \ read LCD bits pattern
27872 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
27873 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
27874 AND.B #LCD_DB,TOS \
27879 CODE LCD_W \ byte -- write byte to LCD
27881 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
27882 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
27883 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
27884 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
27885 COLON \ high level word starts here
27886 TOP_LCD 2 20_US \ write high nibble first
27891 CODE LCD_WrC \ char -- Write Char
27892 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
27897 CODE LCD_WrF \ func -- Write Fonction
27898 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
27904 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
27909 $02 LCD_WrF 100 20_us
27913 [UNDEFINED] OR [IF]
27915 \ https://forth-standard.org/standard/core/OR
27916 \ C OR x1 x2 -- x3 logical OR
27925 : LCD_Entry_set $04 OR LCD_WrF ;
27927 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
27929 : LCD_DSP_Shift $10 OR LCD_WrF ;
27931 : LCD_Fn_Set $20 OR LCD_WrF ;
27933 : LCD_CGRAM_Set $40 OR LCD_WrF ;
27935 : LCD_Goto $80 OR LCD_WrF ;
27937 CODE LCD_R \ -- byte read byte from LCD
27938 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
27939 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
27940 COLON \ starts a FORTH word
27941 TOP_LCD 2 20_us \ -- %0000HHHH
27942 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
27943 HI2LO \ switch from FORTH to assembler
27944 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
27945 ADD.B @PSP+,TOS \ -- %HHHHLLLL
27946 MOV @RSP+,IP \ restore IP saved by COLON
27951 CODE LCD_RdS \ -- status Read Status
27952 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
27957 CODE LCD_RdC \ -- char Read Char
27958 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
27964 \ ******************************\
27965 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
27966 \ ******************************\
27967 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
27968 BIT.B #SW2,&SW2_IN \ test switch S2
27969 0= IF \ case of switch S2 pressed
27970 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
27972 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
27975 BIT.B #SW1,&SW1_IN \ test switch S1 input
27976 0= IF \ case of Switch S1 pressed
27977 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
27979 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
27983 BW1 \ from quit on truncated RC5 message
27984 BW2 \ from repeated RC5 command
27985 BW3 \ from end of RC5_INT
27986 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
27991 \ ******************************\
27992 ASM RC5_INT \ wake up on Px.RC5 change interrupt
27993 \ ******************************\
27994 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
27995 \ ******************************\
27996 \ \ in : SR(9)=old Toggle bit memory (ADD on)
27997 \ \ SMclock = 8|16|24 MHz
27998 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
27999 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
28000 \ \ SR(9)=new Toggle bit memory (ADD on)
28001 \ ******************************\
28002 \ RC5_FirstStartBitHalfCycle: \
28003 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
28004 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
28005 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
28006 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
28007 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
28008 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
28009 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
28010 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
28011 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
28012 MOV #1778,X \ RC5_Period * 1us
28013 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
28014 MOV #14,W \ count of loop
28016 \ ******************************\
28017 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
28018 \ ******************************\ |
28019 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
28020 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
28021 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
28022 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
28023 \ RC5_Compute_3/4_Period: \ |
28024 RRUM #1,X \ X=1/2 cycle |
28027 ADD X,Y \ Y=3/4 cycle
28028 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
28030 \ ******************************\
28031 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
28032 \ ******************************\
28033 BIT.B #RC5,&IR_IN \ C_flag = IR bit
28034 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
28035 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
28036 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
28037 SUB #1,W \ decrement count loop
28038 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
28039 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
28040 0<> WHILE \ ----> out of loop ----+
28041 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
28043 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
28044 CMP Y,X \ 1 | cycle time out of bound ?
28045 U>= IF \ 2 ^ | yes:
28046 BIC #$30,&RC5_TIM_CTL \ | | stop timer
28047 GOTO BW1 \ | | quit on truncated RC5 message
28049 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
28051 REPEAT \ ----> loop back --+ | with X = new RC5_period value
28052 \ ******************************\ |
28053 \ RC5_SampleEndOf: \ <---------------------+
28054 \ ******************************\
28055 BIC #$30,&RC5_TIM_CTL \ stop timer
28056 \ ******************************\
28057 \ RC5_ComputeNewRC5word \
28058 \ ******************************\
28059 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
28060 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
28061 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
28062 \ ******************************\
28063 \ RC5_ComputeC6bit \
28064 \ ******************************\
28065 BIT #BIT14,T \ test /C6 bit in T
28066 0= IF BIS #BIT6,X \ set C6 bit in X
28067 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
28068 \ ******************************\
28069 \ RC5_CommandByteIsDone \ -- BASE RC5_code
28070 \ ******************************\
28071 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
28072 \ ******************************\
28073 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
28074 XOR @RSP,T \ (new XOR old) Toggle bits
28075 BIT #UF10,T \ repeated RC5_command ?
28076 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
28077 XOR #UF10,0(RSP) \ 5 toggle bit memory
28078 \ ******************************\
28079 \ Display IR_RC5 code \ X = RC5 code
28080 \ ******************************\
28082 MOV &BASE,2(PSP) \ save current base
28083 MOV #$10,&BASE \ set hex base
28084 MOV TOS,0(PSP) \ save TOS
28086 LO2HI \ switch from assembler to FORTH
28087 ['] LCD_CLEAR IS CR \ redirects CR
28088 ['] LCD_WrC IS EMIT \ redirects EMIT
28089 CR ." $" 2 U.R \ print IR_RC5 code
28090 ['] CR >BODY IS CR \ restore CR
28091 ['] EMIT >BODY IS EMIT \ restore EMIT
28092 HI2LO \ switch from FORTH to assembler
28093 MOV TOS,&BASE \ restore current BASE
28095 \ ******************************\
28097 \ ******************************\
28101 \ ------------------------------\
28103 \ ------------------------------\
28104 \ ... \ insert here your background task
28107 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
28108 ADD #4,X \ 1 X = BODY of SLEEP
28111 \ ------------------------------\
28115 \ ------------------------------\
28116 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
28117 \ - - \CNTL Counter lentgh \ 00 = 16 bits
28118 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
28119 \ -- \ID input divider \ 10 = /4
28120 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
28121 \ - \TBCLR TimerB Clear
28124 \ -------------------------------\
28125 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
28126 \ -- \CM Capture Mode
28131 \ --- \OUTMOD \ 011 = set/reset
28137 \ -------------------------------\
28139 \ -------------------------------\
28141 \ ------------------------------\
28142 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
28143 \ ------------------------------\
28144 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
28145 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
28146 \ ------------------------------\
28147 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
28148 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
28149 \ ------------------------------\
28150 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
28151 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
28152 \ ------------------------------\
28153 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
28154 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
28155 \ ------------------------------\
28156 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
28157 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
28158 \ ------------------------------\
28159 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
28160 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
28161 \ ------------------------------\
28162 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
28163 \ ------------------------------\
28164 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
28165 \ ------------------------------\
28166 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
28167 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
28168 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
28169 \ ------------------------------\
28170 BIS.B #LCDVo,&LCDVo_DIR \
28171 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
28172 \ ------------------------------\
28173 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
28174 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
28175 \ ------------------------------\
28176 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
28177 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
28178 \ ******************************\
28180 \ ******************************\
28181 BIS.B #RC5,&IR_IE \ enable RC5_Int
28182 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
28183 MOV #RC5_INT,&IR_Vec \ init interrupt vector
28184 \ ******************************\
28185 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
28186 \ ******************************\
28187 \ %01 0001 0100 \ TAxCTL
28188 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
28189 \ -- \ ID divided by 1
28190 \ -- \ MC MODE = up to TAxCCRn
28191 \ - \ TACLR clear timer count
28194 \ ------------------------------\
28195 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
28196 \ ------------------------------\
28198 \ --- \ TAIDEX pre divisor
28199 \ ------------------------------\
28200 \ %0000 0000 0000 0101 \ TAxCCR0
28201 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
28202 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
28203 \ ------------------------------\
28204 \ %0000 0000 0001 0000 \ TAxCCTL0
28205 \ - \ CAP capture/compare mode = compare
28208 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
28209 \ ------------------------------\
28210 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
28211 \ ------------------------------\
28212 \ define LPM mode for ACCEPT \
28213 \ ------------------------------\
28214 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
28215 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
28216 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
28218 \ ------------------------------\
28219 \ redirects to background task \
28220 \ ------------------------------\
28222 MOV #BACKGROUND,2(X) \
28223 \ ------------------------------\
28225 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
28227 \ ------------------------------\
28229 \ ------------------------------\
28230 $03E8 20_US \ 1- wait 20 ms
28231 $03 TOP_LCD \ 2- send DB5=DB4=1
28232 $CD 20_US \ 3- wait 4,1 ms
28233 $03 TOP_LCD \ 4- send again DB5=DB4=1
28234 $5 20_US \ 5- wait 0,1 ms
28235 $03 TOP_LCD \ 6- send again again DB5=DB4=1
28236 $2 20_US \ wait 40 us = LCD cycle
28237 $02 TOP_LCD \ 7- send DB5=1 DB4=0
28238 $2 20_US \ wait 40 us = LCD cycle
28239 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
28240 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
28241 LCD_Clear \ 10- "LCD_Clear"
28242 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
28243 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
28244 LCD_Clear \ 10- "LCD_Clear"
28245 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
28246 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
28248 ['] CR >BODY IS CR \
28249 ['] EMIT >BODY IS EMIT \
28250 ." RC5toLCD is running. Type STOP to quit"
28251 LIT RECURSE IS WARM \ replace WARM by this START routine
28252 ABORT \ and continue with the next word after WARM...
28253 ; \ ...until interpreter falls in sleep mode within ACCEPT.
28256 CODE STOP \ stops multitasking, must to be used before downloading app
28257 \ restore default action of primary DEFERred word SLEEP, assembly version
28258 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
28259 ADD #4,X \ X = BODY of SLEEP
28260 MOV X,-2(X) \ restore the default background
28263 \ restore default action of primary DEFERred word WARM, FORTH version
28264 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
28266 COLD \ because we want to reset CPU and interrupt vectors
28271 ; downloading RC5toLCD.4th is done
28272 RST_HERE ; this app is protected against <reset>
28280 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
28282 [DEFINED] ASM [IF] \ security test
28286 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
28288 CODE MAX \ n1 n2 -- n3 signed maximum
28289 CMP @PSP,TOS \ n2-n1
28290 S< ?GOTO FW1 \ n2<n1
28296 CODE MIN \ n1 n2 -- n3 signed minimum
28297 CMP @PSP,TOS \ n2-n1
28298 S< ?GOTO BW1 \ n2<n1
28306 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
28307 : U.R \ u n -- display u unsigned in n width (n >= 2)
28309 R> OVER - 0 MAX SPACES TYPE
28314 \ CODE 20_US \ n -- n * 20 us
28315 \ BEGIN \ 3 cycles loop + 6~
28316 \ \ MOV #5,W \ 3 MCLK = 1 MHz
28317 \ \ MOV #23,W \ 3 MCLK = 4 MHz
28318 \ \ MOV #51,W \ 3 MCLK = 8 MHz
28319 \ MOV #104,W \ 3 MCLK = 16 MHz
28320 \ \ MOV #158,W \ 3 MCLK = 24 MHz
28321 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
28326 \ MOV @PSP+,TOS \ 2
28331 CODE 20_US \ n -- n * 20 us
28332 BEGIN \ here we presume that LCD_TIM_IFG = 1...
28334 BIT #1,&LCD_TIM_CTL \ 3
28335 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
28336 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
28338 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
28344 CODE TOP_LCD \ LCD Sample
28345 \ \ if write : %xxxxWWWW --
28346 \ \ if read : -- %0000RRRR
28347 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
28348 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
28349 0= IF \ write LCD bits pattern
28350 AND.B #LCD_DB,TOS \
28351 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
28352 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
28355 THEN \ read LCD bits pattern
28358 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
28359 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
28360 AND.B #LCD_DB,TOS \
28365 CODE LCD_W \ byte -- write byte to LCD
28367 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
28368 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
28369 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
28370 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
28371 COLON \ high level word starts here
28372 TOP_LCD 2 20_US \ write high nibble first
28377 CODE LCD_WrC \ char -- Write Char
28378 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
28383 CODE LCD_WrF \ func -- Write Fonction
28384 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
28390 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
28395 $02 LCD_WrF 100 20_us
28399 [UNDEFINED] OR [IF]
28401 \ https://forth-standard.org/standard/core/OR
28402 \ C OR x1 x2 -- x3 logical OR
28411 : LCD_Entry_set $04 OR LCD_WrF ;
28413 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
28415 : LCD_DSP_Shift $10 OR LCD_WrF ;
28417 : LCD_Fn_Set $20 OR LCD_WrF ;
28419 : LCD_CGRAM_Set $40 OR LCD_WrF ;
28421 : LCD_Goto $80 OR LCD_WrF ;
28423 CODE LCD_R \ -- byte read byte from LCD
28424 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
28425 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
28426 COLON \ starts a FORTH word
28427 TOP_LCD 2 20_us \ -- %0000HHHH
28428 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
28429 HI2LO \ switch from FORTH to assembler
28430 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
28431 ADD.B @PSP+,TOS \ -- %HHHHLLLL
28432 MOV @RSP+,IP \ restore IP saved by COLON
28437 CODE LCD_RdS \ -- status Read Status
28438 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
28443 CODE LCD_RdC \ -- char Read Char
28444 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
28450 \ ******************************\
28451 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
28452 \ ******************************\
28453 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
28454 BIT.B #SW2,&SW2_IN \ test switch S2
28455 0= IF \ case of switch S2 pressed
28456 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
28458 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
28461 BIT.B #SW1,&SW1_IN \ test switch S1 input
28462 0= IF \ case of Switch S1 pressed
28463 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
28465 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
28469 BW1 \ from quit on truncated RC5 message
28470 BW2 \ from repeated RC5 command
28471 BW3 \ from end of RC5_INT
28472 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
28477 \ ******************************\
28478 ASM RC5_INT \ wake up on Px.RC5 change interrupt
28479 \ ******************************\
28480 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
28481 \ ******************************\
28482 \ \ in : SR(9)=old Toggle bit memory (ADD on)
28483 \ \ SMclock = 8|16|24 MHz
28484 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
28485 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
28486 \ \ SR(9)=new Toggle bit memory (ADD on)
28487 \ ******************************\
28488 \ RC5_FirstStartBitHalfCycle: \
28489 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
28490 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
28491 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
28492 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
28493 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
28494 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
28495 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
28496 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
28497 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
28498 MOV #1778,X \ RC5_Period * 1us
28499 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
28500 MOV #14,W \ count of loop
28502 \ ******************************\
28503 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
28504 \ ******************************\ |
28505 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
28506 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
28507 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
28508 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
28509 \ RC5_Compute_3/4_Period: \ |
28510 RRUM #1,X \ X=1/2 cycle |
28513 ADD X,Y \ Y=3/4 cycle
28514 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
28516 \ ******************************\
28517 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
28518 \ ******************************\
28519 BIT.B #RC5,&IR_IN \ C_flag = IR bit
28520 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
28521 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
28522 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
28523 SUB #1,W \ decrement count loop
28524 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
28525 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
28526 0<> WHILE \ ----> out of loop ----+
28527 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
28529 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
28530 CMP Y,X \ 1 | cycle time out of bound ?
28531 U>= IF \ 2 ^ | yes:
28532 BIC #$30,&RC5_TIM_CTL \ | | stop timer
28533 GOTO BW1 \ | | quit on truncated RC5 message
28535 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
28537 REPEAT \ ----> loop back --+ | with X = new RC5_period value
28538 \ ******************************\ |
28539 \ RC5_SampleEndOf: \ <---------------------+
28540 \ ******************************\
28541 BIC #$30,&RC5_TIM_CTL \ stop timer
28542 \ ******************************\
28543 \ RC5_ComputeNewRC5word \
28544 \ ******************************\
28545 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
28546 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
28547 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
28548 \ ******************************\
28549 \ RC5_ComputeC6bit \
28550 \ ******************************\
28551 BIT #BIT14,T \ test /C6 bit in T
28552 0= IF BIS #BIT6,X \ set C6 bit in X
28553 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
28554 \ ******************************\
28555 \ RC5_CommandByteIsDone \ -- BASE RC5_code
28556 \ ******************************\
28557 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
28558 \ ******************************\
28559 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
28560 XOR @RSP,T \ (new XOR old) Toggle bits
28561 BIT #UF10,T \ repeated RC5_command ?
28562 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
28563 XOR #UF10,0(RSP) \ 5 toggle bit memory
28564 \ ******************************\
28565 \ Display IR_RC5 code \ X = RC5 code
28566 \ ******************************\
28568 MOV &BASE,2(PSP) \ save current base
28569 MOV #$10,&BASE \ set hex base
28570 MOV TOS,0(PSP) \ save TOS
28572 LO2HI \ switch from assembler to FORTH
28573 ['] LCD_CLEAR IS CR \ redirects CR
28574 ['] LCD_WrC IS EMIT \ redirects EMIT
28575 CR ." $" 2 U.R \ print IR_RC5 code
28576 ['] CR >BODY IS CR \ restore CR
28577 ['] EMIT >BODY IS EMIT \ restore EMIT
28578 HI2LO \ switch from FORTH to assembler
28579 MOV TOS,&BASE \ restore current BASE
28581 \ ******************************\
28583 \ ******************************\
28587 \ ------------------------------\
28589 \ ------------------------------\
28590 \ ... \ insert here your background task
28593 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
28594 ADD #4,X \ 1 X = BODY of SLEEP
28597 \ ------------------------------\
28601 \ ------------------------------\
28602 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
28603 \ - - \CNTL Counter lentgh \ 00 = 16 bits
28604 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
28605 \ -- \ID input divider \ 10 = /4
28606 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
28607 \ - \TBCLR TimerB Clear
28610 \ -------------------------------\
28611 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
28612 \ -- \CM Capture Mode
28617 \ --- \OUTMOD \ 011 = set/reset
28623 \ -------------------------------\
28625 \ -------------------------------\
28627 \ ------------------------------\
28628 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
28629 \ ------------------------------\
28630 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
28631 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
28632 \ ------------------------------\
28633 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
28634 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
28635 \ ------------------------------\
28636 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
28637 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
28638 \ ------------------------------\
28639 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
28640 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
28641 \ ------------------------------\
28642 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
28643 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
28644 \ ------------------------------\
28645 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
28646 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
28647 \ ------------------------------\
28648 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
28649 \ ------------------------------\
28650 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
28651 \ ------------------------------\
28652 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
28653 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
28654 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
28655 \ ------------------------------\
28656 BIS.B #LCDVo,&LCDVo_DIR \
28657 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
28658 \ ------------------------------\
28659 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
28660 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
28661 \ ------------------------------\
28662 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
28663 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
28664 \ ******************************\
28666 \ ******************************\
28667 BIS.B #RC5,&IR_IE \ enable RC5_Int
28668 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
28669 MOV #RC5_INT,&IR_Vec \ init interrupt vector
28670 \ ******************************\
28671 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
28672 \ ******************************\
28673 \ %01 0001 0100 \ TAxCTL
28674 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
28675 \ -- \ ID divided by 1
28676 \ -- \ MC MODE = up to TAxCCRn
28677 \ - \ TACLR clear timer count
28680 \ ------------------------------\
28681 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
28682 \ ------------------------------\
28684 \ --- \ TAIDEX pre divisor
28685 \ ------------------------------\
28686 \ %0000 0000 0000 0101 \ TAxCCR0
28687 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
28688 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
28689 \ ------------------------------\
28690 \ %0000 0000 0001 0000 \ TAxCCTL0
28691 \ - \ CAP capture/compare mode = compare
28694 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
28695 \ ------------------------------\
28696 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
28697 \ ------------------------------\
28698 \ define LPM mode for ACCEPT \
28699 \ ------------------------------\
28700 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
28701 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
28702 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
28704 \ ------------------------------\
28705 \ redirects to background task \
28706 \ ------------------------------\
28708 MOV #BACKGROUND,2(X) \
28709 \ ------------------------------\
28711 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
28713 \ ------------------------------\
28715 \ ------------------------------\
28716 $03E8 20_US \ 1- wait 20 ms
28717 $03 TOP_LCD \ 2- send DB5=DB4=1
28718 $CD 20_US \ 3- wait 4,1 ms
28719 $03 TOP_LCD \ 4- send again DB5=DB4=1
28720 $5 20_US \ 5- wait 0,1 ms
28721 $03 TOP_LCD \ 6- send again again DB5=DB4=1
28722 $2 20_US \ wait 40 us = LCD cycle
28723 $02 TOP_LCD \ 7- send DB5=1 DB4=0
28724 $2 20_US \ wait 40 us = LCD cycle
28725 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
28726 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
28727 LCD_Clear \ 10- "LCD_Clear"
28728 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
28729 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
28730 LCD_Clear \ 10- "LCD_Clear"
28731 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
28732 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
28734 ['] CR >BODY IS CR \
28735 ['] EMIT >BODY IS EMIT \
28736 ." RC5toLCD is running. Type STOP to quit"
28737 LIT RECURSE IS WARM \ replace WARM by this START routine
28738 ABORT \ and continue with the next word after WARM...
28739 ; \ ...until interpreter falls in sleep mode within ACCEPT.
28742 CODE STOP \ stops multitasking, must to be used before downloading app
28743 \ restore default action of primary DEFERred word SLEEP, assembly version
28744 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
28745 ADD #4,X \ X = BODY of SLEEP
28746 MOV X,-2(X) \ restore the default background
28749 \ restore default action of primary DEFERred word WARM, FORTH version
28750 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
28752 COLD \ because we want to reset CPU and interrupt vectors
28757 ; downloading RC5toLCD.4th is done
28758 RST_HERE ; this app is protected against <reset>
28766 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
28768 [DEFINED] ASM [IF] \ security test
28772 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
28774 CODE MAX \ n1 n2 -- n3 signed maximum
28775 CMP @PSP,TOS \ n2-n1
28776 S< ?GOTO FW1 \ n2<n1
28782 CODE MIN \ n1 n2 -- n3 signed minimum
28783 CMP @PSP,TOS \ n2-n1
28784 S< ?GOTO BW1 \ n2<n1
28792 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
28793 : U.R \ u n -- display u unsigned in n width (n >= 2)
28795 R> OVER - 0 MAX SPACES TYPE
28800 \ CODE 20_US \ n -- n * 20 us
28801 \ BEGIN \ 3 cycles loop + 6~
28802 \ \ MOV #5,W \ 3 MCLK = 1 MHz
28803 \ \ MOV #23,W \ 3 MCLK = 4 MHz
28804 \ \ MOV #51,W \ 3 MCLK = 8 MHz
28805 \ MOV #104,W \ 3 MCLK = 16 MHz
28806 \ \ MOV #158,W \ 3 MCLK = 24 MHz
28807 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
28812 \ MOV @PSP+,TOS \ 2
28817 CODE 20_US \ n -- n * 20 us
28818 BEGIN \ here we presume that LCD_TIM_IFG = 1...
28820 BIT #1,&LCD_TIM_CTL \ 3
28821 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
28822 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
28824 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
28830 CODE TOP_LCD \ LCD Sample
28831 \ \ if write : %xxxxWWWW --
28832 \ \ if read : -- %0000RRRR
28833 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
28834 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
28835 0= IF \ write LCD bits pattern
28836 AND.B #LCD_DB,TOS \
28837 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
28838 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
28841 THEN \ read LCD bits pattern
28844 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
28845 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
28846 AND.B #LCD_DB,TOS \
28851 CODE LCD_W \ byte -- write byte to LCD
28853 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
28854 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
28855 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
28856 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
28857 COLON \ high level word starts here
28858 TOP_LCD 2 20_US \ write high nibble first
28863 CODE LCD_WrC \ char -- Write Char
28864 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
28869 CODE LCD_WrF \ func -- Write Fonction
28870 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
28876 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
28881 $02 LCD_WrF 100 20_us
28885 [UNDEFINED] OR [IF]
28887 \ https://forth-standard.org/standard/core/OR
28888 \ C OR x1 x2 -- x3 logical OR
28897 : LCD_Entry_set $04 OR LCD_WrF ;
28899 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
28901 : LCD_DSP_Shift $10 OR LCD_WrF ;
28903 : LCD_Fn_Set $20 OR LCD_WrF ;
28905 : LCD_CGRAM_Set $40 OR LCD_WrF ;
28907 : LCD_Goto $80 OR LCD_WrF ;
28909 CODE LCD_R \ -- byte read byte from LCD
28910 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
28911 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
28912 COLON \ starts a FORTH word
28913 TOP_LCD 2 20_us \ -- %0000HHHH
28914 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
28915 HI2LO \ switch from FORTH to assembler
28916 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
28917 ADD.B @PSP+,TOS \ -- %HHHHLLLL
28918 MOV @RSP+,IP \ restore IP saved by COLON
28923 CODE LCD_RdS \ -- status Read Status
28924 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
28929 CODE LCD_RdC \ -- char Read Char
28930 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
28936 \ ******************************\
28937 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
28938 \ ******************************\
28939 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
28940 BIT.B #SW2,&SW2_IN \ test switch S2
28941 0= IF \ case of switch S2 pressed
28942 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
28944 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
28947 BIT.B #SW1,&SW1_IN \ test switch S1 input
28948 0= IF \ case of Switch S1 pressed
28949 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
28951 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
28955 BW1 \ from quit on truncated RC5 message
28956 BW2 \ from repeated RC5 command
28957 BW3 \ from end of RC5_INT
28958 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
28963 \ ******************************\
28964 ASM RC5_INT \ wake up on Px.RC5 change interrupt
28965 \ ******************************\
28966 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
28967 \ ******************************\
28968 \ \ in : SR(9)=old Toggle bit memory (ADD on)
28969 \ \ SMclock = 8|16|24 MHz
28970 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
28971 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
28972 \ \ SR(9)=new Toggle bit memory (ADD on)
28973 \ ******************************\
28974 \ RC5_FirstStartBitHalfCycle: \
28975 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
28976 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
28977 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
28978 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
28979 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
28980 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
28981 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
28982 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
28983 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
28984 MOV #1778,X \ RC5_Period * 1us
28985 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
28986 MOV #14,W \ count of loop
28988 \ ******************************\
28989 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
28990 \ ******************************\ |
28991 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
28992 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
28993 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
28994 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
28995 \ RC5_Compute_3/4_Period: \ |
28996 RRUM #1,X \ X=1/2 cycle |
28999 ADD X,Y \ Y=3/4 cycle
29000 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
29002 \ ******************************\
29003 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
29004 \ ******************************\
29005 BIT.B #RC5,&IR_IN \ C_flag = IR bit
29006 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
29007 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
29008 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
29009 SUB #1,W \ decrement count loop
29010 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
29011 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
29012 0<> WHILE \ ----> out of loop ----+
29013 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
29015 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
29016 CMP Y,X \ 1 | cycle time out of bound ?
29017 U>= IF \ 2 ^ | yes:
29018 BIC #$30,&RC5_TIM_CTL \ | | stop timer
29019 GOTO BW1 \ | | quit on truncated RC5 message
29021 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
29023 REPEAT \ ----> loop back --+ | with X = new RC5_period value
29024 \ ******************************\ |
29025 \ RC5_SampleEndOf: \ <---------------------+
29026 \ ******************************\
29027 BIC #$30,&RC5_TIM_CTL \ stop timer
29028 \ ******************************\
29029 \ RC5_ComputeNewRC5word \
29030 \ ******************************\
29031 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
29032 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
29033 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
29034 \ ******************************\
29035 \ RC5_ComputeC6bit \
29036 \ ******************************\
29037 BIT #BIT14,T \ test /C6 bit in T
29038 0= IF BIS #BIT6,X \ set C6 bit in X
29039 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
29040 \ ******************************\
29041 \ RC5_CommandByteIsDone \ -- BASE RC5_code
29042 \ ******************************\
29043 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
29044 \ ******************************\
29045 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
29046 XOR @RSP,T \ (new XOR old) Toggle bits
29047 BIT #UF10,T \ repeated RC5_command ?
29048 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
29049 XOR #UF10,0(RSP) \ 5 toggle bit memory
29050 \ ******************************\
29051 \ Display IR_RC5 code \ X = RC5 code
29052 \ ******************************\
29054 MOV &BASE,2(PSP) \ save current base
29055 MOV #$10,&BASE \ set hex base
29056 MOV TOS,0(PSP) \ save TOS
29058 LO2HI \ switch from assembler to FORTH
29059 ['] LCD_CLEAR IS CR \ redirects CR
29060 ['] LCD_WrC IS EMIT \ redirects EMIT
29061 CR ." $" 2 U.R \ print IR_RC5 code
29062 ['] CR >BODY IS CR \ restore CR
29063 ['] EMIT >BODY IS EMIT \ restore EMIT
29064 HI2LO \ switch from FORTH to assembler
29065 MOV TOS,&BASE \ restore current BASE
29067 \ ******************************\
29069 \ ******************************\
29073 \ ------------------------------\
29075 \ ------------------------------\
29076 \ ... \ insert here your background task
29079 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
29080 ADD #4,X \ 1 X = BODY of SLEEP
29083 \ ------------------------------\
29087 \ ------------------------------\
29088 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
29089 \ - - \CNTL Counter lentgh \ 00 = 16 bits
29090 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
29091 \ -- \ID input divider \ 10 = /4
29092 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
29093 \ - \TBCLR TimerB Clear
29096 \ -------------------------------\
29097 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
29098 \ -- \CM Capture Mode
29103 \ --- \OUTMOD \ 011 = set/reset
29109 \ -------------------------------\
29111 \ -------------------------------\
29113 \ ------------------------------\
29114 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
29115 \ ------------------------------\
29116 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
29117 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
29118 \ ------------------------------\
29119 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
29120 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
29121 \ ------------------------------\
29122 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
29123 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
29124 \ ------------------------------\
29125 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
29126 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
29127 \ ------------------------------\
29128 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
29129 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
29130 \ ------------------------------\
29131 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
29132 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
29133 \ ------------------------------\
29134 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
29135 \ ------------------------------\
29136 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
29137 \ ------------------------------\
29138 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
29139 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
29140 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
29141 \ ------------------------------\
29142 BIS.B #LCDVo,&LCDVo_DIR \
29143 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
29144 \ ------------------------------\
29145 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
29146 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
29147 \ ------------------------------\
29148 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
29149 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
29150 \ ******************************\
29152 \ ******************************\
29153 BIS.B #RC5,&IR_IE \ enable RC5_Int
29154 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
29155 MOV #RC5_INT,&IR_Vec \ init interrupt vector
29156 \ ******************************\
29157 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
29158 \ ******************************\
29159 \ %01 0001 0100 \ TAxCTL
29160 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
29161 \ -- \ ID divided by 1
29162 \ -- \ MC MODE = up to TAxCCRn
29163 \ - \ TACLR clear timer count
29166 \ ------------------------------\
29167 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
29168 \ ------------------------------\
29170 \ --- \ TAIDEX pre divisor
29171 \ ------------------------------\
29172 \ %0000 0000 0000 0101 \ TAxCCR0
29173 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
29174 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
29175 \ ------------------------------\
29176 \ %0000 0000 0001 0000 \ TAxCCTL0
29177 \ - \ CAP capture/compare mode = compare
29180 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
29181 \ ------------------------------\
29182 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
29183 \ ------------------------------\
29184 \ define LPM mode for ACCEPT \
29185 \ ------------------------------\
29186 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
29187 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
29188 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
29190 \ ------------------------------\
29191 \ redirects to background task \
29192 \ ------------------------------\
29194 MOV #BACKGROUND,2(X) \
29195 \ ------------------------------\
29197 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
29199 \ ------------------------------\
29201 \ ------------------------------\
29202 $03E8 20_US \ 1- wait 20 ms
29203 $03 TOP_LCD \ 2- send DB5=DB4=1
29204 $CD 20_US \ 3- wait 4,1 ms
29205 $03 TOP_LCD \ 4- send again DB5=DB4=1
29206 $5 20_US \ 5- wait 0,1 ms
29207 $03 TOP_LCD \ 6- send again again DB5=DB4=1
29208 $2 20_US \ wait 40 us = LCD cycle
29209 $02 TOP_LCD \ 7- send DB5=1 DB4=0
29210 $2 20_US \ wait 40 us = LCD cycle
29211 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
29212 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
29213 LCD_Clear \ 10- "LCD_Clear"
29214 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
29215 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
29216 LCD_Clear \ 10- "LCD_Clear"
29217 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
29218 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
29220 ['] CR >BODY IS CR \
29221 ['] EMIT >BODY IS EMIT \
29222 ." RC5toLCD is running. Type STOP to quit"
29223 LIT RECURSE IS WARM \ replace WARM by this START routine
29224 ABORT \ and continue with the next word after WARM...
29225 ; \ ...until interpreter falls in sleep mode within ACCEPT.
29228 CODE STOP \ stops multitasking, must to be used before downloading app
29229 \ restore default action of primary DEFERred word SLEEP, assembly version
29230 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
29231 ADD #4,X \ X = BODY of SLEEP
29232 MOV X,-2(X) \ restore the default background
29235 \ restore default action of primary DEFERred word WARM, FORTH version
29236 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
29238 COLD \ because we want to reset CPU and interrupt vectors
29243 ; downloading RC5toLCD.4th is done
29244 RST_HERE ; this app is protected against <reset>
29252 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
29254 [DEFINED] ASM [IF] \ security test
29258 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
29260 CODE MAX \ n1 n2 -- n3 signed maximum
29261 CMP @PSP,TOS \ n2-n1
29262 S< ?GOTO FW1 \ n2<n1
29268 CODE MIN \ n1 n2 -- n3 signed minimum
29269 CMP @PSP,TOS \ n2-n1
29270 S< ?GOTO BW1 \ n2<n1
29278 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
29279 : U.R \ u n -- display u unsigned in n width (n >= 2)
29281 R> OVER - 0 MAX SPACES TYPE
29286 \ CODE 20_US \ n -- n * 20 us
29287 \ BEGIN \ 3 cycles loop + 6~
29288 \ \ MOV #5,W \ 3 MCLK = 1 MHz
29289 \ \ MOV #23,W \ 3 MCLK = 4 MHz
29290 \ \ MOV #51,W \ 3 MCLK = 8 MHz
29291 \ MOV #104,W \ 3 MCLK = 16 MHz
29292 \ \ MOV #158,W \ 3 MCLK = 24 MHz
29293 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
29298 \ MOV @PSP+,TOS \ 2
29303 CODE 20_US \ n -- n * 20 us
29304 BEGIN \ here we presume that LCD_TIM_IFG = 1...
29306 BIT #1,&LCD_TIM_CTL \ 3
29307 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
29308 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
29310 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
29316 CODE TOP_LCD \ LCD Sample
29317 \ \ if write : %xxxxWWWW --
29318 \ \ if read : -- %0000RRRR
29319 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
29320 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
29321 0= IF \ write LCD bits pattern
29322 AND.B #LCD_DB,TOS \
29323 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
29324 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
29327 THEN \ read LCD bits pattern
29330 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
29331 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
29332 AND.B #LCD_DB,TOS \
29337 CODE LCD_W \ byte -- write byte to LCD
29339 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
29340 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
29341 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
29342 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
29343 COLON \ high level word starts here
29344 TOP_LCD 2 20_US \ write high nibble first
29349 CODE LCD_WrC \ char -- Write Char
29350 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
29355 CODE LCD_WrF \ func -- Write Fonction
29356 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
29362 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
29367 $02 LCD_WrF 100 20_us
29371 [UNDEFINED] OR [IF]
29373 \ https://forth-standard.org/standard/core/OR
29374 \ C OR x1 x2 -- x3 logical OR
29383 : LCD_Entry_set $04 OR LCD_WrF ;
29385 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
29387 : LCD_DSP_Shift $10 OR LCD_WrF ;
29389 : LCD_Fn_Set $20 OR LCD_WrF ;
29391 : LCD_CGRAM_Set $40 OR LCD_WrF ;
29393 : LCD_Goto $80 OR LCD_WrF ;
29395 CODE LCD_R \ -- byte read byte from LCD
29396 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
29397 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
29398 COLON \ starts a FORTH word
29399 TOP_LCD 2 20_us \ -- %0000HHHH
29400 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
29401 HI2LO \ switch from FORTH to assembler
29402 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
29403 ADD.B @PSP+,TOS \ -- %HHHHLLLL
29404 MOV @RSP+,IP \ restore IP saved by COLON
29409 CODE LCD_RdS \ -- status Read Status
29410 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
29415 CODE LCD_RdC \ -- char Read Char
29416 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
29422 \ ******************************\
29423 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
29424 \ ******************************\
29425 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
29426 BIT.B #SW2,&SW2_IN \ test switch S2
29427 0= IF \ case of switch S2 pressed
29428 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
29430 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
29433 BIT.B #SW1,&SW1_IN \ test switch S1 input
29434 0= IF \ case of Switch S1 pressed
29435 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
29437 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
29441 BW1 \ from quit on truncated RC5 message
29442 BW2 \ from repeated RC5 command
29443 BW3 \ from end of RC5_INT
29444 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
29449 \ ******************************\
29450 ASM RC5_INT \ wake up on Px.RC5 change interrupt
29451 \ ******************************\
29452 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
29453 \ ******************************\
29454 \ \ in : SR(9)=old Toggle bit memory (ADD on)
29455 \ \ SMclock = 8|16|24 MHz
29456 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
29457 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
29458 \ \ SR(9)=new Toggle bit memory (ADD on)
29459 \ ******************************\
29460 \ RC5_FirstStartBitHalfCycle: \
29461 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
29462 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
29463 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
29464 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
29465 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
29466 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
29467 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
29468 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
29469 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
29470 MOV #1778,X \ RC5_Period * 1us
29471 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
29472 MOV #14,W \ count of loop
29474 \ ******************************\
29475 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
29476 \ ******************************\ |
29477 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
29478 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
29479 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
29480 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
29481 \ RC5_Compute_3/4_Period: \ |
29482 RRUM #1,X \ X=1/2 cycle |
29485 ADD X,Y \ Y=3/4 cycle
29486 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
29488 \ ******************************\
29489 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
29490 \ ******************************\
29491 BIT.B #RC5,&IR_IN \ C_flag = IR bit
29492 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
29493 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
29494 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
29495 SUB #1,W \ decrement count loop
29496 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
29497 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
29498 0<> WHILE \ ----> out of loop ----+
29499 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
29501 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
29502 CMP Y,X \ 1 | cycle time out of bound ?
29503 U>= IF \ 2 ^ | yes:
29504 BIC #$30,&RC5_TIM_CTL \ | | stop timer
29505 GOTO BW1 \ | | quit on truncated RC5 message
29507 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
29509 REPEAT \ ----> loop back --+ | with X = new RC5_period value
29510 \ ******************************\ |
29511 \ RC5_SampleEndOf: \ <---------------------+
29512 \ ******************************\
29513 BIC #$30,&RC5_TIM_CTL \ stop timer
29514 \ ******************************\
29515 \ RC5_ComputeNewRC5word \
29516 \ ******************************\
29517 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
29518 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
29519 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
29520 \ ******************************\
29521 \ RC5_ComputeC6bit \
29522 \ ******************************\
29523 BIT #BIT14,T \ test /C6 bit in T
29524 0= IF BIS #BIT6,X \ set C6 bit in X
29525 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
29526 \ ******************************\
29527 \ RC5_CommandByteIsDone \ -- BASE RC5_code
29528 \ ******************************\
29529 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
29530 \ ******************************\
29531 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
29532 XOR @RSP,T \ (new XOR old) Toggle bits
29533 BIT #UF10,T \ repeated RC5_command ?
29534 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
29535 XOR #UF10,0(RSP) \ 5 toggle bit memory
29536 \ ******************************\
29537 \ Display IR_RC5 code \ X = RC5 code
29538 \ ******************************\
29540 MOV &BASE,2(PSP) \ save current base
29541 MOV #$10,&BASE \ set hex base
29542 MOV TOS,0(PSP) \ save TOS
29544 LO2HI \ switch from assembler to FORTH
29545 ['] LCD_CLEAR IS CR \ redirects CR
29546 ['] LCD_WrC IS EMIT \ redirects EMIT
29547 CR ." $" 2 U.R \ print IR_RC5 code
29548 ['] CR >BODY IS CR \ restore CR
29549 ['] EMIT >BODY IS EMIT \ restore EMIT
29550 HI2LO \ switch from FORTH to assembler
29551 MOV TOS,&BASE \ restore current BASE
29553 \ ******************************\
29555 \ ******************************\
29559 \ ------------------------------\
29561 \ ------------------------------\
29562 \ ... \ insert here your background task
29565 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
29566 ADD #4,X \ 1 X = BODY of SLEEP
29569 \ ------------------------------\
29573 \ ------------------------------\
29574 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
29575 \ - - \CNTL Counter lentgh \ 00 = 16 bits
29576 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
29577 \ -- \ID input divider \ 10 = /4
29578 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
29579 \ - \TBCLR TimerB Clear
29582 \ -------------------------------\
29583 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
29584 \ -- \CM Capture Mode
29589 \ --- \OUTMOD \ 011 = set/reset
29595 \ -------------------------------\
29597 \ -------------------------------\
29599 \ ------------------------------\
29600 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
29601 \ ------------------------------\
29602 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
29603 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
29604 \ ------------------------------\
29605 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
29606 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
29607 \ ------------------------------\
29608 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
29609 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
29610 \ ------------------------------\
29611 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
29612 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
29613 \ ------------------------------\
29614 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
29615 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
29616 \ ------------------------------\
29617 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
29618 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
29619 \ ------------------------------\
29620 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
29621 \ ------------------------------\
29622 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
29623 \ ------------------------------\
29624 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
29625 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
29626 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
29627 \ ------------------------------\
29628 BIS.B #LCDVo,&LCDVo_DIR \
29629 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
29630 \ ------------------------------\
29631 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
29632 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
29633 \ ------------------------------\
29634 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
29635 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
29636 \ ******************************\
29638 \ ******************************\
29639 BIS.B #RC5,&IR_IE \ enable RC5_Int
29640 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
29641 MOV #RC5_INT,&IR_Vec \ init interrupt vector
29642 \ ******************************\
29643 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
29644 \ ******************************\
29645 \ %01 0001 0100 \ TAxCTL
29646 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
29647 \ -- \ ID divided by 1
29648 \ -- \ MC MODE = up to TAxCCRn
29649 \ - \ TACLR clear timer count
29652 \ ------------------------------\
29653 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
29654 \ ------------------------------\
29656 \ --- \ TAIDEX pre divisor
29657 \ ------------------------------\
29658 \ %0000 0000 0000 0101 \ TAxCCR0
29659 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
29660 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
29661 \ ------------------------------\
29662 \ %0000 0000 0001 0000 \ TAxCCTL0
29663 \ - \ CAP capture/compare mode = compare
29666 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
29667 \ ------------------------------\
29668 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
29669 \ ------------------------------\
29670 \ define LPM mode for ACCEPT \
29671 \ ------------------------------\
29672 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
29673 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
29674 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
29676 \ ------------------------------\
29677 \ redirects to background task \
29678 \ ------------------------------\
29680 MOV #BACKGROUND,2(X) \
29681 \ ------------------------------\
29683 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
29685 \ ------------------------------\
29687 \ ------------------------------\
29688 $03E8 20_US \ 1- wait 20 ms
29689 $03 TOP_LCD \ 2- send DB5=DB4=1
29690 $CD 20_US \ 3- wait 4,1 ms
29691 $03 TOP_LCD \ 4- send again DB5=DB4=1
29692 $5 20_US \ 5- wait 0,1 ms
29693 $03 TOP_LCD \ 6- send again again DB5=DB4=1
29694 $2 20_US \ wait 40 us = LCD cycle
29695 $02 TOP_LCD \ 7- send DB5=1 DB4=0
29696 $2 20_US \ wait 40 us = LCD cycle
29697 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
29698 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
29699 LCD_Clear \ 10- "LCD_Clear"
29700 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
29701 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
29702 LCD_Clear \ 10- "LCD_Clear"
29703 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
29704 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
29706 ['] CR >BODY IS CR \
29707 ['] EMIT >BODY IS EMIT \
29708 ." RC5toLCD is running. Type STOP to quit"
29709 LIT RECURSE IS WARM \ replace WARM by this START routine
29710 ABORT \ and continue with the next word after WARM...
29711 ; \ ...until interpreter falls in sleep mode within ACCEPT.
29714 CODE STOP \ stops multitasking, must to be used before downloading app
29715 \ restore default action of primary DEFERred word SLEEP, assembly version
29716 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
29717 ADD #4,X \ X = BODY of SLEEP
29718 MOV X,-2(X) \ restore the default background
29721 \ restore default action of primary DEFERred word WARM, FORTH version
29722 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
29724 COLD \ because we want to reset CPU and interrupt vectors
29729 ; downloading RC5toLCD.4th is done
29730 RST_HERE ; this app is protected against <reset>
29738 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
29740 [DEFINED] ASM [IF] \ security test
29744 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
29746 CODE MAX \ n1 n2 -- n3 signed maximum
29747 CMP @PSP,TOS \ n2-n1
29748 S< ?GOTO FW1 \ n2<n1
29754 CODE MIN \ n1 n2 -- n3 signed minimum
29755 CMP @PSP,TOS \ n2-n1
29756 S< ?GOTO BW1 \ n2<n1
29764 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
29765 : U.R \ u n -- display u unsigned in n width (n >= 2)
29767 R> OVER - 0 MAX SPACES TYPE
29772 \ CODE 20_US \ n -- n * 20 us
29773 \ BEGIN \ 3 cycles loop + 6~
29774 \ \ MOV #5,W \ 3 MCLK = 1 MHz
29775 \ \ MOV #23,W \ 3 MCLK = 4 MHz
29776 \ \ MOV #51,W \ 3 MCLK = 8 MHz
29777 \ MOV #104,W \ 3 MCLK = 16 MHz
29778 \ \ MOV #158,W \ 3 MCLK = 24 MHz
29779 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
29784 \ MOV @PSP+,TOS \ 2
29789 CODE 20_US \ n -- n * 20 us
29790 BEGIN \ here we presume that LCD_TIM_IFG = 1...
29792 BIT #1,&LCD_TIM_CTL \ 3
29793 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
29794 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
29796 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
29802 CODE TOP_LCD \ LCD Sample
29803 \ \ if write : %xxxxWWWW --
29804 \ \ if read : -- %0000RRRR
29805 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
29806 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
29807 0= IF \ write LCD bits pattern
29808 AND.B #LCD_DB,TOS \
29809 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
29810 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
29813 THEN \ read LCD bits pattern
29816 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
29817 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
29818 AND.B #LCD_DB,TOS \
29823 CODE LCD_W \ byte -- write byte to LCD
29825 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
29826 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
29827 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
29828 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
29829 COLON \ high level word starts here
29830 TOP_LCD 2 20_US \ write high nibble first
29835 CODE LCD_WrC \ char -- Write Char
29836 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
29841 CODE LCD_WrF \ func -- Write Fonction
29842 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
29848 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
29853 $02 LCD_WrF 100 20_us
29857 [UNDEFINED] OR [IF]
29859 \ https://forth-standard.org/standard/core/OR
29860 \ C OR x1 x2 -- x3 logical OR
29869 : LCD_Entry_set $04 OR LCD_WrF ;
29871 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
29873 : LCD_DSP_Shift $10 OR LCD_WrF ;
29875 : LCD_Fn_Set $20 OR LCD_WrF ;
29877 : LCD_CGRAM_Set $40 OR LCD_WrF ;
29879 : LCD_Goto $80 OR LCD_WrF ;
29881 CODE LCD_R \ -- byte read byte from LCD
29882 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
29883 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
29884 COLON \ starts a FORTH word
29885 TOP_LCD 2 20_us \ -- %0000HHHH
29886 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
29887 HI2LO \ switch from FORTH to assembler
29888 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
29889 ADD.B @PSP+,TOS \ -- %HHHHLLLL
29890 MOV @RSP+,IP \ restore IP saved by COLON
29895 CODE LCD_RdS \ -- status Read Status
29896 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
29901 CODE LCD_RdC \ -- char Read Char
29902 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
29908 \ ******************************\
29909 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
29910 \ ******************************\
29911 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
29912 BIT.B #SW2,&SW2_IN \ test switch S2
29913 0= IF \ case of switch S2 pressed
29914 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
29916 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
29919 BIT.B #SW1,&SW1_IN \ test switch S1 input
29920 0= IF \ case of Switch S1 pressed
29921 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
29923 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
29927 BW1 \ from quit on truncated RC5 message
29928 BW2 \ from repeated RC5 command
29929 BW3 \ from end of RC5_INT
29930 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
29935 \ ******************************\
29936 ASM RC5_INT \ wake up on Px.RC5 change interrupt
29937 \ ******************************\
29938 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
29939 \ ******************************\
29940 \ \ in : SR(9)=old Toggle bit memory (ADD on)
29941 \ \ SMclock = 8|16|24 MHz
29942 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
29943 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
29944 \ \ SR(9)=new Toggle bit memory (ADD on)
29945 \ ******************************\
29946 \ RC5_FirstStartBitHalfCycle: \
29947 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
29948 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
29949 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
29950 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
29951 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
29952 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
29953 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
29954 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
29955 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
29956 MOV #1778,X \ RC5_Period * 1us
29957 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
29958 MOV #14,W \ count of loop
29960 \ ******************************\
29961 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
29962 \ ******************************\ |
29963 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
29964 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
29965 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
29966 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
29967 \ RC5_Compute_3/4_Period: \ |
29968 RRUM #1,X \ X=1/2 cycle |
29971 ADD X,Y \ Y=3/4 cycle
29972 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
29974 \ ******************************\
29975 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
29976 \ ******************************\
29977 BIT.B #RC5,&IR_IN \ C_flag = IR bit
29978 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
29979 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
29980 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
29981 SUB #1,W \ decrement count loop
29982 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
29983 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
29984 0<> WHILE \ ----> out of loop ----+
29985 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
29987 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
29988 CMP Y,X \ 1 | cycle time out of bound ?
29989 U>= IF \ 2 ^ | yes:
29990 BIC #$30,&RC5_TIM_CTL \ | | stop timer
29991 GOTO BW1 \ | | quit on truncated RC5 message
29993 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
29995 REPEAT \ ----> loop back --+ | with X = new RC5_period value
29996 \ ******************************\ |
29997 \ RC5_SampleEndOf: \ <---------------------+
29998 \ ******************************\
29999 BIC #$30,&RC5_TIM_CTL \ stop timer
30000 \ ******************************\
30001 \ RC5_ComputeNewRC5word \
30002 \ ******************************\
30003 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
30004 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
30005 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
30006 \ ******************************\
30007 \ RC5_ComputeC6bit \
30008 \ ******************************\
30009 BIT #BIT14,T \ test /C6 bit in T
30010 0= IF BIS #BIT6,X \ set C6 bit in X
30011 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
30012 \ ******************************\
30013 \ RC5_CommandByteIsDone \ -- BASE RC5_code
30014 \ ******************************\
30015 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
30016 \ ******************************\
30017 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
30018 XOR @RSP,T \ (new XOR old) Toggle bits
30019 BIT #UF10,T \ repeated RC5_command ?
30020 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
30021 XOR #UF10,0(RSP) \ 5 toggle bit memory
30022 \ ******************************\
30023 \ Display IR_RC5 code \ X = RC5 code
30024 \ ******************************\
30026 MOV &BASE,2(PSP) \ save current base
30027 MOV #$10,&BASE \ set hex base
30028 MOV TOS,0(PSP) \ save TOS
30030 LO2HI \ switch from assembler to FORTH
30031 ['] LCD_CLEAR IS CR \ redirects CR
30032 ['] LCD_WrC IS EMIT \ redirects EMIT
30033 CR ." $" 2 U.R \ print IR_RC5 code
30034 ['] CR >BODY IS CR \ restore CR
30035 ['] EMIT >BODY IS EMIT \ restore EMIT
30036 HI2LO \ switch from FORTH to assembler
30037 MOV TOS,&BASE \ restore current BASE
30039 \ ******************************\
30041 \ ******************************\
30045 \ ------------------------------\
30047 \ ------------------------------\
30048 \ ... \ insert here your background task
30051 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
30052 ADD #4,X \ 1 X = BODY of SLEEP
30055 \ ------------------------------\
30059 \ ------------------------------\
30060 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
30061 \ - - \CNTL Counter lentgh \ 00 = 16 bits
30062 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
30063 \ -- \ID input divider \ 10 = /4
30064 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
30065 \ - \TBCLR TimerB Clear
30068 \ -------------------------------\
30069 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
30070 \ -- \CM Capture Mode
30075 \ --- \OUTMOD \ 011 = set/reset
30081 \ -------------------------------\
30083 \ -------------------------------\
30085 \ ------------------------------\
30086 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
30087 \ ------------------------------\
30088 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
30089 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
30090 \ ------------------------------\
30091 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
30092 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
30093 \ ------------------------------\
30094 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
30095 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
30096 \ ------------------------------\
30097 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
30098 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
30099 \ ------------------------------\
30100 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
30101 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
30102 \ ------------------------------\
30103 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
30104 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
30105 \ ------------------------------\
30106 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
30107 \ ------------------------------\
30108 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
30109 \ ------------------------------\
30110 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
30111 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
30112 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
30113 \ ------------------------------\
30114 BIS.B #LCDVo,&LCDVo_DIR \
30115 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
30116 \ ------------------------------\
30117 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
30118 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
30119 \ ------------------------------\
30120 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
30121 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
30122 \ ******************************\
30124 \ ******************************\
30125 BIS.B #RC5,&IR_IE \ enable RC5_Int
30126 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
30127 MOV #RC5_INT,&IR_Vec \ init interrupt vector
30128 \ ******************************\
30129 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
30130 \ ******************************\
30131 \ %01 0001 0100 \ TAxCTL
30132 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
30133 \ -- \ ID divided by 1
30134 \ -- \ MC MODE = up to TAxCCRn
30135 \ - \ TACLR clear timer count
30138 \ ------------------------------\
30139 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
30140 \ ------------------------------\
30142 \ --- \ TAIDEX pre divisor
30143 \ ------------------------------\
30144 \ %0000 0000 0000 0101 \ TAxCCR0
30145 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
30146 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
30147 \ ------------------------------\
30148 \ %0000 0000 0001 0000 \ TAxCCTL0
30149 \ - \ CAP capture/compare mode = compare
30152 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
30153 \ ------------------------------\
30154 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
30155 \ ------------------------------\
30156 \ define LPM mode for ACCEPT \
30157 \ ------------------------------\
30158 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
30159 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
30160 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
30162 \ ------------------------------\
30163 \ redirects to background task \
30164 \ ------------------------------\
30166 MOV #BACKGROUND,2(X) \
30167 \ ------------------------------\
30169 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
30171 \ ------------------------------\
30173 \ ------------------------------\
30174 $03E8 20_US \ 1- wait 20 ms
30175 $03 TOP_LCD \ 2- send DB5=DB4=1
30176 $CD 20_US \ 3- wait 4,1 ms
30177 $03 TOP_LCD \ 4- send again DB5=DB4=1
30178 $5 20_US \ 5- wait 0,1 ms
30179 $03 TOP_LCD \ 6- send again again DB5=DB4=1
30180 $2 20_US \ wait 40 us = LCD cycle
30181 $02 TOP_LCD \ 7- send DB5=1 DB4=0
30182 $2 20_US \ wait 40 us = LCD cycle
30183 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
30184 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
30185 LCD_Clear \ 10- "LCD_Clear"
30186 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
30187 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
30188 LCD_Clear \ 10- "LCD_Clear"
30189 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
30190 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
30192 ['] CR >BODY IS CR \
30193 ['] EMIT >BODY IS EMIT \
30194 ." RC5toLCD is running. Type STOP to quit"
30195 LIT RECURSE IS WARM \ replace WARM by this START routine
30196 ABORT \ and continue with the next word after WARM...
30197 ; \ ...until interpreter falls in sleep mode within ACCEPT.
30200 CODE STOP \ stops multitasking, must to be used before downloading app
30201 \ restore default action of primary DEFERred word SLEEP, assembly version
30202 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
30203 ADD #4,X \ X = BODY of SLEEP
30204 MOV X,-2(X) \ restore the default background
30207 \ restore default action of primary DEFERred word WARM, FORTH version
30208 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
30210 COLD \ because we want to reset CPU and interrupt vectors
30215 ; downloading RC5toLCD.4th is done
30216 RST_HERE ; this app is protected against <reset>
30224 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
30226 [DEFINED] ASM [IF] \ security test
30230 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
30232 CODE MAX \ n1 n2 -- n3 signed maximum
30233 CMP @PSP,TOS \ n2-n1
30234 S< ?GOTO FW1 \ n2<n1
30240 CODE MIN \ n1 n2 -- n3 signed minimum
30241 CMP @PSP,TOS \ n2-n1
30242 S< ?GOTO BW1 \ n2<n1
30250 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
30251 : U.R \ u n -- display u unsigned in n width (n >= 2)
30253 R> OVER - 0 MAX SPACES TYPE
30258 \ CODE 20_US \ n -- n * 20 us
30259 \ BEGIN \ 3 cycles loop + 6~
30260 \ \ MOV #5,W \ 3 MCLK = 1 MHz
30261 \ \ MOV #23,W \ 3 MCLK = 4 MHz
30262 \ \ MOV #51,W \ 3 MCLK = 8 MHz
30263 \ MOV #104,W \ 3 MCLK = 16 MHz
30264 \ \ MOV #158,W \ 3 MCLK = 24 MHz
30265 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
30270 \ MOV @PSP+,TOS \ 2
30275 CODE 20_US \ n -- n * 20 us
30276 BEGIN \ here we presume that LCD_TIM_IFG = 1...
30278 BIT #1,&LCD_TIM_CTL \ 3
30279 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
30280 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
30282 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
30288 CODE TOP_LCD \ LCD Sample
30289 \ \ if write : %xxxxWWWW --
30290 \ \ if read : -- %0000RRRR
30291 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
30292 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
30293 0= IF \ write LCD bits pattern
30294 AND.B #LCD_DB,TOS \
30295 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
30296 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
30299 THEN \ read LCD bits pattern
30302 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
30303 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
30304 AND.B #LCD_DB,TOS \
30309 CODE LCD_W \ byte -- write byte to LCD
30311 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
30312 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
30313 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
30314 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
30315 COLON \ high level word starts here
30316 TOP_LCD 2 20_US \ write high nibble first
30321 CODE LCD_WrC \ char -- Write Char
30322 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
30327 CODE LCD_WrF \ func -- Write Fonction
30328 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
30334 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
30339 $02 LCD_WrF 100 20_us
30343 [UNDEFINED] OR [IF]
30345 \ https://forth-standard.org/standard/core/OR
30346 \ C OR x1 x2 -- x3 logical OR
30355 : LCD_Entry_set $04 OR LCD_WrF ;
30357 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
30359 : LCD_DSP_Shift $10 OR LCD_WrF ;
30361 : LCD_Fn_Set $20 OR LCD_WrF ;
30363 : LCD_CGRAM_Set $40 OR LCD_WrF ;
30365 : LCD_Goto $80 OR LCD_WrF ;
30367 CODE LCD_R \ -- byte read byte from LCD
30368 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
30369 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
30370 COLON \ starts a FORTH word
30371 TOP_LCD 2 20_us \ -- %0000HHHH
30372 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
30373 HI2LO \ switch from FORTH to assembler
30374 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
30375 ADD.B @PSP+,TOS \ -- %HHHHLLLL
30376 MOV @RSP+,IP \ restore IP saved by COLON
30381 CODE LCD_RdS \ -- status Read Status
30382 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
30387 CODE LCD_RdC \ -- char Read Char
30388 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
30394 \ ******************************\
30395 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
30396 \ ******************************\
30397 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
30398 BIT.B #SW2,&SW2_IN \ test switch S2
30399 0= IF \ case of switch S2 pressed
30400 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
30402 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
30405 BIT.B #SW1,&SW1_IN \ test switch S1 input
30406 0= IF \ case of Switch S1 pressed
30407 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
30409 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
30413 BW1 \ from quit on truncated RC5 message
30414 BW2 \ from repeated RC5 command
30415 BW3 \ from end of RC5_INT
30416 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
30421 \ ******************************\
30422 ASM RC5_INT \ wake up on Px.RC5 change interrupt
30423 \ ******************************\
30424 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
30425 \ ******************************\
30426 \ \ in : SR(9)=old Toggle bit memory (ADD on)
30427 \ \ SMclock = 8|16|24 MHz
30428 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
30429 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
30430 \ \ SR(9)=new Toggle bit memory (ADD on)
30431 \ ******************************\
30432 \ RC5_FirstStartBitHalfCycle: \
30433 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
30434 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
30435 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
30436 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
30437 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
30438 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
30439 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
30440 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
30441 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
30442 MOV #1778,X \ RC5_Period * 1us
30443 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
30444 MOV #14,W \ count of loop
30446 \ ******************************\
30447 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
30448 \ ******************************\ |
30449 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
30450 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
30451 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
30452 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
30453 \ RC5_Compute_3/4_Period: \ |
30454 RRUM #1,X \ X=1/2 cycle |
30457 ADD X,Y \ Y=3/4 cycle
30458 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
30460 \ ******************************\
30461 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
30462 \ ******************************\
30463 BIT.B #RC5,&IR_IN \ C_flag = IR bit
30464 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
30465 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
30466 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
30467 SUB #1,W \ decrement count loop
30468 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
30469 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
30470 0<> WHILE \ ----> out of loop ----+
30471 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
30473 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
30474 CMP Y,X \ 1 | cycle time out of bound ?
30475 U>= IF \ 2 ^ | yes:
30476 BIC #$30,&RC5_TIM_CTL \ | | stop timer
30477 GOTO BW1 \ | | quit on truncated RC5 message
30479 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
30481 REPEAT \ ----> loop back --+ | with X = new RC5_period value
30482 \ ******************************\ |
30483 \ RC5_SampleEndOf: \ <---------------------+
30484 \ ******************************\
30485 BIC #$30,&RC5_TIM_CTL \ stop timer
30486 \ ******************************\
30487 \ RC5_ComputeNewRC5word \
30488 \ ******************************\
30489 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
30490 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
30491 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
30492 \ ******************************\
30493 \ RC5_ComputeC6bit \
30494 \ ******************************\
30495 BIT #BIT14,T \ test /C6 bit in T
30496 0= IF BIS #BIT6,X \ set C6 bit in X
30497 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
30498 \ ******************************\
30499 \ RC5_CommandByteIsDone \ -- BASE RC5_code
30500 \ ******************************\
30501 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
30502 \ ******************************\
30503 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
30504 XOR @RSP,T \ (new XOR old) Toggle bits
30505 BIT #UF10,T \ repeated RC5_command ?
30506 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
30507 XOR #UF10,0(RSP) \ 5 toggle bit memory
30508 \ ******************************\
30509 \ Display IR_RC5 code \ X = RC5 code
30510 \ ******************************\
30512 MOV &BASE,2(PSP) \ save current base
30513 MOV #$10,&BASE \ set hex base
30514 MOV TOS,0(PSP) \ save TOS
30516 LO2HI \ switch from assembler to FORTH
30517 ['] LCD_CLEAR IS CR \ redirects CR
30518 ['] LCD_WrC IS EMIT \ redirects EMIT
30519 CR ." $" 2 U.R \ print IR_RC5 code
30520 ['] CR >BODY IS CR \ restore CR
30521 ['] EMIT >BODY IS EMIT \ restore EMIT
30522 HI2LO \ switch from FORTH to assembler
30523 MOV TOS,&BASE \ restore current BASE
30525 \ ******************************\
30527 \ ******************************\
30531 \ ------------------------------\
30533 \ ------------------------------\
30534 \ ... \ insert here your background task
30537 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
30538 ADD #4,X \ 1 X = BODY of SLEEP
30541 \ ------------------------------\
30545 \ ------------------------------\
30546 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
30547 \ - - \CNTL Counter lentgh \ 00 = 16 bits
30548 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
30549 \ -- \ID input divider \ 10 = /4
30550 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
30551 \ - \TBCLR TimerB Clear
30554 \ -------------------------------\
30555 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
30556 \ -- \CM Capture Mode
30561 \ --- \OUTMOD \ 011 = set/reset
30567 \ -------------------------------\
30569 \ -------------------------------\
30571 \ ------------------------------\
30572 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
30573 \ ------------------------------\
30574 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
30575 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
30576 \ ------------------------------\
30577 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
30578 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
30579 \ ------------------------------\
30580 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
30581 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
30582 \ ------------------------------\
30583 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
30584 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
30585 \ ------------------------------\
30586 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
30587 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
30588 \ ------------------------------\
30589 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
30590 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
30591 \ ------------------------------\
30592 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
30593 \ ------------------------------\
30594 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
30595 \ ------------------------------\
30596 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
30597 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
30598 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
30599 \ ------------------------------\
30600 BIS.B #LCDVo,&LCDVo_DIR \
30601 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
30602 \ ------------------------------\
30603 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
30604 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
30605 \ ------------------------------\
30606 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
30607 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
30608 \ ******************************\
30610 \ ******************************\
30611 BIS.B #RC5,&IR_IE \ enable RC5_Int
30612 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
30613 MOV #RC5_INT,&IR_Vec \ init interrupt vector
30614 \ ******************************\
30615 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
30616 \ ******************************\
30617 \ %01 0001 0100 \ TAxCTL
30618 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
30619 \ -- \ ID divided by 1
30620 \ -- \ MC MODE = up to TAxCCRn
30621 \ - \ TACLR clear timer count
30624 \ ------------------------------\
30625 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
30626 \ ------------------------------\
30628 \ --- \ TAIDEX pre divisor
30629 \ ------------------------------\
30630 \ %0000 0000 0000 0101 \ TAxCCR0
30631 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
30632 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
30633 \ ------------------------------\
30634 \ %0000 0000 0001 0000 \ TAxCCTL0
30635 \ - \ CAP capture/compare mode = compare
30638 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
30639 \ ------------------------------\
30640 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
30641 \ ------------------------------\
30642 \ define LPM mode for ACCEPT \
30643 \ ------------------------------\
30644 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
30645 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
30646 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
30648 \ ------------------------------\
30649 \ redirects to background task \
30650 \ ------------------------------\
30652 MOV #BACKGROUND,2(X) \
30653 \ ------------------------------\
30655 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
30657 \ ------------------------------\
30659 \ ------------------------------\
30660 $03E8 20_US \ 1- wait 20 ms
30661 $03 TOP_LCD \ 2- send DB5=DB4=1
30662 $CD 20_US \ 3- wait 4,1 ms
30663 $03 TOP_LCD \ 4- send again DB5=DB4=1
30664 $5 20_US \ 5- wait 0,1 ms
30665 $03 TOP_LCD \ 6- send again again DB5=DB4=1
30666 $2 20_US \ wait 40 us = LCD cycle
30667 $02 TOP_LCD \ 7- send DB5=1 DB4=0
30668 $2 20_US \ wait 40 us = LCD cycle
30669 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
30670 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
30671 LCD_Clear \ 10- "LCD_Clear"
30672 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
30673 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
30674 LCD_Clear \ 10- "LCD_Clear"
30675 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
30676 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
30678 ['] CR >BODY IS CR \
30679 ['] EMIT >BODY IS EMIT \
30680 ." RC5toLCD is running. Type STOP to quit"
30681 LIT RECURSE IS WARM \ replace WARM by this START routine
30682 ABORT \ and continue with the next word after WARM...
30683 ; \ ...until interpreter falls in sleep mode within ACCEPT.
30686 CODE STOP \ stops multitasking, must to be used before downloading app
30687 \ restore default action of primary DEFERred word SLEEP, assembly version
30688 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
30689 ADD #4,X \ X = BODY of SLEEP
30690 MOV X,-2(X) \ restore the default background
30693 \ restore default action of primary DEFERred word WARM, FORTH version
30694 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
30696 COLD \ because we want to reset CPU and interrupt vectors
30701 ; downloading RC5toLCD.4th is done
30702 RST_HERE ; this app is protected against <reset>
30710 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
30712 [DEFINED] ASM [IF] \ security test
30716 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
30718 CODE MAX \ n1 n2 -- n3 signed maximum
30719 CMP @PSP,TOS \ n2-n1
30720 S< ?GOTO FW1 \ n2<n1
30726 CODE MIN \ n1 n2 -- n3 signed minimum
30727 CMP @PSP,TOS \ n2-n1
30728 S< ?GOTO BW1 \ n2<n1
30736 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
30737 : U.R \ u n -- display u unsigned in n width (n >= 2)
30739 R> OVER - 0 MAX SPACES TYPE
30744 \ CODE 20_US \ n -- n * 20 us
30745 \ BEGIN \ 3 cycles loop + 6~
30746 \ \ MOV #5,W \ 3 MCLK = 1 MHz
30747 \ \ MOV #23,W \ 3 MCLK = 4 MHz
30748 \ \ MOV #51,W \ 3 MCLK = 8 MHz
30749 \ MOV #104,W \ 3 MCLK = 16 MHz
30750 \ \ MOV #158,W \ 3 MCLK = 24 MHz
30751 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
30756 \ MOV @PSP+,TOS \ 2
30761 CODE 20_US \ n -- n * 20 us
30762 BEGIN \ here we presume that LCD_TIM_IFG = 1...
30764 BIT #1,&LCD_TIM_CTL \ 3
30765 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
30766 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
30768 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
30774 CODE TOP_LCD \ LCD Sample
30775 \ \ if write : %xxxxWWWW --
30776 \ \ if read : -- %0000RRRR
30777 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
30778 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
30779 0= IF \ write LCD bits pattern
30780 AND.B #LCD_DB,TOS \
30781 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
30782 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
30785 THEN \ read LCD bits pattern
30788 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
30789 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
30790 AND.B #LCD_DB,TOS \
30795 CODE LCD_W \ byte -- write byte to LCD
30797 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
30798 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
30799 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
30800 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
30801 COLON \ high level word starts here
30802 TOP_LCD 2 20_US \ write high nibble first
30807 CODE LCD_WrC \ char -- Write Char
30808 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
30813 CODE LCD_WrF \ func -- Write Fonction
30814 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
30820 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
30825 $02 LCD_WrF 100 20_us
30829 [UNDEFINED] OR [IF]
30831 \ https://forth-standard.org/standard/core/OR
30832 \ C OR x1 x2 -- x3 logical OR
30841 : LCD_Entry_set $04 OR LCD_WrF ;
30843 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
30845 : LCD_DSP_Shift $10 OR LCD_WrF ;
30847 : LCD_Fn_Set $20 OR LCD_WrF ;
30849 : LCD_CGRAM_Set $40 OR LCD_WrF ;
30851 : LCD_Goto $80 OR LCD_WrF ;
30853 CODE LCD_R \ -- byte read byte from LCD
30854 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
30855 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
30856 COLON \ starts a FORTH word
30857 TOP_LCD 2 20_us \ -- %0000HHHH
30858 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
30859 HI2LO \ switch from FORTH to assembler
30860 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
30861 ADD.B @PSP+,TOS \ -- %HHHHLLLL
30862 MOV @RSP+,IP \ restore IP saved by COLON
30867 CODE LCD_RdS \ -- status Read Status
30868 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
30873 CODE LCD_RdC \ -- char Read Char
30874 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
30880 \ ******************************\
30881 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
30882 \ ******************************\
30883 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
30884 BIT.B #SW2,&SW2_IN \ test switch S2
30885 0= IF \ case of switch S2 pressed
30886 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
30888 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
30891 BIT.B #SW1,&SW1_IN \ test switch S1 input
30892 0= IF \ case of Switch S1 pressed
30893 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
30895 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
30899 BW1 \ from quit on truncated RC5 message
30900 BW2 \ from repeated RC5 command
30901 BW3 \ from end of RC5_INT
30902 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
30907 \ ******************************\
30908 ASM RC5_INT \ wake up on Px.RC5 change interrupt
30909 \ ******************************\
30910 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
30911 \ ******************************\
30912 \ \ in : SR(9)=old Toggle bit memory (ADD on)
30913 \ \ SMclock = 8|16|24 MHz
30914 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
30915 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
30916 \ \ SR(9)=new Toggle bit memory (ADD on)
30917 \ ******************************\
30918 \ RC5_FirstStartBitHalfCycle: \
30919 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
30920 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
30921 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
30922 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
30923 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
30924 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
30925 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
30926 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
30927 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
30928 MOV #1778,X \ RC5_Period * 1us
30929 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
30930 MOV #14,W \ count of loop
30932 \ ******************************\
30933 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
30934 \ ******************************\ |
30935 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
30936 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
30937 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
30938 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
30939 \ RC5_Compute_3/4_Period: \ |
30940 RRUM #1,X \ X=1/2 cycle |
30943 ADD X,Y \ Y=3/4 cycle
30944 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
30946 \ ******************************\
30947 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
30948 \ ******************************\
30949 BIT.B #RC5,&IR_IN \ C_flag = IR bit
30950 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
30951 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
30952 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
30953 SUB #1,W \ decrement count loop
30954 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
30955 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
30956 0<> WHILE \ ----> out of loop ----+
30957 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
30959 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
30960 CMP Y,X \ 1 | cycle time out of bound ?
30961 U>= IF \ 2 ^ | yes:
30962 BIC #$30,&RC5_TIM_CTL \ | | stop timer
30963 GOTO BW1 \ | | quit on truncated RC5 message
30965 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
30967 REPEAT \ ----> loop back --+ | with X = new RC5_period value
30968 \ ******************************\ |
30969 \ RC5_SampleEndOf: \ <---------------------+
30970 \ ******************************\
30971 BIC #$30,&RC5_TIM_CTL \ stop timer
30972 \ ******************************\
30973 \ RC5_ComputeNewRC5word \
30974 \ ******************************\
30975 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
30976 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
30977 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
30978 \ ******************************\
30979 \ RC5_ComputeC6bit \
30980 \ ******************************\
30981 BIT #BIT14,T \ test /C6 bit in T
30982 0= IF BIS #BIT6,X \ set C6 bit in X
30983 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
30984 \ ******************************\
30985 \ RC5_CommandByteIsDone \ -- BASE RC5_code
30986 \ ******************************\
30987 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
30988 \ ******************************\
30989 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
30990 XOR @RSP,T \ (new XOR old) Toggle bits
30991 BIT #UF10,T \ repeated RC5_command ?
30992 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
30993 XOR #UF10,0(RSP) \ 5 toggle bit memory
30994 \ ******************************\
30995 \ Display IR_RC5 code \ X = RC5 code
30996 \ ******************************\
30998 MOV &BASE,2(PSP) \ save current base
30999 MOV #$10,&BASE \ set hex base
31000 MOV TOS,0(PSP) \ save TOS
31002 LO2HI \ switch from assembler to FORTH
31003 ['] LCD_CLEAR IS CR \ redirects CR
31004 ['] LCD_WrC IS EMIT \ redirects EMIT
31005 CR ." $" 2 U.R \ print IR_RC5 code
31006 ['] CR >BODY IS CR \ restore CR
31007 ['] EMIT >BODY IS EMIT \ restore EMIT
31008 HI2LO \ switch from FORTH to assembler
31009 MOV TOS,&BASE \ restore current BASE
31011 \ ******************************\
31013 \ ******************************\
31017 \ ------------------------------\
31019 \ ------------------------------\
31020 \ ... \ insert here your background task
31023 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
31024 ADD #4,X \ 1 X = BODY of SLEEP
31027 \ ------------------------------\
31031 \ ------------------------------\
31032 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
31033 \ - - \CNTL Counter lentgh \ 00 = 16 bits
31034 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
31035 \ -- \ID input divider \ 10 = /4
31036 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
31037 \ - \TBCLR TimerB Clear
31040 \ -------------------------------\
31041 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
31042 \ -- \CM Capture Mode
31047 \ --- \OUTMOD \ 011 = set/reset
31053 \ -------------------------------\
31055 \ -------------------------------\
31057 \ ------------------------------\
31058 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
31059 \ ------------------------------\
31060 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
31061 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
31062 \ ------------------------------\
31063 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
31064 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
31065 \ ------------------------------\
31066 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
31067 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
31068 \ ------------------------------\
31069 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
31070 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
31071 \ ------------------------------\
31072 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
31073 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
31074 \ ------------------------------\
31075 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
31076 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
31077 \ ------------------------------\
31078 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
31079 \ ------------------------------\
31080 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
31081 \ ------------------------------\
31082 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
31083 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
31084 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
31085 \ ------------------------------\
31086 BIS.B #LCDVo,&LCDVo_DIR \
31087 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
31088 \ ------------------------------\
31089 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
31090 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
31091 \ ------------------------------\
31092 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
31093 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
31094 \ ******************************\
31096 \ ******************************\
31097 BIS.B #RC5,&IR_IE \ enable RC5_Int
31098 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
31099 MOV #RC5_INT,&IR_Vec \ init interrupt vector
31100 \ ******************************\
31101 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
31102 \ ******************************\
31103 \ %01 0001 0100 \ TAxCTL
31104 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
31105 \ -- \ ID divided by 1
31106 \ -- \ MC MODE = up to TAxCCRn
31107 \ - \ TACLR clear timer count
31110 \ ------------------------------\
31111 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
31112 \ ------------------------------\
31114 \ --- \ TAIDEX pre divisor
31115 \ ------------------------------\
31116 \ %0000 0000 0000 0101 \ TAxCCR0
31117 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
31118 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
31119 \ ------------------------------\
31120 \ %0000 0000 0001 0000 \ TAxCCTL0
31121 \ - \ CAP capture/compare mode = compare
31124 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
31125 \ ------------------------------\
31126 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
31127 \ ------------------------------\
31128 \ define LPM mode for ACCEPT \
31129 \ ------------------------------\
31130 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
31131 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
31132 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
31134 \ ------------------------------\
31135 \ redirects to background task \
31136 \ ------------------------------\
31138 MOV #BACKGROUND,2(X) \
31139 \ ------------------------------\
31141 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
31143 \ ------------------------------\
31145 \ ------------------------------\
31146 $03E8 20_US \ 1- wait 20 ms
31147 $03 TOP_LCD \ 2- send DB5=DB4=1
31148 $CD 20_US \ 3- wait 4,1 ms
31149 $03 TOP_LCD \ 4- send again DB5=DB4=1
31150 $5 20_US \ 5- wait 0,1 ms
31151 $03 TOP_LCD \ 6- send again again DB5=DB4=1
31152 $2 20_US \ wait 40 us = LCD cycle
31153 $02 TOP_LCD \ 7- send DB5=1 DB4=0
31154 $2 20_US \ wait 40 us = LCD cycle
31155 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
31156 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
31157 LCD_Clear \ 10- "LCD_Clear"
31158 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
31159 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
31160 LCD_Clear \ 10- "LCD_Clear"
31161 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
31162 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
31164 ['] CR >BODY IS CR \
31165 ['] EMIT >BODY IS EMIT \
31166 ." RC5toLCD is running. Type STOP to quit"
31167 LIT RECURSE IS WARM \ replace WARM by this START routine
31168 ABORT \ and continue with the next word after WARM...
31169 ; \ ...until interpreter falls in sleep mode within ACCEPT.
31172 CODE STOP \ stops multitasking, must to be used before downloading app
31173 \ restore default action of primary DEFERred word SLEEP, assembly version
31174 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
31175 ADD #4,X \ X = BODY of SLEEP
31176 MOV X,-2(X) \ restore the default background
31179 \ restore default action of primary DEFERred word WARM, FORTH version
31180 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
31182 COLD \ because we want to reset CPU and interrupt vectors
31187 ; downloading RC5toLCD.4th is done
31188 RST_HERE ; this app is protected against <reset>
31196 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
31198 [DEFINED] ASM [IF] \ security test
31202 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
31204 CODE MAX \ n1 n2 -- n3 signed maximum
31205 CMP @PSP,TOS \ n2-n1
31206 S< ?GOTO FW1 \ n2<n1
31212 CODE MIN \ n1 n2 -- n3 signed minimum
31213 CMP @PSP,TOS \ n2-n1
31214 S< ?GOTO BW1 \ n2<n1
31222 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
31223 : U.R \ u n -- display u unsigned in n width (n >= 2)
31225 R> OVER - 0 MAX SPACES TYPE
31230 \ CODE 20_US \ n -- n * 20 us
31231 \ BEGIN \ 3 cycles loop + 6~
31232 \ \ MOV #5,W \ 3 MCLK = 1 MHz
31233 \ \ MOV #23,W \ 3 MCLK = 4 MHz
31234 \ \ MOV #51,W \ 3 MCLK = 8 MHz
31235 \ MOV #104,W \ 3 MCLK = 16 MHz
31236 \ \ MOV #158,W \ 3 MCLK = 24 MHz
31237 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
31242 \ MOV @PSP+,TOS \ 2
31247 CODE 20_US \ n -- n * 20 us
31248 BEGIN \ here we presume that LCD_TIM_IFG = 1...
31250 BIT #1,&LCD_TIM_CTL \ 3
31251 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
31252 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
31254 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
31260 CODE TOP_LCD \ LCD Sample
31261 \ \ if write : %xxxxWWWW --
31262 \ \ if read : -- %0000RRRR
31263 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
31264 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
31265 0= IF \ write LCD bits pattern
31266 AND.B #LCD_DB,TOS \
31267 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
31268 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
31271 THEN \ read LCD bits pattern
31274 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
31275 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
31276 AND.B #LCD_DB,TOS \
31281 CODE LCD_W \ byte -- write byte to LCD
31283 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
31284 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
31285 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
31286 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
31287 COLON \ high level word starts here
31288 TOP_LCD 2 20_US \ write high nibble first
31293 CODE LCD_WrC \ char -- Write Char
31294 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
31299 CODE LCD_WrF \ func -- Write Fonction
31300 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
31306 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
31311 $02 LCD_WrF 100 20_us
31315 [UNDEFINED] OR [IF]
31317 \ https://forth-standard.org/standard/core/OR
31318 \ C OR x1 x2 -- x3 logical OR
31327 : LCD_Entry_set $04 OR LCD_WrF ;
31329 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
31331 : LCD_DSP_Shift $10 OR LCD_WrF ;
31333 : LCD_Fn_Set $20 OR LCD_WrF ;
31335 : LCD_CGRAM_Set $40 OR LCD_WrF ;
31337 : LCD_Goto $80 OR LCD_WrF ;
31339 CODE LCD_R \ -- byte read byte from LCD
31340 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
31341 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
31342 COLON \ starts a FORTH word
31343 TOP_LCD 2 20_us \ -- %0000HHHH
31344 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
31345 HI2LO \ switch from FORTH to assembler
31346 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
31347 ADD.B @PSP+,TOS \ -- %HHHHLLLL
31348 MOV @RSP+,IP \ restore IP saved by COLON
31353 CODE LCD_RdS \ -- status Read Status
31354 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
31359 CODE LCD_RdC \ -- char Read Char
31360 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
31366 \ ******************************\
31367 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
31368 \ ******************************\
31369 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
31370 BIT.B #SW2,&SW2_IN \ test switch S2
31371 0= IF \ case of switch S2 pressed
31372 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
31374 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
31377 BIT.B #SW1,&SW1_IN \ test switch S1 input
31378 0= IF \ case of Switch S1 pressed
31379 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
31381 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
31385 BW1 \ from quit on truncated RC5 message
31386 BW2 \ from repeated RC5 command
31387 BW3 \ from end of RC5_INT
31388 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
31393 \ ******************************\
31394 ASM RC5_INT \ wake up on Px.RC5 change interrupt
31395 \ ******************************\
31396 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
31397 \ ******************************\
31398 \ \ in : SR(9)=old Toggle bit memory (ADD on)
31399 \ \ SMclock = 8|16|24 MHz
31400 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
31401 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
31402 \ \ SR(9)=new Toggle bit memory (ADD on)
31403 \ ******************************\
31404 \ RC5_FirstStartBitHalfCycle: \
31405 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
31406 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
31407 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
31408 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
31409 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
31410 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
31411 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
31412 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
31413 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
31414 MOV #1778,X \ RC5_Period * 1us
31415 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
31416 MOV #14,W \ count of loop
31418 \ ******************************\
31419 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
31420 \ ******************************\ |
31421 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
31422 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
31423 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
31424 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
31425 \ RC5_Compute_3/4_Period: \ |
31426 RRUM #1,X \ X=1/2 cycle |
31429 ADD X,Y \ Y=3/4 cycle
31430 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
31432 \ ******************************\
31433 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
31434 \ ******************************\
31435 BIT.B #RC5,&IR_IN \ C_flag = IR bit
31436 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
31437 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
31438 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
31439 SUB #1,W \ decrement count loop
31440 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
31441 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
31442 0<> WHILE \ ----> out of loop ----+
31443 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
31445 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
31446 CMP Y,X \ 1 | cycle time out of bound ?
31447 U>= IF \ 2 ^ | yes:
31448 BIC #$30,&RC5_TIM_CTL \ | | stop timer
31449 GOTO BW1 \ | | quit on truncated RC5 message
31451 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
31453 REPEAT \ ----> loop back --+ | with X = new RC5_period value
31454 \ ******************************\ |
31455 \ RC5_SampleEndOf: \ <---------------------+
31456 \ ******************************\
31457 BIC #$30,&RC5_TIM_CTL \ stop timer
31458 \ ******************************\
31459 \ RC5_ComputeNewRC5word \
31460 \ ******************************\
31461 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
31462 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
31463 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
31464 \ ******************************\
31465 \ RC5_ComputeC6bit \
31466 \ ******************************\
31467 BIT #BIT14,T \ test /C6 bit in T
31468 0= IF BIS #BIT6,X \ set C6 bit in X
31469 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
31470 \ ******************************\
31471 \ RC5_CommandByteIsDone \ -- BASE RC5_code
31472 \ ******************************\
31473 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
31474 \ ******************************\
31475 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
31476 XOR @RSP,T \ (new XOR old) Toggle bits
31477 BIT #UF10,T \ repeated RC5_command ?
31478 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
31479 XOR #UF10,0(RSP) \ 5 toggle bit memory
31480 \ ******************************\
31481 \ Display IR_RC5 code \ X = RC5 code
31482 \ ******************************\
31484 MOV &BASE,2(PSP) \ save current base
31485 MOV #$10,&BASE \ set hex base
31486 MOV TOS,0(PSP) \ save TOS
31488 LO2HI \ switch from assembler to FORTH
31489 ['] LCD_CLEAR IS CR \ redirects CR
31490 ['] LCD_WrC IS EMIT \ redirects EMIT
31491 CR ." $" 2 U.R \ print IR_RC5 code
31492 ['] CR >BODY IS CR \ restore CR
31493 ['] EMIT >BODY IS EMIT \ restore EMIT
31494 HI2LO \ switch from FORTH to assembler
31495 MOV TOS,&BASE \ restore current BASE
31497 \ ******************************\
31499 \ ******************************\
31503 \ ------------------------------\
31505 \ ------------------------------\
31506 \ ... \ insert here your background task
31509 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
31510 ADD #4,X \ 1 X = BODY of SLEEP
31513 \ ------------------------------\
31517 \ ------------------------------\
31518 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
31519 \ - - \CNTL Counter lentgh \ 00 = 16 bits
31520 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
31521 \ -- \ID input divider \ 10 = /4
31522 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
31523 \ - \TBCLR TimerB Clear
31526 \ -------------------------------\
31527 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
31528 \ -- \CM Capture Mode
31533 \ --- \OUTMOD \ 011 = set/reset
31539 \ -------------------------------\
31541 \ -------------------------------\
31543 \ ------------------------------\
31544 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
31545 \ ------------------------------\
31546 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
31547 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
31548 \ ------------------------------\
31549 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
31550 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
31551 \ ------------------------------\
31552 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
31553 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
31554 \ ------------------------------\
31555 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
31556 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
31557 \ ------------------------------\
31558 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
31559 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
31560 \ ------------------------------\
31561 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
31562 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
31563 \ ------------------------------\
31564 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
31565 \ ------------------------------\
31566 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
31567 \ ------------------------------\
31568 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
31569 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
31570 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
31571 \ ------------------------------\
31572 BIS.B #LCDVo,&LCDVo_DIR \
31573 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
31574 \ ------------------------------\
31575 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
31576 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
31577 \ ------------------------------\
31578 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
31579 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
31580 \ ******************************\
31582 \ ******************************\
31583 BIS.B #RC5,&IR_IE \ enable RC5_Int
31584 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
31585 MOV #RC5_INT,&IR_Vec \ init interrupt vector
31586 \ ******************************\
31587 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
31588 \ ******************************\
31589 \ %01 0001 0100 \ TAxCTL
31590 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
31591 \ -- \ ID divided by 1
31592 \ -- \ MC MODE = up to TAxCCRn
31593 \ - \ TACLR clear timer count
31596 \ ------------------------------\
31597 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
31598 \ ------------------------------\
31600 \ --- \ TAIDEX pre divisor
31601 \ ------------------------------\
31602 \ %0000 0000 0000 0101 \ TAxCCR0
31603 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
31604 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
31605 \ ------------------------------\
31606 \ %0000 0000 0001 0000 \ TAxCCTL0
31607 \ - \ CAP capture/compare mode = compare
31610 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
31611 \ ------------------------------\
31612 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
31613 \ ------------------------------\
31614 \ define LPM mode for ACCEPT \
31615 \ ------------------------------\
31616 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
31617 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
31618 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
31620 \ ------------------------------\
31621 \ redirects to background task \
31622 \ ------------------------------\
31624 MOV #BACKGROUND,2(X) \
31625 \ ------------------------------\
31627 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
31629 \ ------------------------------\
31631 \ ------------------------------\
31632 $03E8 20_US \ 1- wait 20 ms
31633 $03 TOP_LCD \ 2- send DB5=DB4=1
31634 $CD 20_US \ 3- wait 4,1 ms
31635 $03 TOP_LCD \ 4- send again DB5=DB4=1
31636 $5 20_US \ 5- wait 0,1 ms
31637 $03 TOP_LCD \ 6- send again again DB5=DB4=1
31638 $2 20_US \ wait 40 us = LCD cycle
31639 $02 TOP_LCD \ 7- send DB5=1 DB4=0
31640 $2 20_US \ wait 40 us = LCD cycle
31641 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
31642 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
31643 LCD_Clear \ 10- "LCD_Clear"
31644 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
31645 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
31646 LCD_Clear \ 10- "LCD_Clear"
31647 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
31648 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
31650 ['] CR >BODY IS CR \
31651 ['] EMIT >BODY IS EMIT \
31652 ." RC5toLCD is running. Type STOP to quit"
31653 LIT RECURSE IS WARM \ replace WARM by this START routine
31654 ABORT \ and continue with the next word after WARM...
31655 ; \ ...until interpreter falls in sleep mode within ACCEPT.
31658 CODE STOP \ stops multitasking, must to be used before downloading app
31659 \ restore default action of primary DEFERred word SLEEP, assembly version
31660 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
31661 ADD #4,X \ X = BODY of SLEEP
31662 MOV X,-2(X) \ restore the default background
31665 \ restore default action of primary DEFERred word WARM, FORTH version
31666 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
31668 COLD \ because we want to reset CPU and interrupt vectors
31673 ; downloading RC5toLCD.4th is done
31674 RST_HERE ; this app is protected against <reset>
31682 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
31684 [DEFINED] ASM [IF] \ security test
31688 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
31690 CODE MAX \ n1 n2 -- n3 signed maximum
31691 CMP @PSP,TOS \ n2-n1
31692 S< ?GOTO FW1 \ n2<n1
31698 CODE MIN \ n1 n2 -- n3 signed minimum
31699 CMP @PSP,TOS \ n2-n1
31700 S< ?GOTO BW1 \ n2<n1
31708 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
31709 : U.R \ u n -- display u unsigned in n width (n >= 2)
31711 R> OVER - 0 MAX SPACES TYPE
31716 \ CODE 20_US \ n -- n * 20 us
31717 \ BEGIN \ 3 cycles loop + 6~
31718 \ \ MOV #5,W \ 3 MCLK = 1 MHz
31719 \ \ MOV #23,W \ 3 MCLK = 4 MHz
31720 \ \ MOV #51,W \ 3 MCLK = 8 MHz
31721 \ MOV #104,W \ 3 MCLK = 16 MHz
31722 \ \ MOV #158,W \ 3 MCLK = 24 MHz
31723 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
31728 \ MOV @PSP+,TOS \ 2
31733 CODE 20_US \ n -- n * 20 us
31734 BEGIN \ here we presume that LCD_TIM_IFG = 1...
31736 BIT #1,&LCD_TIM_CTL \ 3
31737 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
31738 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
31740 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
31746 CODE TOP_LCD \ LCD Sample
31747 \ \ if write : %xxxxWWWW --
31748 \ \ if read : -- %0000RRRR
31749 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
31750 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
31751 0= IF \ write LCD bits pattern
31752 AND.B #LCD_DB,TOS \
31753 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
31754 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
31757 THEN \ read LCD bits pattern
31760 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
31761 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
31762 AND.B #LCD_DB,TOS \
31767 CODE LCD_W \ byte -- write byte to LCD
31769 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
31770 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
31771 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
31772 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
31773 COLON \ high level word starts here
31774 TOP_LCD 2 20_US \ write high nibble first
31779 CODE LCD_WrC \ char -- Write Char
31780 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
31785 CODE LCD_WrF \ func -- Write Fonction
31786 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
31792 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
31797 $02 LCD_WrF 100 20_us
31801 [UNDEFINED] OR [IF]
31803 \ https://forth-standard.org/standard/core/OR
31804 \ C OR x1 x2 -- x3 logical OR
31813 : LCD_Entry_set $04 OR LCD_WrF ;
31815 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
31817 : LCD_DSP_Shift $10 OR LCD_WrF ;
31819 : LCD_Fn_Set $20 OR LCD_WrF ;
31821 : LCD_CGRAM_Set $40 OR LCD_WrF ;
31823 : LCD_Goto $80 OR LCD_WrF ;
31825 CODE LCD_R \ -- byte read byte from LCD
31826 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
31827 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
31828 COLON \ starts a FORTH word
31829 TOP_LCD 2 20_us \ -- %0000HHHH
31830 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
31831 HI2LO \ switch from FORTH to assembler
31832 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
31833 ADD.B @PSP+,TOS \ -- %HHHHLLLL
31834 MOV @RSP+,IP \ restore IP saved by COLON
31839 CODE LCD_RdS \ -- status Read Status
31840 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
31845 CODE LCD_RdC \ -- char Read Char
31846 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
31852 \ ******************************\
31853 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
31854 \ ******************************\
31855 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
31856 BIT.B #SW2,&SW2_IN \ test switch S2
31857 0= IF \ case of switch S2 pressed
31858 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
31860 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
31863 BIT.B #SW1,&SW1_IN \ test switch S1 input
31864 0= IF \ case of Switch S1 pressed
31865 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
31867 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
31871 BW1 \ from quit on truncated RC5 message
31872 BW2 \ from repeated RC5 command
31873 BW3 \ from end of RC5_INT
31874 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
31879 \ ******************************\
31880 ASM RC5_INT \ wake up on Px.RC5 change interrupt
31881 \ ******************************\
31882 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
31883 \ ******************************\
31884 \ \ in : SR(9)=old Toggle bit memory (ADD on)
31885 \ \ SMclock = 8|16|24 MHz
31886 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
31887 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
31888 \ \ SR(9)=new Toggle bit memory (ADD on)
31889 \ ******************************\
31890 \ RC5_FirstStartBitHalfCycle: \
31891 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
31892 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
31893 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
31894 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
31895 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
31896 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
31897 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
31898 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
31899 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
31900 MOV #1778,X \ RC5_Period * 1us
31901 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
31902 MOV #14,W \ count of loop
31904 \ ******************************\
31905 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
31906 \ ******************************\ |
31907 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
31908 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
31909 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
31910 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
31911 \ RC5_Compute_3/4_Period: \ |
31912 RRUM #1,X \ X=1/2 cycle |
31915 ADD X,Y \ Y=3/4 cycle
31916 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
31918 \ ******************************\
31919 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
31920 \ ******************************\
31921 BIT.B #RC5,&IR_IN \ C_flag = IR bit
31922 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
31923 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
31924 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
31925 SUB #1,W \ decrement count loop
31926 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
31927 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
31928 0<> WHILE \ ----> out of loop ----+
31929 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
31931 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
31932 CMP Y,X \ 1 | cycle time out of bound ?
31933 U>= IF \ 2 ^ | yes:
31934 BIC #$30,&RC5_TIM_CTL \ | | stop timer
31935 GOTO BW1 \ | | quit on truncated RC5 message
31937 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
31939 REPEAT \ ----> loop back --+ | with X = new RC5_period value
31940 \ ******************************\ |
31941 \ RC5_SampleEndOf: \ <---------------------+
31942 \ ******************************\
31943 BIC #$30,&RC5_TIM_CTL \ stop timer
31944 \ ******************************\
31945 \ RC5_ComputeNewRC5word \
31946 \ ******************************\
31947 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
31948 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
31949 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
31950 \ ******************************\
31951 \ RC5_ComputeC6bit \
31952 \ ******************************\
31953 BIT #BIT14,T \ test /C6 bit in T
31954 0= IF BIS #BIT6,X \ set C6 bit in X
31955 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
31956 \ ******************************\
31957 \ RC5_CommandByteIsDone \ -- BASE RC5_code
31958 \ ******************************\
31959 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
31960 \ ******************************\
31961 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
31962 XOR @RSP,T \ (new XOR old) Toggle bits
31963 BIT #UF10,T \ repeated RC5_command ?
31964 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
31965 XOR #UF10,0(RSP) \ 5 toggle bit memory
31966 \ ******************************\
31967 \ Display IR_RC5 code \ X = RC5 code
31968 \ ******************************\
31970 MOV &BASE,2(PSP) \ save current base
31971 MOV #$10,&BASE \ set hex base
31972 MOV TOS,0(PSP) \ save TOS
31974 LO2HI \ switch from assembler to FORTH
31975 ['] LCD_CLEAR IS CR \ redirects CR
31976 ['] LCD_WrC IS EMIT \ redirects EMIT
31977 CR ." $" 2 U.R \ print IR_RC5 code
31978 ['] CR >BODY IS CR \ restore CR
31979 ['] EMIT >BODY IS EMIT \ restore EMIT
31980 HI2LO \ switch from FORTH to assembler
31981 MOV TOS,&BASE \ restore current BASE
31983 \ ******************************\
31985 \ ******************************\
31989 \ ------------------------------\
31991 \ ------------------------------\
31992 \ ... \ insert here your background task
31995 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
31996 ADD #4,X \ 1 X = BODY of SLEEP
31999 \ ------------------------------\
32003 \ ------------------------------\
32004 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
32005 \ - - \CNTL Counter lentgh \ 00 = 16 bits
32006 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
32007 \ -- \ID input divider \ 10 = /4
32008 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
32009 \ - \TBCLR TimerB Clear
32012 \ -------------------------------\
32013 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
32014 \ -- \CM Capture Mode
32019 \ --- \OUTMOD \ 011 = set/reset
32025 \ -------------------------------\
32027 \ -------------------------------\
32029 \ ------------------------------\
32030 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
32031 \ ------------------------------\
32032 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
32033 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
32034 \ ------------------------------\
32035 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
32036 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
32037 \ ------------------------------\
32038 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
32039 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
32040 \ ------------------------------\
32041 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
32042 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
32043 \ ------------------------------\
32044 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
32045 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
32046 \ ------------------------------\
32047 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
32048 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
32049 \ ------------------------------\
32050 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
32051 \ ------------------------------\
32052 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
32053 \ ------------------------------\
32054 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
32055 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
32056 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
32057 \ ------------------------------\
32058 BIS.B #LCDVo,&LCDVo_DIR \
32059 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
32060 \ ------------------------------\
32061 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
32062 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
32063 \ ------------------------------\
32064 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
32065 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
32066 \ ******************************\
32068 \ ******************************\
32069 BIS.B #RC5,&IR_IE \ enable RC5_Int
32070 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
32071 MOV #RC5_INT,&IR_Vec \ init interrupt vector
32072 \ ******************************\
32073 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
32074 \ ******************************\
32075 \ %01 0001 0100 \ TAxCTL
32076 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
32077 \ -- \ ID divided by 1
32078 \ -- \ MC MODE = up to TAxCCRn
32079 \ - \ TACLR clear timer count
32082 \ ------------------------------\
32083 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
32084 \ ------------------------------\
32086 \ --- \ TAIDEX pre divisor
32087 \ ------------------------------\
32088 \ %0000 0000 0000 0101 \ TAxCCR0
32089 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
32090 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
32091 \ ------------------------------\
32092 \ %0000 0000 0001 0000 \ TAxCCTL0
32093 \ - \ CAP capture/compare mode = compare
32096 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
32097 \ ------------------------------\
32098 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
32099 \ ------------------------------\
32100 \ define LPM mode for ACCEPT \
32101 \ ------------------------------\
32102 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
32103 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
32104 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
32106 \ ------------------------------\
32107 \ redirects to background task \
32108 \ ------------------------------\
32110 MOV #BACKGROUND,2(X) \
32111 \ ------------------------------\
32113 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
32115 \ ------------------------------\
32117 \ ------------------------------\
32118 $03E8 20_US \ 1- wait 20 ms
32119 $03 TOP_LCD \ 2- send DB5=DB4=1
32120 $CD 20_US \ 3- wait 4,1 ms
32121 $03 TOP_LCD \ 4- send again DB5=DB4=1
32122 $5 20_US \ 5- wait 0,1 ms
32123 $03 TOP_LCD \ 6- send again again DB5=DB4=1
32124 $2 20_US \ wait 40 us = LCD cycle
32125 $02 TOP_LCD \ 7- send DB5=1 DB4=0
32126 $2 20_US \ wait 40 us = LCD cycle
32127 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
32128 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
32129 LCD_Clear \ 10- "LCD_Clear"
32130 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
32131 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
32132 LCD_Clear \ 10- "LCD_Clear"
32133 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
32134 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
32136 ['] CR >BODY IS CR \
32137 ['] EMIT >BODY IS EMIT \
32138 ." RC5toLCD is running. Type STOP to quit"
32139 LIT RECURSE IS WARM \ replace WARM by this START routine
32140 ABORT \ and continue with the next word after WARM...
32141 ; \ ...until interpreter falls in sleep mode within ACCEPT.
32144 CODE STOP \ stops multitasking, must to be used before downloading app
32145 \ restore default action of primary DEFERred word SLEEP, assembly version
32146 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
32147 ADD #4,X \ X = BODY of SLEEP
32148 MOV X,-2(X) \ restore the default background
32151 \ restore default action of primary DEFERred word WARM, FORTH version
32152 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
32154 COLD \ because we want to reset CPU and interrupt vectors
32159 ; downloading RC5toLCD.4th is done
32160 RST_HERE ; this app is protected against <reset>
32168 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
32170 [DEFINED] ASM [IF] \ security test
32174 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
32176 CODE MAX \ n1 n2 -- n3 signed maximum
32177 CMP @PSP,TOS \ n2-n1
32178 S< ?GOTO FW1 \ n2<n1
32184 CODE MIN \ n1 n2 -- n3 signed minimum
32185 CMP @PSP,TOS \ n2-n1
32186 S< ?GOTO BW1 \ n2<n1
32194 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
32195 : U.R \ u n -- display u unsigned in n width (n >= 2)
32197 R> OVER - 0 MAX SPACES TYPE
32202 \ CODE 20_US \ n -- n * 20 us
32203 \ BEGIN \ 3 cycles loop + 6~
32204 \ \ MOV #5,W \ 3 MCLK = 1 MHz
32205 \ \ MOV #23,W \ 3 MCLK = 4 MHz
32206 \ \ MOV #51,W \ 3 MCLK = 8 MHz
32207 \ MOV #104,W \ 3 MCLK = 16 MHz
32208 \ \ MOV #158,W \ 3 MCLK = 24 MHz
32209 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
32214 \ MOV @PSP+,TOS \ 2
32219 CODE 20_US \ n -- n * 20 us
32220 BEGIN \ here we presume that LCD_TIM_IFG = 1...
32222 BIT #1,&LCD_TIM_CTL \ 3
32223 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
32224 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
32226 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
32232 CODE TOP_LCD \ LCD Sample
32233 \ \ if write : %xxxxWWWW --
32234 \ \ if read : -- %0000RRRR
32235 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
32236 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
32237 0= IF \ write LCD bits pattern
32238 AND.B #LCD_DB,TOS \
32239 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
32240 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
32243 THEN \ read LCD bits pattern
32246 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
32247 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
32248 AND.B #LCD_DB,TOS \
32253 CODE LCD_W \ byte -- write byte to LCD
32255 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
32256 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
32257 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
32258 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
32259 COLON \ high level word starts here
32260 TOP_LCD 2 20_US \ write high nibble first
32265 CODE LCD_WrC \ char -- Write Char
32266 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
32271 CODE LCD_WrF \ func -- Write Fonction
32272 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
32278 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
32283 $02 LCD_WrF 100 20_us
32287 [UNDEFINED] OR [IF]
32289 \ https://forth-standard.org/standard/core/OR
32290 \ C OR x1 x2 -- x3 logical OR
32299 : LCD_Entry_set $04 OR LCD_WrF ;
32301 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
32303 : LCD_DSP_Shift $10 OR LCD_WrF ;
32305 : LCD_Fn_Set $20 OR LCD_WrF ;
32307 : LCD_CGRAM_Set $40 OR LCD_WrF ;
32309 : LCD_Goto $80 OR LCD_WrF ;
32311 CODE LCD_R \ -- byte read byte from LCD
32312 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
32313 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
32314 COLON \ starts a FORTH word
32315 TOP_LCD 2 20_us \ -- %0000HHHH
32316 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
32317 HI2LO \ switch from FORTH to assembler
32318 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
32319 ADD.B @PSP+,TOS \ -- %HHHHLLLL
32320 MOV @RSP+,IP \ restore IP saved by COLON
32325 CODE LCD_RdS \ -- status Read Status
32326 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
32331 CODE LCD_RdC \ -- char Read Char
32332 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
32338 \ ******************************\
32339 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
32340 \ ******************************\
32341 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
32342 BIT.B #SW2,&SW2_IN \ test switch S2
32343 0= IF \ case of switch S2 pressed
32344 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
32346 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
32349 BIT.B #SW1,&SW1_IN \ test switch S1 input
32350 0= IF \ case of Switch S1 pressed
32351 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
32353 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
32357 BW1 \ from quit on truncated RC5 message
32358 BW2 \ from repeated RC5 command
32359 BW3 \ from end of RC5_INT
32360 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
32365 \ ******************************\
32366 ASM RC5_INT \ wake up on Px.RC5 change interrupt
32367 \ ******************************\
32368 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
32369 \ ******************************\
32370 \ \ in : SR(9)=old Toggle bit memory (ADD on)
32371 \ \ SMclock = 8|16|24 MHz
32372 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
32373 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
32374 \ \ SR(9)=new Toggle bit memory (ADD on)
32375 \ ******************************\
32376 \ RC5_FirstStartBitHalfCycle: \
32377 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
32378 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
32379 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
32380 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
32381 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
32382 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
32383 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
32384 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
32385 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
32386 MOV #1778,X \ RC5_Period * 1us
32387 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
32388 MOV #14,W \ count of loop
32390 \ ******************************\
32391 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
32392 \ ******************************\ |
32393 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
32394 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
32395 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
32396 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
32397 \ RC5_Compute_3/4_Period: \ |
32398 RRUM #1,X \ X=1/2 cycle |
32401 ADD X,Y \ Y=3/4 cycle
32402 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
32404 \ ******************************\
32405 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
32406 \ ******************************\
32407 BIT.B #RC5,&IR_IN \ C_flag = IR bit
32408 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
32409 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
32410 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
32411 SUB #1,W \ decrement count loop
32412 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
32413 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
32414 0<> WHILE \ ----> out of loop ----+
32415 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
32417 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
32418 CMP Y,X \ 1 | cycle time out of bound ?
32419 U>= IF \ 2 ^ | yes:
32420 BIC #$30,&RC5_TIM_CTL \ | | stop timer
32421 GOTO BW1 \ | | quit on truncated RC5 message
32423 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
32425 REPEAT \ ----> loop back --+ | with X = new RC5_period value
32426 \ ******************************\ |
32427 \ RC5_SampleEndOf: \ <---------------------+
32428 \ ******************************\
32429 BIC #$30,&RC5_TIM_CTL \ stop timer
32430 \ ******************************\
32431 \ RC5_ComputeNewRC5word \
32432 \ ******************************\
32433 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
32434 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
32435 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
32436 \ ******************************\
32437 \ RC5_ComputeC6bit \
32438 \ ******************************\
32439 BIT #BIT14,T \ test /C6 bit in T
32440 0= IF BIS #BIT6,X \ set C6 bit in X
32441 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
32442 \ ******************************\
32443 \ RC5_CommandByteIsDone \ -- BASE RC5_code
32444 \ ******************************\
32445 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
32446 \ ******************************\
32447 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
32448 XOR @RSP,T \ (new XOR old) Toggle bits
32449 BIT #UF10,T \ repeated RC5_command ?
32450 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
32451 XOR #UF10,0(RSP) \ 5 toggle bit memory
32452 \ ******************************\
32453 \ Display IR_RC5 code \ X = RC5 code
32454 \ ******************************\
32456 MOV &BASE,2(PSP) \ save current base
32457 MOV #$10,&BASE \ set hex base
32458 MOV TOS,0(PSP) \ save TOS
32460 LO2HI \ switch from assembler to FORTH
32461 ['] LCD_CLEAR IS CR \ redirects CR
32462 ['] LCD_WrC IS EMIT \ redirects EMIT
32463 CR ." $" 2 U.R \ print IR_RC5 code
32464 ['] CR >BODY IS CR \ restore CR
32465 ['] EMIT >BODY IS EMIT \ restore EMIT
32466 HI2LO \ switch from FORTH to assembler
32467 MOV TOS,&BASE \ restore current BASE
32469 \ ******************************\
32471 \ ******************************\
32475 \ ------------------------------\
32477 \ ------------------------------\
32478 \ ... \ insert here your background task
32481 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
32482 ADD #4,X \ 1 X = BODY of SLEEP
32485 \ ------------------------------\
32489 \ ------------------------------\
32490 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
32491 \ - - \CNTL Counter lentgh \ 00 = 16 bits
32492 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
32493 \ -- \ID input divider \ 10 = /4
32494 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
32495 \ - \TBCLR TimerB Clear
32498 \ -------------------------------\
32499 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
32500 \ -- \CM Capture Mode
32505 \ --- \OUTMOD \ 011 = set/reset
32511 \ -------------------------------\
32513 \ -------------------------------\
32515 \ ------------------------------\
32516 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
32517 \ ------------------------------\
32518 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
32519 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
32520 \ ------------------------------\
32521 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
32522 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
32523 \ ------------------------------\
32524 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
32525 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
32526 \ ------------------------------\
32527 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
32528 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
32529 \ ------------------------------\
32530 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
32531 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
32532 \ ------------------------------\
32533 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
32534 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
32535 \ ------------------------------\
32536 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
32537 \ ------------------------------\
32538 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
32539 \ ------------------------------\
32540 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
32541 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
32542 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
32543 \ ------------------------------\
32544 BIS.B #LCDVo,&LCDVo_DIR \
32545 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
32546 \ ------------------------------\
32547 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
32548 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
32549 \ ------------------------------\
32550 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
32551 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
32552 \ ******************************\
32554 \ ******************************\
32555 BIS.B #RC5,&IR_IE \ enable RC5_Int
32556 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
32557 MOV #RC5_INT,&IR_Vec \ init interrupt vector
32558 \ ******************************\
32559 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
32560 \ ******************************\
32561 \ %01 0001 0100 \ TAxCTL
32562 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
32563 \ -- \ ID divided by 1
32564 \ -- \ MC MODE = up to TAxCCRn
32565 \ - \ TACLR clear timer count
32568 \ ------------------------------\
32569 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
32570 \ ------------------------------\
32572 \ --- \ TAIDEX pre divisor
32573 \ ------------------------------\
32574 \ %0000 0000 0000 0101 \ TAxCCR0
32575 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
32576 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
32577 \ ------------------------------\
32578 \ %0000 0000 0001 0000 \ TAxCCTL0
32579 \ - \ CAP capture/compare mode = compare
32582 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
32583 \ ------------------------------\
32584 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
32585 \ ------------------------------\
32586 \ define LPM mode for ACCEPT \
32587 \ ------------------------------\
32588 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
32589 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
32590 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
32592 \ ------------------------------\
32593 \ redirects to background task \
32594 \ ------------------------------\
32596 MOV #BACKGROUND,2(X) \
32597 \ ------------------------------\
32599 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
32601 \ ------------------------------\
32603 \ ------------------------------\
32604 $03E8 20_US \ 1- wait 20 ms
32605 $03 TOP_LCD \ 2- send DB5=DB4=1
32606 $CD 20_US \ 3- wait 4,1 ms
32607 $03 TOP_LCD \ 4- send again DB5=DB4=1
32608 $5 20_US \ 5- wait 0,1 ms
32609 $03 TOP_LCD \ 6- send again again DB5=DB4=1
32610 $2 20_US \ wait 40 us = LCD cycle
32611 $02 TOP_LCD \ 7- send DB5=1 DB4=0
32612 $2 20_US \ wait 40 us = LCD cycle
32613 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
32614 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
32615 LCD_Clear \ 10- "LCD_Clear"
32616 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
32617 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
32618 LCD_Clear \ 10- "LCD_Clear"
32619 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
32620 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
32622 ['] CR >BODY IS CR \
32623 ['] EMIT >BODY IS EMIT \
32624 ." RC5toLCD is running. Type STOP to quit"
32625 LIT RECURSE IS WARM \ replace WARM by this START routine
32626 ABORT \ and continue with the next word after WARM...
32627 ; \ ...until interpreter falls in sleep mode within ACCEPT.
32630 CODE STOP \ stops multitasking, must to be used before downloading app
32631 \ restore default action of primary DEFERred word SLEEP, assembly version
32632 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
32633 ADD #4,X \ X = BODY of SLEEP
32634 MOV X,-2(X) \ restore the default background
32637 \ restore default action of primary DEFERred word WARM, FORTH version
32638 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
32640 COLD \ because we want to reset CPU and interrupt vectors
32645 ; downloading RC5toLCD.4th is done
32646 RST_HERE ; this app is protected against <reset>
32654 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
32656 [DEFINED] ASM [IF] \ security test
32660 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
32662 CODE MAX \ n1 n2 -- n3 signed maximum
32663 CMP @PSP,TOS \ n2-n1
32664 S< ?GOTO FW1 \ n2<n1
32670 CODE MIN \ n1 n2 -- n3 signed minimum
32671 CMP @PSP,TOS \ n2-n1
32672 S< ?GOTO BW1 \ n2<n1
32680 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
32681 : U.R \ u n -- display u unsigned in n width (n >= 2)
32683 R> OVER - 0 MAX SPACES TYPE
32688 \ CODE 20_US \ n -- n * 20 us
32689 \ BEGIN \ 3 cycles loop + 6~
32690 \ \ MOV #5,W \ 3 MCLK = 1 MHz
32691 \ \ MOV #23,W \ 3 MCLK = 4 MHz
32692 \ \ MOV #51,W \ 3 MCLK = 8 MHz
32693 \ MOV #104,W \ 3 MCLK = 16 MHz
32694 \ \ MOV #158,W \ 3 MCLK = 24 MHz
32695 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
32700 \ MOV @PSP+,TOS \ 2
32705 CODE 20_US \ n -- n * 20 us
32706 BEGIN \ here we presume that LCD_TIM_IFG = 1...
32708 BIT #1,&LCD_TIM_CTL \ 3
32709 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
32710 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
32712 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
32718 CODE TOP_LCD \ LCD Sample
32719 \ \ if write : %xxxxWWWW --
32720 \ \ if read : -- %0000RRRR
32721 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
32722 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
32723 0= IF \ write LCD bits pattern
32724 AND.B #LCD_DB,TOS \
32725 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
32726 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
32729 THEN \ read LCD bits pattern
32732 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
32733 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
32734 AND.B #LCD_DB,TOS \
32739 CODE LCD_W \ byte -- write byte to LCD
32741 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
32742 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
32743 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
32744 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
32745 COLON \ high level word starts here
32746 TOP_LCD 2 20_US \ write high nibble first
32751 CODE LCD_WrC \ char -- Write Char
32752 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
32757 CODE LCD_WrF \ func -- Write Fonction
32758 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
32764 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
32769 $02 LCD_WrF 100 20_us
32773 [UNDEFINED] OR [IF]
32775 \ https://forth-standard.org/standard/core/OR
32776 \ C OR x1 x2 -- x3 logical OR
32785 : LCD_Entry_set $04 OR LCD_WrF ;
32787 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
32789 : LCD_DSP_Shift $10 OR LCD_WrF ;
32791 : LCD_Fn_Set $20 OR LCD_WrF ;
32793 : LCD_CGRAM_Set $40 OR LCD_WrF ;
32795 : LCD_Goto $80 OR LCD_WrF ;
32797 CODE LCD_R \ -- byte read byte from LCD
32798 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
32799 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
32800 COLON \ starts a FORTH word
32801 TOP_LCD 2 20_us \ -- %0000HHHH
32802 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
32803 HI2LO \ switch from FORTH to assembler
32804 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
32805 ADD.B @PSP+,TOS \ -- %HHHHLLLL
32806 MOV @RSP+,IP \ restore IP saved by COLON
32811 CODE LCD_RdS \ -- status Read Status
32812 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
32817 CODE LCD_RdC \ -- char Read Char
32818 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
32824 \ ******************************\
32825 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
32826 \ ******************************\
32827 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
32828 BIT.B #SW2,&SW2_IN \ test switch S2
32829 0= IF \ case of switch S2 pressed
32830 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
32832 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
32835 BIT.B #SW1,&SW1_IN \ test switch S1 input
32836 0= IF \ case of Switch S1 pressed
32837 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
32839 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
32843 BW1 \ from quit on truncated RC5 message
32844 BW2 \ from repeated RC5 command
32845 BW3 \ from end of RC5_INT
32846 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
32851 \ ******************************\
32852 ASM RC5_INT \ wake up on Px.RC5 change interrupt
32853 \ ******************************\
32854 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
32855 \ ******************************\
32856 \ \ in : SR(9)=old Toggle bit memory (ADD on)
32857 \ \ SMclock = 8|16|24 MHz
32858 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
32859 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
32860 \ \ SR(9)=new Toggle bit memory (ADD on)
32861 \ ******************************\
32862 \ RC5_FirstStartBitHalfCycle: \
32863 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
32864 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
32865 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
32866 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
32867 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
32868 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
32869 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
32870 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
32871 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
32872 MOV #1778,X \ RC5_Period * 1us
32873 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
32874 MOV #14,W \ count of loop
32876 \ ******************************\
32877 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
32878 \ ******************************\ |
32879 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
32880 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
32881 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
32882 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
32883 \ RC5_Compute_3/4_Period: \ |
32884 RRUM #1,X \ X=1/2 cycle |
32887 ADD X,Y \ Y=3/4 cycle
32888 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
32890 \ ******************************\
32891 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
32892 \ ******************************\
32893 BIT.B #RC5,&IR_IN \ C_flag = IR bit
32894 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
32895 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
32896 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
32897 SUB #1,W \ decrement count loop
32898 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
32899 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
32900 0<> WHILE \ ----> out of loop ----+
32901 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
32903 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
32904 CMP Y,X \ 1 | cycle time out of bound ?
32905 U>= IF \ 2 ^ | yes:
32906 BIC #$30,&RC5_TIM_CTL \ | | stop timer
32907 GOTO BW1 \ | | quit on truncated RC5 message
32909 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
32911 REPEAT \ ----> loop back --+ | with X = new RC5_period value
32912 \ ******************************\ |
32913 \ RC5_SampleEndOf: \ <---------------------+
32914 \ ******************************\
32915 BIC #$30,&RC5_TIM_CTL \ stop timer
32916 \ ******************************\
32917 \ RC5_ComputeNewRC5word \
32918 \ ******************************\
32919 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
32920 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
32921 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
32922 \ ******************************\
32923 \ RC5_ComputeC6bit \
32924 \ ******************************\
32925 BIT #BIT14,T \ test /C6 bit in T
32926 0= IF BIS #BIT6,X \ set C6 bit in X
32927 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
32928 \ ******************************\
32929 \ RC5_CommandByteIsDone \ -- BASE RC5_code
32930 \ ******************************\
32931 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
32932 \ ******************************\
32933 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
32934 XOR @RSP,T \ (new XOR old) Toggle bits
32935 BIT #UF10,T \ repeated RC5_command ?
32936 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
32937 XOR #UF10,0(RSP) \ 5 toggle bit memory
32938 \ ******************************\
32939 \ Display IR_RC5 code \ X = RC5 code
32940 \ ******************************\
32942 MOV &BASE,2(PSP) \ save current base
32943 MOV #$10,&BASE \ set hex base
32944 MOV TOS,0(PSP) \ save TOS
32946 LO2HI \ switch from assembler to FORTH
32947 ['] LCD_CLEAR IS CR \ redirects CR
32948 ['] LCD_WrC IS EMIT \ redirects EMIT
32949 CR ." $" 2 U.R \ print IR_RC5 code
32950 ['] CR >BODY IS CR \ restore CR
32951 ['] EMIT >BODY IS EMIT \ restore EMIT
32952 HI2LO \ switch from FORTH to assembler
32953 MOV TOS,&BASE \ restore current BASE
32955 \ ******************************\
32957 \ ******************************\
32961 \ ------------------------------\
32963 \ ------------------------------\
32964 \ ... \ insert here your background task
32967 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
32968 ADD #4,X \ 1 X = BODY of SLEEP
32971 \ ------------------------------\
32975 \ ------------------------------\
32976 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
32977 \ - - \CNTL Counter lentgh \ 00 = 16 bits
32978 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
32979 \ -- \ID input divider \ 10 = /4
32980 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
32981 \ - \TBCLR TimerB Clear
32984 \ -------------------------------\
32985 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
32986 \ -- \CM Capture Mode
32991 \ --- \OUTMOD \ 011 = set/reset
32997 \ -------------------------------\
32999 \ -------------------------------\
33001 \ ------------------------------\
33002 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
33003 \ ------------------------------\
33004 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
33005 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
33006 \ ------------------------------\
33007 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
33008 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
33009 \ ------------------------------\
33010 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
33011 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
33012 \ ------------------------------\
33013 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
33014 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
33015 \ ------------------------------\
33016 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
33017 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
33018 \ ------------------------------\
33019 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
33020 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
33021 \ ------------------------------\
33022 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
33023 \ ------------------------------\
33024 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
33025 \ ------------------------------\
33026 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
33027 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
33028 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
33029 \ ------------------------------\
33030 BIS.B #LCDVo,&LCDVo_DIR \
33031 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
33032 \ ------------------------------\
33033 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
33034 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
33035 \ ------------------------------\
33036 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
33037 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
33038 \ ******************************\
33040 \ ******************************\
33041 BIS.B #RC5,&IR_IE \ enable RC5_Int
33042 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
33043 MOV #RC5_INT,&IR_Vec \ init interrupt vector
33044 \ ******************************\
33045 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
33046 \ ******************************\
33047 \ %01 0001 0100 \ TAxCTL
33048 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
33049 \ -- \ ID divided by 1
33050 \ -- \ MC MODE = up to TAxCCRn
33051 \ - \ TACLR clear timer count
33054 \ ------------------------------\
33055 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
33056 \ ------------------------------\
33058 \ --- \ TAIDEX pre divisor
33059 \ ------------------------------\
33060 \ %0000 0000 0000 0101 \ TAxCCR0
33061 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
33062 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
33063 \ ------------------------------\
33064 \ %0000 0000 0001 0000 \ TAxCCTL0
33065 \ - \ CAP capture/compare mode = compare
33068 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
33069 \ ------------------------------\
33070 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
33071 \ ------------------------------\
33072 \ define LPM mode for ACCEPT \
33073 \ ------------------------------\
33074 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
33075 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
33076 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
33078 \ ------------------------------\
33079 \ redirects to background task \
33080 \ ------------------------------\
33082 MOV #BACKGROUND,2(X) \
33083 \ ------------------------------\
33085 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
33087 \ ------------------------------\
33089 \ ------------------------------\
33090 $03E8 20_US \ 1- wait 20 ms
33091 $03 TOP_LCD \ 2- send DB5=DB4=1
33092 $CD 20_US \ 3- wait 4,1 ms
33093 $03 TOP_LCD \ 4- send again DB5=DB4=1
33094 $5 20_US \ 5- wait 0,1 ms
33095 $03 TOP_LCD \ 6- send again again DB5=DB4=1
33096 $2 20_US \ wait 40 us = LCD cycle
33097 $02 TOP_LCD \ 7- send DB5=1 DB4=0
33098 $2 20_US \ wait 40 us = LCD cycle
33099 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
33100 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
33101 LCD_Clear \ 10- "LCD_Clear"
33102 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
33103 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
33104 LCD_Clear \ 10- "LCD_Clear"
33105 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
33106 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
33108 ['] CR >BODY IS CR \
33109 ['] EMIT >BODY IS EMIT \
33110 ." RC5toLCD is running. Type STOP to quit"
33111 LIT RECURSE IS WARM \ replace WARM by this START routine
33112 ABORT \ and continue with the next word after WARM...
33113 ; \ ...until interpreter falls in sleep mode within ACCEPT.
33116 CODE STOP \ stops multitasking, must to be used before downloading app
33117 \ restore default action of primary DEFERred word SLEEP, assembly version
33118 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
33119 ADD #4,X \ X = BODY of SLEEP
33120 MOV X,-2(X) \ restore the default background
33123 \ restore default action of primary DEFERred word WARM, FORTH version
33124 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
33126 COLD \ because we want to reset CPU and interrupt vectors
33131 ; downloading RC5toLCD.4th is done
33132 RST_HERE ; this app is protected against <reset>
33140 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
33142 [DEFINED] ASM [IF] \ security test
33146 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
33148 CODE MAX \ n1 n2 -- n3 signed maximum
33149 CMP @PSP,TOS \ n2-n1
33150 S< ?GOTO FW1 \ n2<n1
33156 CODE MIN \ n1 n2 -- n3 signed minimum
33157 CMP @PSP,TOS \ n2-n1
33158 S< ?GOTO BW1 \ n2<n1
33166 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
33167 : U.R \ u n -- display u unsigned in n width (n >= 2)
33169 R> OVER - 0 MAX SPACES TYPE
33174 \ CODE 20_US \ n -- n * 20 us
33175 \ BEGIN \ 3 cycles loop + 6~
33176 \ \ MOV #5,W \ 3 MCLK = 1 MHz
33177 \ \ MOV #23,W \ 3 MCLK = 4 MHz
33178 \ \ MOV #51,W \ 3 MCLK = 8 MHz
33179 \ MOV #104,W \ 3 MCLK = 16 MHz
33180 \ \ MOV #158,W \ 3 MCLK = 24 MHz
33181 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
33186 \ MOV @PSP+,TOS \ 2
33191 CODE 20_US \ n -- n * 20 us
33192 BEGIN \ here we presume that LCD_TIM_IFG = 1...
33194 BIT #1,&LCD_TIM_CTL \ 3
33195 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
33196 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
33198 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
33204 CODE TOP_LCD \ LCD Sample
33205 \ \ if write : %xxxxWWWW --
33206 \ \ if read : -- %0000RRRR
33207 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
33208 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
33209 0= IF \ write LCD bits pattern
33210 AND.B #LCD_DB,TOS \
33211 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
33212 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
33215 THEN \ read LCD bits pattern
33218 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
33219 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
33220 AND.B #LCD_DB,TOS \
33225 CODE LCD_W \ byte -- write byte to LCD
33227 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
33228 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
33229 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
33230 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
33231 COLON \ high level word starts here
33232 TOP_LCD 2 20_US \ write high nibble first
33237 CODE LCD_WrC \ char -- Write Char
33238 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
33243 CODE LCD_WrF \ func -- Write Fonction
33244 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
33250 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
33255 $02 LCD_WrF 100 20_us
33259 [UNDEFINED] OR [IF]
33261 \ https://forth-standard.org/standard/core/OR
33262 \ C OR x1 x2 -- x3 logical OR
33271 : LCD_Entry_set $04 OR LCD_WrF ;
33273 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
33275 : LCD_DSP_Shift $10 OR LCD_WrF ;
33277 : LCD_Fn_Set $20 OR LCD_WrF ;
33279 : LCD_CGRAM_Set $40 OR LCD_WrF ;
33281 : LCD_Goto $80 OR LCD_WrF ;
33283 CODE LCD_R \ -- byte read byte from LCD
33284 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
33285 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
33286 COLON \ starts a FORTH word
33287 TOP_LCD 2 20_us \ -- %0000HHHH
33288 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
33289 HI2LO \ switch from FORTH to assembler
33290 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
33291 ADD.B @PSP+,TOS \ -- %HHHHLLLL
33292 MOV @RSP+,IP \ restore IP saved by COLON
33297 CODE LCD_RdS \ -- status Read Status
33298 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
33303 CODE LCD_RdC \ -- char Read Char
33304 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
33310 \ ******************************\
33311 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
33312 \ ******************************\
33313 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
33314 BIT.B #SW2,&SW2_IN \ test switch S2
33315 0= IF \ case of switch S2 pressed
33316 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
33318 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
33321 BIT.B #SW1,&SW1_IN \ test switch S1 input
33322 0= IF \ case of Switch S1 pressed
33323 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
33325 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
33329 BW1 \ from quit on truncated RC5 message
33330 BW2 \ from repeated RC5 command
33331 BW3 \ from end of RC5_INT
33332 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
33337 \ ******************************\
33338 ASM RC5_INT \ wake up on Px.RC5 change interrupt
33339 \ ******************************\
33340 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
33341 \ ******************************\
33342 \ \ in : SR(9)=old Toggle bit memory (ADD on)
33343 \ \ SMclock = 8|16|24 MHz
33344 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
33345 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
33346 \ \ SR(9)=new Toggle bit memory (ADD on)
33347 \ ******************************\
33348 \ RC5_FirstStartBitHalfCycle: \
33349 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
33350 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
33351 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
33352 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
33353 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
33354 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
33355 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
33356 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
33357 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
33358 MOV #1778,X \ RC5_Period * 1us
33359 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
33360 MOV #14,W \ count of loop
33362 \ ******************************\
33363 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
33364 \ ******************************\ |
33365 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
33366 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
33367 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
33368 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
33369 \ RC5_Compute_3/4_Period: \ |
33370 RRUM #1,X \ X=1/2 cycle |
33373 ADD X,Y \ Y=3/4 cycle
33374 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
33376 \ ******************************\
33377 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
33378 \ ******************************\
33379 BIT.B #RC5,&IR_IN \ C_flag = IR bit
33380 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
33381 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
33382 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
33383 SUB #1,W \ decrement count loop
33384 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
33385 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
33386 0<> WHILE \ ----> out of loop ----+
33387 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
33389 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
33390 CMP Y,X \ 1 | cycle time out of bound ?
33391 U>= IF \ 2 ^ | yes:
33392 BIC #$30,&RC5_TIM_CTL \ | | stop timer
33393 GOTO BW1 \ | | quit on truncated RC5 message
33395 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
33397 REPEAT \ ----> loop back --+ | with X = new RC5_period value
33398 \ ******************************\ |
33399 \ RC5_SampleEndOf: \ <---------------------+
33400 \ ******************************\
33401 BIC #$30,&RC5_TIM_CTL \ stop timer
33402 \ ******************************\
33403 \ RC5_ComputeNewRC5word \
33404 \ ******************************\
33405 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
33406 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
33407 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
33408 \ ******************************\
33409 \ RC5_ComputeC6bit \
33410 \ ******************************\
33411 BIT #BIT14,T \ test /C6 bit in T
33412 0= IF BIS #BIT6,X \ set C6 bit in X
33413 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
33414 \ ******************************\
33415 \ RC5_CommandByteIsDone \ -- BASE RC5_code
33416 \ ******************************\
33417 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
33418 \ ******************************\
33419 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
33420 XOR @RSP,T \ (new XOR old) Toggle bits
33421 BIT #UF10,T \ repeated RC5_command ?
33422 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
33423 XOR #UF10,0(RSP) \ 5 toggle bit memory
33424 \ ******************************\
33425 \ Display IR_RC5 code \ X = RC5 code
33426 \ ******************************\
33428 MOV &BASE,2(PSP) \ save current base
33429 MOV #$10,&BASE \ set hex base
33430 MOV TOS,0(PSP) \ save TOS
33432 LO2HI \ switch from assembler to FORTH
33433 ['] LCD_CLEAR IS CR \ redirects CR
33434 ['] LCD_WrC IS EMIT \ redirects EMIT
33435 CR ." $" 2 U.R \ print IR_RC5 code
33436 ['] CR >BODY IS CR \ restore CR
33437 ['] EMIT >BODY IS EMIT \ restore EMIT
33438 HI2LO \ switch from FORTH to assembler
33439 MOV TOS,&BASE \ restore current BASE
33441 \ ******************************\
33443 \ ******************************\
33447 \ ------------------------------\
33449 \ ------------------------------\
33450 \ ... \ insert here your background task
33453 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
33454 ADD #4,X \ 1 X = BODY of SLEEP
33457 \ ------------------------------\
33461 \ ------------------------------\
33462 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
33463 \ - - \CNTL Counter lentgh \ 00 = 16 bits
33464 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
33465 \ -- \ID input divider \ 10 = /4
33466 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
33467 \ - \TBCLR TimerB Clear
33470 \ -------------------------------\
33471 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
33472 \ -- \CM Capture Mode
33477 \ --- \OUTMOD \ 011 = set/reset
33483 \ -------------------------------\
33485 \ -------------------------------\
33487 \ ------------------------------\
33488 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
33489 \ ------------------------------\
33490 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
33491 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
33492 \ ------------------------------\
33493 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
33494 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
33495 \ ------------------------------\
33496 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
33497 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
33498 \ ------------------------------\
33499 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
33500 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
33501 \ ------------------------------\
33502 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
33503 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
33504 \ ------------------------------\
33505 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
33506 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
33507 \ ------------------------------\
33508 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
33509 \ ------------------------------\
33510 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
33511 \ ------------------------------\
33512 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
33513 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
33514 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
33515 \ ------------------------------\
33516 BIS.B #LCDVo,&LCDVo_DIR \
33517 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
33518 \ ------------------------------\
33519 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
33520 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
33521 \ ------------------------------\
33522 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
33523 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
33524 \ ******************************\
33526 \ ******************************\
33527 BIS.B #RC5,&IR_IE \ enable RC5_Int
33528 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
33529 MOV #RC5_INT,&IR_Vec \ init interrupt vector
33530 \ ******************************\
33531 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
33532 \ ******************************\
33533 \ %01 0001 0100 \ TAxCTL
33534 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
33535 \ -- \ ID divided by 1
33536 \ -- \ MC MODE = up to TAxCCRn
33537 \ - \ TACLR clear timer count
33540 \ ------------------------------\
33541 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
33542 \ ------------------------------\
33544 \ --- \ TAIDEX pre divisor
33545 \ ------------------------------\
33546 \ %0000 0000 0000 0101 \ TAxCCR0
33547 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
33548 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
33549 \ ------------------------------\
33550 \ %0000 0000 0001 0000 \ TAxCCTL0
33551 \ - \ CAP capture/compare mode = compare
33554 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
33555 \ ------------------------------\
33556 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
33557 \ ------------------------------\
33558 \ define LPM mode for ACCEPT \
33559 \ ------------------------------\
33560 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
33561 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
33562 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
33564 \ ------------------------------\
33565 \ redirects to background task \
33566 \ ------------------------------\
33568 MOV #BACKGROUND,2(X) \
33569 \ ------------------------------\
33571 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
33573 \ ------------------------------\
33575 \ ------------------------------\
33576 $03E8 20_US \ 1- wait 20 ms
33577 $03 TOP_LCD \ 2- send DB5=DB4=1
33578 $CD 20_US \ 3- wait 4,1 ms
33579 $03 TOP_LCD \ 4- send again DB5=DB4=1
33580 $5 20_US \ 5- wait 0,1 ms
33581 $03 TOP_LCD \ 6- send again again DB5=DB4=1
33582 $2 20_US \ wait 40 us = LCD cycle
33583 $02 TOP_LCD \ 7- send DB5=1 DB4=0
33584 $2 20_US \ wait 40 us = LCD cycle
33585 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
33586 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
33587 LCD_Clear \ 10- "LCD_Clear"
33588 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
33589 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
33590 LCD_Clear \ 10- "LCD_Clear"
33591 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
33592 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
33594 ['] CR >BODY IS CR \
33595 ['] EMIT >BODY IS EMIT \
33596 ." RC5toLCD is running. Type STOP to quit"
33597 LIT RECURSE IS WARM \ replace WARM by this START routine
33598 ABORT \ and continue with the next word after WARM...
33599 ; \ ...until interpreter falls in sleep mode within ACCEPT.
33602 CODE STOP \ stops multitasking, must to be used before downloading app
33603 \ restore default action of primary DEFERred word SLEEP, assembly version
33604 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
33605 ADD #4,X \ X = BODY of SLEEP
33606 MOV X,-2(X) \ restore the default background
33609 \ restore default action of primary DEFERred word WARM, FORTH version
33610 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
33612 COLD \ because we want to reset CPU and interrupt vectors
33617 ; downloading RC5toLCD.4th is done
33618 RST_HERE ; this app is protected against <reset>
33626 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
33628 [DEFINED] ASM [IF] \ security test
33632 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
33634 CODE MAX \ n1 n2 -- n3 signed maximum
33635 CMP @PSP,TOS \ n2-n1
33636 S< ?GOTO FW1 \ n2<n1
33642 CODE MIN \ n1 n2 -- n3 signed minimum
33643 CMP @PSP,TOS \ n2-n1
33644 S< ?GOTO BW1 \ n2<n1
33652 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
33653 : U.R \ u n -- display u unsigned in n width (n >= 2)
33655 R> OVER - 0 MAX SPACES TYPE
33660 \ CODE 20_US \ n -- n * 20 us
33661 \ BEGIN \ 3 cycles loop + 6~
33662 \ \ MOV #5,W \ 3 MCLK = 1 MHz
33663 \ \ MOV #23,W \ 3 MCLK = 4 MHz
33664 \ \ MOV #51,W \ 3 MCLK = 8 MHz
33665 \ MOV #104,W \ 3 MCLK = 16 MHz
33666 \ \ MOV #158,W \ 3 MCLK = 24 MHz
33667 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
33672 \ MOV @PSP+,TOS \ 2
33677 CODE 20_US \ n -- n * 20 us
33678 BEGIN \ here we presume that LCD_TIM_IFG = 1...
33680 BIT #1,&LCD_TIM_CTL \ 3
33681 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
33682 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
33684 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
33690 CODE TOP_LCD \ LCD Sample
33691 \ \ if write : %xxxxWWWW --
33692 \ \ if read : -- %0000RRRR
33693 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
33694 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
33695 0= IF \ write LCD bits pattern
33696 AND.B #LCD_DB,TOS \
33697 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
33698 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
33701 THEN \ read LCD bits pattern
33704 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
33705 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
33706 AND.B #LCD_DB,TOS \
33711 CODE LCD_W \ byte -- write byte to LCD
33713 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
33714 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
33715 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
33716 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
33717 COLON \ high level word starts here
33718 TOP_LCD 2 20_US \ write high nibble first
33723 CODE LCD_WrC \ char -- Write Char
33724 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
33729 CODE LCD_WrF \ func -- Write Fonction
33730 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
33736 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
33741 $02 LCD_WrF 100 20_us
33745 [UNDEFINED] OR [IF]
33747 \ https://forth-standard.org/standard/core/OR
33748 \ C OR x1 x2 -- x3 logical OR
33757 : LCD_Entry_set $04 OR LCD_WrF ;
33759 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
33761 : LCD_DSP_Shift $10 OR LCD_WrF ;
33763 : LCD_Fn_Set $20 OR LCD_WrF ;
33765 : LCD_CGRAM_Set $40 OR LCD_WrF ;
33767 : LCD_Goto $80 OR LCD_WrF ;
33769 CODE LCD_R \ -- byte read byte from LCD
33770 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
33771 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
33772 COLON \ starts a FORTH word
33773 TOP_LCD 2 20_us \ -- %0000HHHH
33774 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
33775 HI2LO \ switch from FORTH to assembler
33776 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
33777 ADD.B @PSP+,TOS \ -- %HHHHLLLL
33778 MOV @RSP+,IP \ restore IP saved by COLON
33783 CODE LCD_RdS \ -- status Read Status
33784 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
33789 CODE LCD_RdC \ -- char Read Char
33790 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
33796 \ ******************************\
33797 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
33798 \ ******************************\
33799 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
33800 BIT.B #SW2,&SW2_IN \ test switch S2
33801 0= IF \ case of switch S2 pressed
33802 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
33804 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
33807 BIT.B #SW1,&SW1_IN \ test switch S1 input
33808 0= IF \ case of Switch S1 pressed
33809 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
33811 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
33815 BW1 \ from quit on truncated RC5 message
33816 BW2 \ from repeated RC5 command
33817 BW3 \ from end of RC5_INT
33818 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
33823 \ ******************************\
33824 ASM RC5_INT \ wake up on Px.RC5 change interrupt
33825 \ ******************************\
33826 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
33827 \ ******************************\
33828 \ \ in : SR(9)=old Toggle bit memory (ADD on)
33829 \ \ SMclock = 8|16|24 MHz
33830 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
33831 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
33832 \ \ SR(9)=new Toggle bit memory (ADD on)
33833 \ ******************************\
33834 \ RC5_FirstStartBitHalfCycle: \
33835 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
33836 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
33837 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
33838 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
33839 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
33840 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
33841 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
33842 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
33843 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
33844 MOV #1778,X \ RC5_Period * 1us
33845 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
33846 MOV #14,W \ count of loop
33848 \ ******************************\
33849 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
33850 \ ******************************\ |
33851 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
33852 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
33853 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
33854 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
33855 \ RC5_Compute_3/4_Period: \ |
33856 RRUM #1,X \ X=1/2 cycle |
33859 ADD X,Y \ Y=3/4 cycle
33860 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
33862 \ ******************************\
33863 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
33864 \ ******************************\
33865 BIT.B #RC5,&IR_IN \ C_flag = IR bit
33866 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
33867 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
33868 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
33869 SUB #1,W \ decrement count loop
33870 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
33871 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
33872 0<> WHILE \ ----> out of loop ----+
33873 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
33875 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
33876 CMP Y,X \ 1 | cycle time out of bound ?
33877 U>= IF \ 2 ^ | yes:
33878 BIC #$30,&RC5_TIM_CTL \ | | stop timer
33879 GOTO BW1 \ | | quit on truncated RC5 message
33881 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
33883 REPEAT \ ----> loop back --+ | with X = new RC5_period value
33884 \ ******************************\ |
33885 \ RC5_SampleEndOf: \ <---------------------+
33886 \ ******************************\
33887 BIC #$30,&RC5_TIM_CTL \ stop timer
33888 \ ******************************\
33889 \ RC5_ComputeNewRC5word \
33890 \ ******************************\
33891 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
33892 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
33893 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
33894 \ ******************************\
33895 \ RC5_ComputeC6bit \
33896 \ ******************************\
33897 BIT #BIT14,T \ test /C6 bit in T
33898 0= IF BIS #BIT6,X \ set C6 bit in X
33899 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
33900 \ ******************************\
33901 \ RC5_CommandByteIsDone \ -- BASE RC5_code
33902 \ ******************************\
33903 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
33904 \ ******************************\
33905 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
33906 XOR @RSP,T \ (new XOR old) Toggle bits
33907 BIT #UF10,T \ repeated RC5_command ?
33908 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
33909 XOR #UF10,0(RSP) \ 5 toggle bit memory
33910 \ ******************************\
33911 \ Display IR_RC5 code \ X = RC5 code
33912 \ ******************************\
33914 MOV &BASE,2(PSP) \ save current base
33915 MOV #$10,&BASE \ set hex base
33916 MOV TOS,0(PSP) \ save TOS
33918 LO2HI \ switch from assembler to FORTH
33919 ['] LCD_CLEAR IS CR \ redirects CR
33920 ['] LCD_WrC IS EMIT \ redirects EMIT
33921 CR ." $" 2 U.R \ print IR_RC5 code
33922 ['] CR >BODY IS CR \ restore CR
33923 ['] EMIT >BODY IS EMIT \ restore EMIT
33924 HI2LO \ switch from FORTH to assembler
33925 MOV TOS,&BASE \ restore current BASE
33927 \ ******************************\
33929 \ ******************************\
33933 \ ------------------------------\
33935 \ ------------------------------\
33936 \ ... \ insert here your background task
33939 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
33940 ADD #4,X \ 1 X = BODY of SLEEP
33943 \ ------------------------------\
33947 \ ------------------------------\
33948 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
33949 \ - - \CNTL Counter lentgh \ 00 = 16 bits
33950 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
33951 \ -- \ID input divider \ 10 = /4
33952 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
33953 \ - \TBCLR TimerB Clear
33956 \ -------------------------------\
33957 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
33958 \ -- \CM Capture Mode
33963 \ --- \OUTMOD \ 011 = set/reset
33969 \ -------------------------------\
33971 \ -------------------------------\
33973 \ ------------------------------\
33974 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
33975 \ ------------------------------\
33976 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
33977 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
33978 \ ------------------------------\
33979 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
33980 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
33981 \ ------------------------------\
33982 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
33983 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
33984 \ ------------------------------\
33985 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
33986 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
33987 \ ------------------------------\
33988 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
33989 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
33990 \ ------------------------------\
33991 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
33992 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
33993 \ ------------------------------\
33994 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
33995 \ ------------------------------\
33996 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
33997 \ ------------------------------\
33998 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
33999 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
34000 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
34001 \ ------------------------------\
34002 BIS.B #LCDVo,&LCDVo_DIR \
34003 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
34004 \ ------------------------------\
34005 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
34006 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
34007 \ ------------------------------\
34008 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
34009 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
34010 \ ******************************\
34012 \ ******************************\
34013 BIS.B #RC5,&IR_IE \ enable RC5_Int
34014 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
34015 MOV #RC5_INT,&IR_Vec \ init interrupt vector
34016 \ ******************************\
34017 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
34018 \ ******************************\
34019 \ %01 0001 0100 \ TAxCTL
34020 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
34021 \ -- \ ID divided by 1
34022 \ -- \ MC MODE = up to TAxCCRn
34023 \ - \ TACLR clear timer count
34026 \ ------------------------------\
34027 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
34028 \ ------------------------------\
34030 \ --- \ TAIDEX pre divisor
34031 \ ------------------------------\
34032 \ %0000 0000 0000 0101 \ TAxCCR0
34033 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
34034 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
34035 \ ------------------------------\
34036 \ %0000 0000 0001 0000 \ TAxCCTL0
34037 \ - \ CAP capture/compare mode = compare
34040 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
34041 \ ------------------------------\
34042 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
34043 \ ------------------------------\
34044 \ define LPM mode for ACCEPT \
34045 \ ------------------------------\
34046 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
34047 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
34048 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
34050 \ ------------------------------\
34051 \ redirects to background task \
34052 \ ------------------------------\
34054 MOV #BACKGROUND,2(X) \
34055 \ ------------------------------\
34057 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
34059 \ ------------------------------\
34061 \ ------------------------------\
34062 $03E8 20_US \ 1- wait 20 ms
34063 $03 TOP_LCD \ 2- send DB5=DB4=1
34064 $CD 20_US \ 3- wait 4,1 ms
34065 $03 TOP_LCD \ 4- send again DB5=DB4=1
34066 $5 20_US \ 5- wait 0,1 ms
34067 $03 TOP_LCD \ 6- send again again DB5=DB4=1
34068 $2 20_US \ wait 40 us = LCD cycle
34069 $02 TOP_LCD \ 7- send DB5=1 DB4=0
34070 $2 20_US \ wait 40 us = LCD cycle
34071 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
34072 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
34073 LCD_Clear \ 10- "LCD_Clear"
34074 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
34075 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
34076 LCD_Clear \ 10- "LCD_Clear"
34077 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
34078 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
34080 ['] CR >BODY IS CR \
34081 ['] EMIT >BODY IS EMIT \
34082 ." RC5toLCD is running. Type STOP to quit"
34083 LIT RECURSE IS WARM \ replace WARM by this START routine
34084 ABORT \ and continue with the next word after WARM...
34085 ; \ ...until interpreter falls in sleep mode within ACCEPT.
34088 CODE STOP \ stops multitasking, must to be used before downloading app
34089 \ restore default action of primary DEFERred word SLEEP, assembly version
34090 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
34091 ADD #4,X \ X = BODY of SLEEP
34092 MOV X,-2(X) \ restore the default background
34095 \ restore default action of primary DEFERred word WARM, FORTH version
34096 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
34098 COLD \ because we want to reset CPU and interrupt vectors
34103 ; downloading RC5toLCD.4th is done
34104 RST_HERE ; this app is protected against <reset>
34112 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
34114 [DEFINED] ASM [IF] \ security test
34118 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
34120 CODE MAX \ n1 n2 -- n3 signed maximum
34121 CMP @PSP,TOS \ n2-n1
34122 S< ?GOTO FW1 \ n2<n1
34128 CODE MIN \ n1 n2 -- n3 signed minimum
34129 CMP @PSP,TOS \ n2-n1
34130 S< ?GOTO BW1 \ n2<n1
34138 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
34139 : U.R \ u n -- display u unsigned in n width (n >= 2)
34141 R> OVER - 0 MAX SPACES TYPE
34146 \ CODE 20_US \ n -- n * 20 us
34147 \ BEGIN \ 3 cycles loop + 6~
34148 \ \ MOV #5,W \ 3 MCLK = 1 MHz
34149 \ \ MOV #23,W \ 3 MCLK = 4 MHz
34150 \ \ MOV #51,W \ 3 MCLK = 8 MHz
34151 \ MOV #104,W \ 3 MCLK = 16 MHz
34152 \ \ MOV #158,W \ 3 MCLK = 24 MHz
34153 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
34158 \ MOV @PSP+,TOS \ 2
34163 CODE 20_US \ n -- n * 20 us
34164 BEGIN \ here we presume that LCD_TIM_IFG = 1...
34166 BIT #1,&LCD_TIM_CTL \ 3
34167 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
34168 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
34170 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
34176 CODE TOP_LCD \ LCD Sample
34177 \ \ if write : %xxxxWWWW --
34178 \ \ if read : -- %0000RRRR
34179 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
34180 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
34181 0= IF \ write LCD bits pattern
34182 AND.B #LCD_DB,TOS \
34183 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
34184 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
34187 THEN \ read LCD bits pattern
34190 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
34191 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
34192 AND.B #LCD_DB,TOS \
34197 CODE LCD_W \ byte -- write byte to LCD
34199 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
34200 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
34201 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
34202 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
34203 COLON \ high level word starts here
34204 TOP_LCD 2 20_US \ write high nibble first
34209 CODE LCD_WrC \ char -- Write Char
34210 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
34215 CODE LCD_WrF \ func -- Write Fonction
34216 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
34222 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
34227 $02 LCD_WrF 100 20_us
34231 [UNDEFINED] OR [IF]
34233 \ https://forth-standard.org/standard/core/OR
34234 \ C OR x1 x2 -- x3 logical OR
34243 : LCD_Entry_set $04 OR LCD_WrF ;
34245 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
34247 : LCD_DSP_Shift $10 OR LCD_WrF ;
34249 : LCD_Fn_Set $20 OR LCD_WrF ;
34251 : LCD_CGRAM_Set $40 OR LCD_WrF ;
34253 : LCD_Goto $80 OR LCD_WrF ;
34255 CODE LCD_R \ -- byte read byte from LCD
34256 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
34257 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
34258 COLON \ starts a FORTH word
34259 TOP_LCD 2 20_us \ -- %0000HHHH
34260 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
34261 HI2LO \ switch from FORTH to assembler
34262 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
34263 ADD.B @PSP+,TOS \ -- %HHHHLLLL
34264 MOV @RSP+,IP \ restore IP saved by COLON
34269 CODE LCD_RdS \ -- status Read Status
34270 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
34275 CODE LCD_RdC \ -- char Read Char
34276 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
34282 \ ******************************\
34283 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
34284 \ ******************************\
34285 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
34286 BIT.B #SW2,&SW2_IN \ test switch S2
34287 0= IF \ case of switch S2 pressed
34288 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
34290 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
34293 BIT.B #SW1,&SW1_IN \ test switch S1 input
34294 0= IF \ case of Switch S1 pressed
34295 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
34297 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
34301 BW1 \ from quit on truncated RC5 message
34302 BW2 \ from repeated RC5 command
34303 BW3 \ from end of RC5_INT
34304 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
34309 \ ******************************\
34310 ASM RC5_INT \ wake up on Px.RC5 change interrupt
34311 \ ******************************\
34312 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
34313 \ ******************************\
34314 \ \ in : SR(9)=old Toggle bit memory (ADD on)
34315 \ \ SMclock = 8|16|24 MHz
34316 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
34317 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
34318 \ \ SR(9)=new Toggle bit memory (ADD on)
34319 \ ******************************\
34320 \ RC5_FirstStartBitHalfCycle: \
34321 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
34322 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
34323 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
34324 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
34325 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
34326 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
34327 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
34328 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
34329 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
34330 MOV #1778,X \ RC5_Period * 1us
34331 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
34332 MOV #14,W \ count of loop
34334 \ ******************************\
34335 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
34336 \ ******************************\ |
34337 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
34338 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
34339 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
34340 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
34341 \ RC5_Compute_3/4_Period: \ |
34342 RRUM #1,X \ X=1/2 cycle |
34345 ADD X,Y \ Y=3/4 cycle
34346 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
34348 \ ******************************\
34349 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
34350 \ ******************************\
34351 BIT.B #RC5,&IR_IN \ C_flag = IR bit
34352 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
34353 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
34354 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
34355 SUB #1,W \ decrement count loop
34356 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
34357 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
34358 0<> WHILE \ ----> out of loop ----+
34359 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
34361 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
34362 CMP Y,X \ 1 | cycle time out of bound ?
34363 U>= IF \ 2 ^ | yes:
34364 BIC #$30,&RC5_TIM_CTL \ | | stop timer
34365 GOTO BW1 \ | | quit on truncated RC5 message
34367 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
34369 REPEAT \ ----> loop back --+ | with X = new RC5_period value
34370 \ ******************************\ |
34371 \ RC5_SampleEndOf: \ <---------------------+
34372 \ ******************************\
34373 BIC #$30,&RC5_TIM_CTL \ stop timer
34374 \ ******************************\
34375 \ RC5_ComputeNewRC5word \
34376 \ ******************************\
34377 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
34378 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
34379 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
34380 \ ******************************\
34381 \ RC5_ComputeC6bit \
34382 \ ******************************\
34383 BIT #BIT14,T \ test /C6 bit in T
34384 0= IF BIS #BIT6,X \ set C6 bit in X
34385 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
34386 \ ******************************\
34387 \ RC5_CommandByteIsDone \ -- BASE RC5_code
34388 \ ******************************\
34389 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
34390 \ ******************************\
34391 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
34392 XOR @RSP,T \ (new XOR old) Toggle bits
34393 BIT #UF10,T \ repeated RC5_command ?
34394 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
34395 XOR #UF10,0(RSP) \ 5 toggle bit memory
34396 \ ******************************\
34397 \ Display IR_RC5 code \ X = RC5 code
34398 \ ******************************\
34400 MOV &BASE,2(PSP) \ save current base
34401 MOV #$10,&BASE \ set hex base
34402 MOV TOS,0(PSP) \ save TOS
34404 LO2HI \ switch from assembler to FORTH
34405 ['] LCD_CLEAR IS CR \ redirects CR
34406 ['] LCD_WrC IS EMIT \ redirects EMIT
34407 CR ." $" 2 U.R \ print IR_RC5 code
34408 ['] CR >BODY IS CR \ restore CR
34409 ['] EMIT >BODY IS EMIT \ restore EMIT
34410 HI2LO \ switch from FORTH to assembler
34411 MOV TOS,&BASE \ restore current BASE
34413 \ ******************************\
34415 \ ******************************\
34419 \ ------------------------------\
34421 \ ------------------------------\
34422 \ ... \ insert here your background task
34425 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
34426 ADD #4,X \ 1 X = BODY of SLEEP
34429 \ ------------------------------\
34433 \ ------------------------------\
34434 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
34435 \ - - \CNTL Counter lentgh \ 00 = 16 bits
34436 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
34437 \ -- \ID input divider \ 10 = /4
34438 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
34439 \ - \TBCLR TimerB Clear
34442 \ -------------------------------\
34443 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
34444 \ -- \CM Capture Mode
34449 \ --- \OUTMOD \ 011 = set/reset
34455 \ -------------------------------\
34457 \ -------------------------------\
34459 \ ------------------------------\
34460 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
34461 \ ------------------------------\
34462 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
34463 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
34464 \ ------------------------------\
34465 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
34466 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
34467 \ ------------------------------\
34468 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
34469 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
34470 \ ------------------------------\
34471 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
34472 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
34473 \ ------------------------------\
34474 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
34475 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
34476 \ ------------------------------\
34477 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
34478 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
34479 \ ------------------------------\
34480 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
34481 \ ------------------------------\
34482 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
34483 \ ------------------------------\
34484 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
34485 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
34486 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
34487 \ ------------------------------\
34488 BIS.B #LCDVo,&LCDVo_DIR \
34489 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
34490 \ ------------------------------\
34491 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
34492 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
34493 \ ------------------------------\
34494 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
34495 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
34496 \ ******************************\
34498 \ ******************************\
34499 BIS.B #RC5,&IR_IE \ enable RC5_Int
34500 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
34501 MOV #RC5_INT,&IR_Vec \ init interrupt vector
34502 \ ******************************\
34503 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
34504 \ ******************************\
34505 \ %01 0001 0100 \ TAxCTL
34506 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
34507 \ -- \ ID divided by 1
34508 \ -- \ MC MODE = up to TAxCCRn
34509 \ - \ TACLR clear timer count
34512 \ ------------------------------\
34513 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
34514 \ ------------------------------\
34516 \ --- \ TAIDEX pre divisor
34517 \ ------------------------------\
34518 \ %0000 0000 0000 0101 \ TAxCCR0
34519 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
34520 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
34521 \ ------------------------------\
34522 \ %0000 0000 0001 0000 \ TAxCCTL0
34523 \ - \ CAP capture/compare mode = compare
34526 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
34527 \ ------------------------------\
34528 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
34529 \ ------------------------------\
34530 \ define LPM mode for ACCEPT \
34531 \ ------------------------------\
34532 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
34533 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
34534 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
34536 \ ------------------------------\
34537 \ redirects to background task \
34538 \ ------------------------------\
34540 MOV #BACKGROUND,2(X) \
34541 \ ------------------------------\
34543 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
34545 \ ------------------------------\
34547 \ ------------------------------\
34548 $03E8 20_US \ 1- wait 20 ms
34549 $03 TOP_LCD \ 2- send DB5=DB4=1
34550 $CD 20_US \ 3- wait 4,1 ms
34551 $03 TOP_LCD \ 4- send again DB5=DB4=1
34552 $5 20_US \ 5- wait 0,1 ms
34553 $03 TOP_LCD \ 6- send again again DB5=DB4=1
34554 $2 20_US \ wait 40 us = LCD cycle
34555 $02 TOP_LCD \ 7- send DB5=1 DB4=0
34556 $2 20_US \ wait 40 us = LCD cycle
34557 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
34558 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
34559 LCD_Clear \ 10- "LCD_Clear"
34560 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
34561 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
34562 LCD_Clear \ 10- "LCD_Clear"
34563 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
34564 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
34566 ['] CR >BODY IS CR \
34567 ['] EMIT >BODY IS EMIT \
34568 ." RC5toLCD is running. Type STOP to quit"
34569 LIT RECURSE IS WARM \ replace WARM by this START routine
34570 ABORT \ and continue with the next word after WARM...
34571 ; \ ...until interpreter falls in sleep mode within ACCEPT.
34574 CODE STOP \ stops multitasking, must to be used before downloading app
34575 \ restore default action of primary DEFERred word SLEEP, assembly version
34576 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
34577 ADD #4,X \ X = BODY of SLEEP
34578 MOV X,-2(X) \ restore the default background
34581 \ restore default action of primary DEFERred word WARM, FORTH version
34582 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
34584 COLD \ because we want to reset CPU and interrupt vectors
34589 ; downloading RC5toLCD.4th is done
34590 RST_HERE ; this app is protected against <reset>
34598 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
34600 [DEFINED] ASM [IF] \ security test
34604 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
34606 CODE MAX \ n1 n2 -- n3 signed maximum
34607 CMP @PSP,TOS \ n2-n1
34608 S< ?GOTO FW1 \ n2<n1
34614 CODE MIN \ n1 n2 -- n3 signed minimum
34615 CMP @PSP,TOS \ n2-n1
34616 S< ?GOTO BW1 \ n2<n1
34624 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
34625 : U.R \ u n -- display u unsigned in n width (n >= 2)
34627 R> OVER - 0 MAX SPACES TYPE
34632 \ CODE 20_US \ n -- n * 20 us
34633 \ BEGIN \ 3 cycles loop + 6~
34634 \ \ MOV #5,W \ 3 MCLK = 1 MHz
34635 \ \ MOV #23,W \ 3 MCLK = 4 MHz
34636 \ \ MOV #51,W \ 3 MCLK = 8 MHz
34637 \ MOV #104,W \ 3 MCLK = 16 MHz
34638 \ \ MOV #158,W \ 3 MCLK = 24 MHz
34639 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
34644 \ MOV @PSP+,TOS \ 2
34649 CODE 20_US \ n -- n * 20 us
34650 BEGIN \ here we presume that LCD_TIM_IFG = 1...
34652 BIT #1,&LCD_TIM_CTL \ 3
34653 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
34654 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
34656 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
34662 CODE TOP_LCD \ LCD Sample
34663 \ \ if write : %xxxxWWWW --
34664 \ \ if read : -- %0000RRRR
34665 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
34666 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
34667 0= IF \ write LCD bits pattern
34668 AND.B #LCD_DB,TOS \
34669 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
34670 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
34673 THEN \ read LCD bits pattern
34676 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
34677 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
34678 AND.B #LCD_DB,TOS \
34683 CODE LCD_W \ byte -- write byte to LCD
34685 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
34686 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
34687 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
34688 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
34689 COLON \ high level word starts here
34690 TOP_LCD 2 20_US \ write high nibble first
34695 CODE LCD_WrC \ char -- Write Char
34696 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
34701 CODE LCD_WrF \ func -- Write Fonction
34702 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
34708 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
34713 $02 LCD_WrF 100 20_us
34717 [UNDEFINED] OR [IF]
34719 \ https://forth-standard.org/standard/core/OR
34720 \ C OR x1 x2 -- x3 logical OR
34729 : LCD_Entry_set $04 OR LCD_WrF ;
34731 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
34733 : LCD_DSP_Shift $10 OR LCD_WrF ;
34735 : LCD_Fn_Set $20 OR LCD_WrF ;
34737 : LCD_CGRAM_Set $40 OR LCD_WrF ;
34739 : LCD_Goto $80 OR LCD_WrF ;
34741 CODE LCD_R \ -- byte read byte from LCD
34742 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
34743 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
34744 COLON \ starts a FORTH word
34745 TOP_LCD 2 20_us \ -- %0000HHHH
34746 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
34747 HI2LO \ switch from FORTH to assembler
34748 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
34749 ADD.B @PSP+,TOS \ -- %HHHHLLLL
34750 MOV @RSP+,IP \ restore IP saved by COLON
34755 CODE LCD_RdS \ -- status Read Status
34756 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
34761 CODE LCD_RdC \ -- char Read Char
34762 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
34768 \ ******************************\
34769 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
34770 \ ******************************\
34771 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
34772 BIT.B #SW2,&SW2_IN \ test switch S2
34773 0= IF \ case of switch S2 pressed
34774 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
34776 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
34779 BIT.B #SW1,&SW1_IN \ test switch S1 input
34780 0= IF \ case of Switch S1 pressed
34781 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
34783 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
34787 BW1 \ from quit on truncated RC5 message
34788 BW2 \ from repeated RC5 command
34789 BW3 \ from end of RC5_INT
34790 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
34795 \ ******************************\
34796 ASM RC5_INT \ wake up on Px.RC5 change interrupt
34797 \ ******************************\
34798 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
34799 \ ******************************\
34800 \ \ in : SR(9)=old Toggle bit memory (ADD on)
34801 \ \ SMclock = 8|16|24 MHz
34802 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
34803 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
34804 \ \ SR(9)=new Toggle bit memory (ADD on)
34805 \ ******************************\
34806 \ RC5_FirstStartBitHalfCycle: \
34807 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
34808 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
34809 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
34810 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
34811 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
34812 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
34813 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
34814 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
34815 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
34816 MOV #1778,X \ RC5_Period * 1us
34817 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
34818 MOV #14,W \ count of loop
34820 \ ******************************\
34821 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
34822 \ ******************************\ |
34823 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
34824 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
34825 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
34826 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
34827 \ RC5_Compute_3/4_Period: \ |
34828 RRUM #1,X \ X=1/2 cycle |
34831 ADD X,Y \ Y=3/4 cycle
34832 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
34834 \ ******************************\
34835 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
34836 \ ******************************\
34837 BIT.B #RC5,&IR_IN \ C_flag = IR bit
34838 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
34839 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
34840 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
34841 SUB #1,W \ decrement count loop
34842 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
34843 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
34844 0<> WHILE \ ----> out of loop ----+
34845 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
34847 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
34848 CMP Y,X \ 1 | cycle time out of bound ?
34849 U>= IF \ 2 ^ | yes:
34850 BIC #$30,&RC5_TIM_CTL \ | | stop timer
34851 GOTO BW1 \ | | quit on truncated RC5 message
34853 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
34855 REPEAT \ ----> loop back --+ | with X = new RC5_period value
34856 \ ******************************\ |
34857 \ RC5_SampleEndOf: \ <---------------------+
34858 \ ******************************\
34859 BIC #$30,&RC5_TIM_CTL \ stop timer
34860 \ ******************************\
34861 \ RC5_ComputeNewRC5word \
34862 \ ******************************\
34863 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
34864 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
34865 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
34866 \ ******************************\
34867 \ RC5_ComputeC6bit \
34868 \ ******************************\
34869 BIT #BIT14,T \ test /C6 bit in T
34870 0= IF BIS #BIT6,X \ set C6 bit in X
34871 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
34872 \ ******************************\
34873 \ RC5_CommandByteIsDone \ -- BASE RC5_code
34874 \ ******************************\
34875 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
34876 \ ******************************\
34877 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
34878 XOR @RSP,T \ (new XOR old) Toggle bits
34879 BIT #UF10,T \ repeated RC5_command ?
34880 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
34881 XOR #UF10,0(RSP) \ 5 toggle bit memory
34882 \ ******************************\
34883 \ Display IR_RC5 code \ X = RC5 code
34884 \ ******************************\
34886 MOV &BASE,2(PSP) \ save current base
34887 MOV #$10,&BASE \ set hex base
34888 MOV TOS,0(PSP) \ save TOS
34890 LO2HI \ switch from assembler to FORTH
34891 ['] LCD_CLEAR IS CR \ redirects CR
34892 ['] LCD_WrC IS EMIT \ redirects EMIT
34893 CR ." $" 2 U.R \ print IR_RC5 code
34894 ['] CR >BODY IS CR \ restore CR
34895 ['] EMIT >BODY IS EMIT \ restore EMIT
34896 HI2LO \ switch from FORTH to assembler
34897 MOV TOS,&BASE \ restore current BASE
34899 \ ******************************\
34901 \ ******************************\
34905 \ ------------------------------\
34907 \ ------------------------------\
34908 \ ... \ insert here your background task
34911 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
34912 ADD #4,X \ 1 X = BODY of SLEEP
34915 \ ------------------------------\
34919 \ ------------------------------\
34920 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
34921 \ - - \CNTL Counter lentgh \ 00 = 16 bits
34922 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
34923 \ -- \ID input divider \ 10 = /4
34924 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
34925 \ - \TBCLR TimerB Clear
34928 \ -------------------------------\
34929 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
34930 \ -- \CM Capture Mode
34935 \ --- \OUTMOD \ 011 = set/reset
34941 \ -------------------------------\
34943 \ -------------------------------\
34945 \ ------------------------------\
34946 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
34947 \ ------------------------------\
34948 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
34949 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
34950 \ ------------------------------\
34951 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
34952 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
34953 \ ------------------------------\
34954 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
34955 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
34956 \ ------------------------------\
34957 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
34958 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
34959 \ ------------------------------\
34960 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
34961 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
34962 \ ------------------------------\
34963 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
34964 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
34965 \ ------------------------------\
34966 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
34967 \ ------------------------------\
34968 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
34969 \ ------------------------------\
34970 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
34971 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
34972 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
34973 \ ------------------------------\
34974 BIS.B #LCDVo,&LCDVo_DIR \
34975 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
34976 \ ------------------------------\
34977 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
34978 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
34979 \ ------------------------------\
34980 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
34981 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
34982 \ ******************************\
34984 \ ******************************\
34985 BIS.B #RC5,&IR_IE \ enable RC5_Int
34986 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
34987 MOV #RC5_INT,&IR_Vec \ init interrupt vector
34988 \ ******************************\
34989 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
34990 \ ******************************\
34991 \ %01 0001 0100 \ TAxCTL
34992 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
34993 \ -- \ ID divided by 1
34994 \ -- \ MC MODE = up to TAxCCRn
34995 \ - \ TACLR clear timer count
34998 \ ------------------------------\
34999 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
35000 \ ------------------------------\
35002 \ --- \ TAIDEX pre divisor
35003 \ ------------------------------\
35004 \ %0000 0000 0000 0101 \ TAxCCR0
35005 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
35006 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
35007 \ ------------------------------\
35008 \ %0000 0000 0001 0000 \ TAxCCTL0
35009 \ - \ CAP capture/compare mode = compare
35012 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
35013 \ ------------------------------\
35014 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
35015 \ ------------------------------\
35016 \ define LPM mode for ACCEPT \
35017 \ ------------------------------\
35018 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
35019 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
35020 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
35022 \ ------------------------------\
35023 \ redirects to background task \
35024 \ ------------------------------\
35026 MOV #BACKGROUND,2(X) \
35027 \ ------------------------------\
35029 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
35031 \ ------------------------------\
35033 \ ------------------------------\
35034 $03E8 20_US \ 1- wait 20 ms
35035 $03 TOP_LCD \ 2- send DB5=DB4=1
35036 $CD 20_US \ 3- wait 4,1 ms
35037 $03 TOP_LCD \ 4- send again DB5=DB4=1
35038 $5 20_US \ 5- wait 0,1 ms
35039 $03 TOP_LCD \ 6- send again again DB5=DB4=1
35040 $2 20_US \ wait 40 us = LCD cycle
35041 $02 TOP_LCD \ 7- send DB5=1 DB4=0
35042 $2 20_US \ wait 40 us = LCD cycle
35043 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
35044 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
35045 LCD_Clear \ 10- "LCD_Clear"
35046 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
35047 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
35048 LCD_Clear \ 10- "LCD_Clear"
35049 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
35050 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
35052 ['] CR >BODY IS CR \
35053 ['] EMIT >BODY IS EMIT \
35054 ." RC5toLCD is running. Type STOP to quit"
35055 LIT RECURSE IS WARM \ replace WARM by this START routine
35056 ABORT \ and continue with the next word after WARM...
35057 ; \ ...until interpreter falls in sleep mode within ACCEPT.
35060 CODE STOP \ stops multitasking, must to be used before downloading app
35061 \ restore default action of primary DEFERred word SLEEP, assembly version
35062 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
35063 ADD #4,X \ X = BODY of SLEEP
35064 MOV X,-2(X) \ restore the default background
35067 \ restore default action of primary DEFERred word WARM, FORTH version
35068 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
35070 COLD \ because we want to reset CPU and interrupt vectors
35075 ; downloading RC5toLCD.4th is done
35076 RST_HERE ; this app is protected against <reset>
35084 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
35086 [DEFINED] ASM [IF] \ security test
35090 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
35092 CODE MAX \ n1 n2 -- n3 signed maximum
35093 CMP @PSP,TOS \ n2-n1
35094 S< ?GOTO FW1 \ n2<n1
35100 CODE MIN \ n1 n2 -- n3 signed minimum
35101 CMP @PSP,TOS \ n2-n1
35102 S< ?GOTO BW1 \ n2<n1
35110 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
35111 : U.R \ u n -- display u unsigned in n width (n >= 2)
35113 R> OVER - 0 MAX SPACES TYPE
35118 \ CODE 20_US \ n -- n * 20 us
35119 \ BEGIN \ 3 cycles loop + 6~
35120 \ \ MOV #5,W \ 3 MCLK = 1 MHz
35121 \ \ MOV #23,W \ 3 MCLK = 4 MHz
35122 \ \ MOV #51,W \ 3 MCLK = 8 MHz
35123 \ MOV #104,W \ 3 MCLK = 16 MHz
35124 \ \ MOV #158,W \ 3 MCLK = 24 MHz
35125 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
35130 \ MOV @PSP+,TOS \ 2
35135 CODE 20_US \ n -- n * 20 us
35136 BEGIN \ here we presume that LCD_TIM_IFG = 1...
35138 BIT #1,&LCD_TIM_CTL \ 3
35139 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
35140 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
35142 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
35148 CODE TOP_LCD \ LCD Sample
35149 \ \ if write : %xxxxWWWW --
35150 \ \ if read : -- %0000RRRR
35151 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
35152 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
35153 0= IF \ write LCD bits pattern
35154 AND.B #LCD_DB,TOS \
35155 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
35156 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
35159 THEN \ read LCD bits pattern
35162 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
35163 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
35164 AND.B #LCD_DB,TOS \
35169 CODE LCD_W \ byte -- write byte to LCD
35171 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
35172 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
35173 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
35174 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
35175 COLON \ high level word starts here
35176 TOP_LCD 2 20_US \ write high nibble first
35181 CODE LCD_WrC \ char -- Write Char
35182 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
35187 CODE LCD_WrF \ func -- Write Fonction
35188 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
35194 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
35199 $02 LCD_WrF 100 20_us
35203 [UNDEFINED] OR [IF]
35205 \ https://forth-standard.org/standard/core/OR
35206 \ C OR x1 x2 -- x3 logical OR
35215 : LCD_Entry_set $04 OR LCD_WrF ;
35217 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
35219 : LCD_DSP_Shift $10 OR LCD_WrF ;
35221 : LCD_Fn_Set $20 OR LCD_WrF ;
35223 : LCD_CGRAM_Set $40 OR LCD_WrF ;
35225 : LCD_Goto $80 OR LCD_WrF ;
35227 CODE LCD_R \ -- byte read byte from LCD
35228 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
35229 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
35230 COLON \ starts a FORTH word
35231 TOP_LCD 2 20_us \ -- %0000HHHH
35232 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
35233 HI2LO \ switch from FORTH to assembler
35234 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
35235 ADD.B @PSP+,TOS \ -- %HHHHLLLL
35236 MOV @RSP+,IP \ restore IP saved by COLON
35241 CODE LCD_RdS \ -- status Read Status
35242 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
35247 CODE LCD_RdC \ -- char Read Char
35248 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
35254 \ ******************************\
35255 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
35256 \ ******************************\
35257 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
35258 BIT.B #SW2,&SW2_IN \ test switch S2
35259 0= IF \ case of switch S2 pressed
35260 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
35262 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
35265 BIT.B #SW1,&SW1_IN \ test switch S1 input
35266 0= IF \ case of Switch S1 pressed
35267 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
35269 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
35273 BW1 \ from quit on truncated RC5 message
35274 BW2 \ from repeated RC5 command
35275 BW3 \ from end of RC5_INT
35276 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
35281 \ ******************************\
35282 ASM RC5_INT \ wake up on Px.RC5 change interrupt
35283 \ ******************************\
35284 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
35285 \ ******************************\
35286 \ \ in : SR(9)=old Toggle bit memory (ADD on)
35287 \ \ SMclock = 8|16|24 MHz
35288 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
35289 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
35290 \ \ SR(9)=new Toggle bit memory (ADD on)
35291 \ ******************************\
35292 \ RC5_FirstStartBitHalfCycle: \
35293 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
35294 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
35295 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
35296 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
35297 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
35298 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
35299 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
35300 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
35301 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
35302 MOV #1778,X \ RC5_Period * 1us
35303 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
35304 MOV #14,W \ count of loop
35306 \ ******************************\
35307 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
35308 \ ******************************\ |
35309 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
35310 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
35311 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
35312 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
35313 \ RC5_Compute_3/4_Period: \ |
35314 RRUM #1,X \ X=1/2 cycle |
35317 ADD X,Y \ Y=3/4 cycle
35318 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
35320 \ ******************************\
35321 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
35322 \ ******************************\
35323 BIT.B #RC5,&IR_IN \ C_flag = IR bit
35324 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
35325 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
35326 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
35327 SUB #1,W \ decrement count loop
35328 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
35329 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
35330 0<> WHILE \ ----> out of loop ----+
35331 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
35333 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
35334 CMP Y,X \ 1 | cycle time out of bound ?
35335 U>= IF \ 2 ^ | yes:
35336 BIC #$30,&RC5_TIM_CTL \ | | stop timer
35337 GOTO BW1 \ | | quit on truncated RC5 message
35339 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
35341 REPEAT \ ----> loop back --+ | with X = new RC5_period value
35342 \ ******************************\ |
35343 \ RC5_SampleEndOf: \ <---------------------+
35344 \ ******************************\
35345 BIC #$30,&RC5_TIM_CTL \ stop timer
35346 \ ******************************\
35347 \ RC5_ComputeNewRC5word \
35348 \ ******************************\
35349 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
35350 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
35351 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
35352 \ ******************************\
35353 \ RC5_ComputeC6bit \
35354 \ ******************************\
35355 BIT #BIT14,T \ test /C6 bit in T
35356 0= IF BIS #BIT6,X \ set C6 bit in X
35357 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
35358 \ ******************************\
35359 \ RC5_CommandByteIsDone \ -- BASE RC5_code
35360 \ ******************************\
35361 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
35362 \ ******************************\
35363 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
35364 XOR @RSP,T \ (new XOR old) Toggle bits
35365 BIT #UF10,T \ repeated RC5_command ?
35366 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
35367 XOR #UF10,0(RSP) \ 5 toggle bit memory
35368 \ ******************************\
35369 \ Display IR_RC5 code \ X = RC5 code
35370 \ ******************************\
35372 MOV &BASE,2(PSP) \ save current base
35373 MOV #$10,&BASE \ set hex base
35374 MOV TOS,0(PSP) \ save TOS
35376 LO2HI \ switch from assembler to FORTH
35377 ['] LCD_CLEAR IS CR \ redirects CR
35378 ['] LCD_WrC IS EMIT \ redirects EMIT
35379 CR ." $" 2 U.R \ print IR_RC5 code
35380 ['] CR >BODY IS CR \ restore CR
35381 ['] EMIT >BODY IS EMIT \ restore EMIT
35382 HI2LO \ switch from FORTH to assembler
35383 MOV TOS,&BASE \ restore current BASE
35385 \ ******************************\
35387 \ ******************************\
35391 \ ------------------------------\
35393 \ ------------------------------\
35394 \ ... \ insert here your background task
35397 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
35398 ADD #4,X \ 1 X = BODY of SLEEP
35401 \ ------------------------------\
35405 \ ------------------------------\
35406 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
35407 \ - - \CNTL Counter lentgh \ 00 = 16 bits
35408 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
35409 \ -- \ID input divider \ 10 = /4
35410 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
35411 \ - \TBCLR TimerB Clear
35414 \ -------------------------------\
35415 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
35416 \ -- \CM Capture Mode
35421 \ --- \OUTMOD \ 011 = set/reset
35427 \ -------------------------------\
35429 \ -------------------------------\
35431 \ ------------------------------\
35432 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
35433 \ ------------------------------\
35434 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
35435 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
35436 \ ------------------------------\
35437 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
35438 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
35439 \ ------------------------------\
35440 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
35441 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
35442 \ ------------------------------\
35443 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
35444 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
35445 \ ------------------------------\
35446 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
35447 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
35448 \ ------------------------------\
35449 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
35450 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
35451 \ ------------------------------\
35452 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
35453 \ ------------------------------\
35454 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
35455 \ ------------------------------\
35456 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
35457 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
35458 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
35459 \ ------------------------------\
35460 BIS.B #LCDVo,&LCDVo_DIR \
35461 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
35462 \ ------------------------------\
35463 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
35464 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
35465 \ ------------------------------\
35466 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
35467 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
35468 \ ******************************\
35470 \ ******************************\
35471 BIS.B #RC5,&IR_IE \ enable RC5_Int
35472 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
35473 MOV #RC5_INT,&IR_Vec \ init interrupt vector
35474 \ ******************************\
35475 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
35476 \ ******************************\
35477 \ %01 0001 0100 \ TAxCTL
35478 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
35479 \ -- \ ID divided by 1
35480 \ -- \ MC MODE = up to TAxCCRn
35481 \ - \ TACLR clear timer count
35484 \ ------------------------------\
35485 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
35486 \ ------------------------------\
35488 \ --- \ TAIDEX pre divisor
35489 \ ------------------------------\
35490 \ %0000 0000 0000 0101 \ TAxCCR0
35491 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
35492 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
35493 \ ------------------------------\
35494 \ %0000 0000 0001 0000 \ TAxCCTL0
35495 \ - \ CAP capture/compare mode = compare
35498 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
35499 \ ------------------------------\
35500 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
35501 \ ------------------------------\
35502 \ define LPM mode for ACCEPT \
35503 \ ------------------------------\
35504 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
35505 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
35506 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
35508 \ ------------------------------\
35509 \ redirects to background task \
35510 \ ------------------------------\
35512 MOV #BACKGROUND,2(X) \
35513 \ ------------------------------\
35515 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
35517 \ ------------------------------\
35519 \ ------------------------------\
35520 $03E8 20_US \ 1- wait 20 ms
35521 $03 TOP_LCD \ 2- send DB5=DB4=1
35522 $CD 20_US \ 3- wait 4,1 ms
35523 $03 TOP_LCD \ 4- send again DB5=DB4=1
35524 $5 20_US \ 5- wait 0,1 ms
35525 $03 TOP_LCD \ 6- send again again DB5=DB4=1
35526 $2 20_US \ wait 40 us = LCD cycle
35527 $02 TOP_LCD \ 7- send DB5=1 DB4=0
35528 $2 20_US \ wait 40 us = LCD cycle
35529 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
35530 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
35531 LCD_Clear \ 10- "LCD_Clear"
35532 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
35533 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
35534 LCD_Clear \ 10- "LCD_Clear"
35535 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
35536 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
35538 ['] CR >BODY IS CR \
35539 ['] EMIT >BODY IS EMIT \
35540 ." RC5toLCD is running. Type STOP to quit"
35541 LIT RECURSE IS WARM \ replace WARM by this START routine
35542 ABORT \ and continue with the next word after WARM...
35543 ; \ ...until interpreter falls in sleep mode within ACCEPT.
35546 CODE STOP \ stops multitasking, must to be used before downloading app
35547 \ restore default action of primary DEFERred word SLEEP, assembly version
35548 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
35549 ADD #4,X \ X = BODY of SLEEP
35550 MOV X,-2(X) \ restore the default background
35553 \ restore default action of primary DEFERred word WARM, FORTH version
35554 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
35556 COLD \ because we want to reset CPU and interrupt vectors
35561 ; downloading RC5toLCD.4th is done
35562 RST_HERE ; this app is protected against <reset>
35570 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
35572 [DEFINED] ASM [IF] \ security test
35576 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
35578 CODE MAX \ n1 n2 -- n3 signed maximum
35579 CMP @PSP,TOS \ n2-n1
35580 S< ?GOTO FW1 \ n2<n1
35586 CODE MIN \ n1 n2 -- n3 signed minimum
35587 CMP @PSP,TOS \ n2-n1
35588 S< ?GOTO BW1 \ n2<n1
35596 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
35597 : U.R \ u n -- display u unsigned in n width (n >= 2)
35599 R> OVER - 0 MAX SPACES TYPE
35604 \ CODE 20_US \ n -- n * 20 us
35605 \ BEGIN \ 3 cycles loop + 6~
35606 \ \ MOV #5,W \ 3 MCLK = 1 MHz
35607 \ \ MOV #23,W \ 3 MCLK = 4 MHz
35608 \ \ MOV #51,W \ 3 MCLK = 8 MHz
35609 \ MOV #104,W \ 3 MCLK = 16 MHz
35610 \ \ MOV #158,W \ 3 MCLK = 24 MHz
35611 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
35616 \ MOV @PSP+,TOS \ 2
35621 CODE 20_US \ n -- n * 20 us
35622 BEGIN \ here we presume that LCD_TIM_IFG = 1...
35624 BIT #1,&LCD_TIM_CTL \ 3
35625 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
35626 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
35628 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
35634 CODE TOP_LCD \ LCD Sample
35635 \ \ if write : %xxxxWWWW --
35636 \ \ if read : -- %0000RRRR
35637 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
35638 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
35639 0= IF \ write LCD bits pattern
35640 AND.B #LCD_DB,TOS \
35641 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
35642 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
35645 THEN \ read LCD bits pattern
35648 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
35649 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
35650 AND.B #LCD_DB,TOS \
35655 CODE LCD_W \ byte -- write byte to LCD
35657 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
35658 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
35659 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
35660 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
35661 COLON \ high level word starts here
35662 TOP_LCD 2 20_US \ write high nibble first
35667 CODE LCD_WrC \ char -- Write Char
35668 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
35673 CODE LCD_WrF \ func -- Write Fonction
35674 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
35680 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
35685 $02 LCD_WrF 100 20_us
35689 [UNDEFINED] OR [IF]
35691 \ https://forth-standard.org/standard/core/OR
35692 \ C OR x1 x2 -- x3 logical OR
35701 : LCD_Entry_set $04 OR LCD_WrF ;
35703 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
35705 : LCD_DSP_Shift $10 OR LCD_WrF ;
35707 : LCD_Fn_Set $20 OR LCD_WrF ;
35709 : LCD_CGRAM_Set $40 OR LCD_WrF ;
35711 : LCD_Goto $80 OR LCD_WrF ;
35713 CODE LCD_R \ -- byte read byte from LCD
35714 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
35715 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
35716 COLON \ starts a FORTH word
35717 TOP_LCD 2 20_us \ -- %0000HHHH
35718 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
35719 HI2LO \ switch from FORTH to assembler
35720 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
35721 ADD.B @PSP+,TOS \ -- %HHHHLLLL
35722 MOV @RSP+,IP \ restore IP saved by COLON
35727 CODE LCD_RdS \ -- status Read Status
35728 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
35733 CODE LCD_RdC \ -- char Read Char
35734 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
35740 \ ******************************\
35741 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
35742 \ ******************************\
35743 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
35744 BIT.B #SW2,&SW2_IN \ test switch S2
35745 0= IF \ case of switch S2 pressed
35746 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
35748 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
35751 BIT.B #SW1,&SW1_IN \ test switch S1 input
35752 0= IF \ case of Switch S1 pressed
35753 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
35755 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
35759 BW1 \ from quit on truncated RC5 message
35760 BW2 \ from repeated RC5 command
35761 BW3 \ from end of RC5_INT
35762 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
35767 \ ******************************\
35768 ASM RC5_INT \ wake up on Px.RC5 change interrupt
35769 \ ******************************\
35770 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
35771 \ ******************************\
35772 \ \ in : SR(9)=old Toggle bit memory (ADD on)
35773 \ \ SMclock = 8|16|24 MHz
35774 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
35775 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
35776 \ \ SR(9)=new Toggle bit memory (ADD on)
35777 \ ******************************\
35778 \ RC5_FirstStartBitHalfCycle: \
35779 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
35780 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
35781 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
35782 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
35783 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
35784 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
35785 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
35786 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
35787 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
35788 MOV #1778,X \ RC5_Period * 1us
35789 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
35790 MOV #14,W \ count of loop
35792 \ ******************************\
35793 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
35794 \ ******************************\ |
35795 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
35796 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
35797 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
35798 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
35799 \ RC5_Compute_3/4_Period: \ |
35800 RRUM #1,X \ X=1/2 cycle |
35803 ADD X,Y \ Y=3/4 cycle
35804 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
35806 \ ******************************\
35807 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
35808 \ ******************************\
35809 BIT.B #RC5,&IR_IN \ C_flag = IR bit
35810 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
35811 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
35812 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
35813 SUB #1,W \ decrement count loop
35814 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
35815 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
35816 0<> WHILE \ ----> out of loop ----+
35817 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
35819 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
35820 CMP Y,X \ 1 | cycle time out of bound ?
35821 U>= IF \ 2 ^ | yes:
35822 BIC #$30,&RC5_TIM_CTL \ | | stop timer
35823 GOTO BW1 \ | | quit on truncated RC5 message
35825 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
35827 REPEAT \ ----> loop back --+ | with X = new RC5_period value
35828 \ ******************************\ |
35829 \ RC5_SampleEndOf: \ <---------------------+
35830 \ ******************************\
35831 BIC #$30,&RC5_TIM_CTL \ stop timer
35832 \ ******************************\
35833 \ RC5_ComputeNewRC5word \
35834 \ ******************************\
35835 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
35836 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
35837 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
35838 \ ******************************\
35839 \ RC5_ComputeC6bit \
35840 \ ******************************\
35841 BIT #BIT14,T \ test /C6 bit in T
35842 0= IF BIS #BIT6,X \ set C6 bit in X
35843 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
35844 \ ******************************\
35845 \ RC5_CommandByteIsDone \ -- BASE RC5_code
35846 \ ******************************\
35847 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
35848 \ ******************************\
35849 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
35850 XOR @RSP,T \ (new XOR old) Toggle bits
35851 BIT #UF10,T \ repeated RC5_command ?
35852 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
35853 XOR #UF10,0(RSP) \ 5 toggle bit memory
35854 \ ******************************\
35855 \ Display IR_RC5 code \ X = RC5 code
35856 \ ******************************\
35858 MOV &BASE,2(PSP) \ save current base
35859 MOV #$10,&BASE \ set hex base
35860 MOV TOS,0(PSP) \ save TOS
35862 LO2HI \ switch from assembler to FORTH
35863 ['] LCD_CLEAR IS CR \ redirects CR
35864 ['] LCD_WrC IS EMIT \ redirects EMIT
35865 CR ." $" 2 U.R \ print IR_RC5 code
35866 ['] CR >BODY IS CR \ restore CR
35867 ['] EMIT >BODY IS EMIT \ restore EMIT
35868 HI2LO \ switch from FORTH to assembler
35869 MOV TOS,&BASE \ restore current BASE
35871 \ ******************************\
35873 \ ******************************\
35877 \ ------------------------------\
35879 \ ------------------------------\
35880 \ ... \ insert here your background task
35883 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
35884 ADD #4,X \ 1 X = BODY of SLEEP
35887 \ ------------------------------\
35891 \ ------------------------------\
35892 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
35893 \ - - \CNTL Counter lentgh \ 00 = 16 bits
35894 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
35895 \ -- \ID input divider \ 10 = /4
35896 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
35897 \ - \TBCLR TimerB Clear
35900 \ -------------------------------\
35901 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
35902 \ -- \CM Capture Mode
35907 \ --- \OUTMOD \ 011 = set/reset
35913 \ -------------------------------\
35915 \ -------------------------------\
35917 \ ------------------------------\
35918 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
35919 \ ------------------------------\
35920 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
35921 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
35922 \ ------------------------------\
35923 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
35924 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
35925 \ ------------------------------\
35926 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
35927 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
35928 \ ------------------------------\
35929 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
35930 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
35931 \ ------------------------------\
35932 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
35933 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
35934 \ ------------------------------\
35935 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
35936 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
35937 \ ------------------------------\
35938 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
35939 \ ------------------------------\
35940 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
35941 \ ------------------------------\
35942 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
35943 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
35944 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
35945 \ ------------------------------\
35946 BIS.B #LCDVo,&LCDVo_DIR \
35947 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
35948 \ ------------------------------\
35949 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
35950 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
35951 \ ------------------------------\
35952 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
35953 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
35954 \ ******************************\
35956 \ ******************************\
35957 BIS.B #RC5,&IR_IE \ enable RC5_Int
35958 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
35959 MOV #RC5_INT,&IR_Vec \ init interrupt vector
35960 \ ******************************\
35961 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
35962 \ ******************************\
35963 \ %01 0001 0100 \ TAxCTL
35964 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
35965 \ -- \ ID divided by 1
35966 \ -- \ MC MODE = up to TAxCCRn
35967 \ - \ TACLR clear timer count
35970 \ ------------------------------\
35971 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
35972 \ ------------------------------\
35974 \ --- \ TAIDEX pre divisor
35975 \ ------------------------------\
35976 \ %0000 0000 0000 0101 \ TAxCCR0
35977 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
35978 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
35979 \ ------------------------------\
35980 \ %0000 0000 0001 0000 \ TAxCCTL0
35981 \ - \ CAP capture/compare mode = compare
35984 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
35985 \ ------------------------------\
35986 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
35987 \ ------------------------------\
35988 \ define LPM mode for ACCEPT \
35989 \ ------------------------------\
35990 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
35991 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
35992 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
35994 \ ------------------------------\
35995 \ redirects to background task \
35996 \ ------------------------------\
35998 MOV #BACKGROUND,2(X) \
35999 \ ------------------------------\
36001 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
36003 \ ------------------------------\
36005 \ ------------------------------\
36006 $03E8 20_US \ 1- wait 20 ms
36007 $03 TOP_LCD \ 2- send DB5=DB4=1
36008 $CD 20_US \ 3- wait 4,1 ms
36009 $03 TOP_LCD \ 4- send again DB5=DB4=1
36010 $5 20_US \ 5- wait 0,1 ms
36011 $03 TOP_LCD \ 6- send again again DB5=DB4=1
36012 $2 20_US \ wait 40 us = LCD cycle
36013 $02 TOP_LCD \ 7- send DB5=1 DB4=0
36014 $2 20_US \ wait 40 us = LCD cycle
36015 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
36016 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
36017 LCD_Clear \ 10- "LCD_Clear"
36018 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
36019 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
36020 LCD_Clear \ 10- "LCD_Clear"
36021 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
36022 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
36024 ['] CR >BODY IS CR \
36025 ['] EMIT >BODY IS EMIT \
36026 ." RC5toLCD is running. Type STOP to quit"
36027 LIT RECURSE IS WARM \ replace WARM by this START routine
36028 ABORT \ and continue with the next word after WARM...
36029 ; \ ...until interpreter falls in sleep mode within ACCEPT.
36032 CODE STOP \ stops multitasking, must to be used before downloading app
36033 \ restore default action of primary DEFERred word SLEEP, assembly version
36034 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
36035 ADD #4,X \ X = BODY of SLEEP
36036 MOV X,-2(X) \ restore the default background
36039 \ restore default action of primary DEFERred word WARM, FORTH version
36040 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
36042 COLD \ because we want to reset CPU and interrupt vectors
36047 ; downloading RC5toLCD.4th is done
36048 RST_HERE ; this app is protected against <reset>
36056 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
36058 [DEFINED] ASM [IF] \ security test
36062 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
36064 CODE MAX \ n1 n2 -- n3 signed maximum
36065 CMP @PSP,TOS \ n2-n1
36066 S< ?GOTO FW1 \ n2<n1
36072 CODE MIN \ n1 n2 -- n3 signed minimum
36073 CMP @PSP,TOS \ n2-n1
36074 S< ?GOTO BW1 \ n2<n1
36082 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
36083 : U.R \ u n -- display u unsigned in n width (n >= 2)
36085 R> OVER - 0 MAX SPACES TYPE
36090 \ CODE 20_US \ n -- n * 20 us
36091 \ BEGIN \ 3 cycles loop + 6~
36092 \ \ MOV #5,W \ 3 MCLK = 1 MHz
36093 \ \ MOV #23,W \ 3 MCLK = 4 MHz
36094 \ \ MOV #51,W \ 3 MCLK = 8 MHz
36095 \ MOV #104,W \ 3 MCLK = 16 MHz
36096 \ \ MOV #158,W \ 3 MCLK = 24 MHz
36097 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
36102 \ MOV @PSP+,TOS \ 2
36107 CODE 20_US \ n -- n * 20 us
36108 BEGIN \ here we presume that LCD_TIM_IFG = 1...
36110 BIT #1,&LCD_TIM_CTL \ 3
36111 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
36112 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
36114 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
36120 CODE TOP_LCD \ LCD Sample
36121 \ \ if write : %xxxxWWWW --
36122 \ \ if read : -- %0000RRRR
36123 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
36124 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
36125 0= IF \ write LCD bits pattern
36126 AND.B #LCD_DB,TOS \
36127 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
36128 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
36131 THEN \ read LCD bits pattern
36134 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
36135 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
36136 AND.B #LCD_DB,TOS \
36141 CODE LCD_W \ byte -- write byte to LCD
36143 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
36144 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
36145 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
36146 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
36147 COLON \ high level word starts here
36148 TOP_LCD 2 20_US \ write high nibble first
36153 CODE LCD_WrC \ char -- Write Char
36154 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
36159 CODE LCD_WrF \ func -- Write Fonction
36160 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
36166 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
36171 $02 LCD_WrF 100 20_us
36175 [UNDEFINED] OR [IF]
36177 \ https://forth-standard.org/standard/core/OR
36178 \ C OR x1 x2 -- x3 logical OR
36187 : LCD_Entry_set $04 OR LCD_WrF ;
36189 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
36191 : LCD_DSP_Shift $10 OR LCD_WrF ;
36193 : LCD_Fn_Set $20 OR LCD_WrF ;
36195 : LCD_CGRAM_Set $40 OR LCD_WrF ;
36197 : LCD_Goto $80 OR LCD_WrF ;
36199 CODE LCD_R \ -- byte read byte from LCD
36200 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
36201 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
36202 COLON \ starts a FORTH word
36203 TOP_LCD 2 20_us \ -- %0000HHHH
36204 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
36205 HI2LO \ switch from FORTH to assembler
36206 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
36207 ADD.B @PSP+,TOS \ -- %HHHHLLLL
36208 MOV @RSP+,IP \ restore IP saved by COLON
36213 CODE LCD_RdS \ -- status Read Status
36214 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
36219 CODE LCD_RdC \ -- char Read Char
36220 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
36226 \ ******************************\
36227 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
36228 \ ******************************\
36229 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
36230 BIT.B #SW2,&SW2_IN \ test switch S2
36231 0= IF \ case of switch S2 pressed
36232 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
36234 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
36237 BIT.B #SW1,&SW1_IN \ test switch S1 input
36238 0= IF \ case of Switch S1 pressed
36239 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
36241 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
36245 BW1 \ from quit on truncated RC5 message
36246 BW2 \ from repeated RC5 command
36247 BW3 \ from end of RC5_INT
36248 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
36253 \ ******************************\
36254 ASM RC5_INT \ wake up on Px.RC5 change interrupt
36255 \ ******************************\
36256 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
36257 \ ******************************\
36258 \ \ in : SR(9)=old Toggle bit memory (ADD on)
36259 \ \ SMclock = 8|16|24 MHz
36260 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
36261 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
36262 \ \ SR(9)=new Toggle bit memory (ADD on)
36263 \ ******************************\
36264 \ RC5_FirstStartBitHalfCycle: \
36265 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
36266 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
36267 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
36268 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
36269 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
36270 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
36271 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
36272 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
36273 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
36274 MOV #1778,X \ RC5_Period * 1us
36275 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
36276 MOV #14,W \ count of loop
36278 \ ******************************\
36279 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
36280 \ ******************************\ |
36281 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
36282 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
36283 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
36284 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
36285 \ RC5_Compute_3/4_Period: \ |
36286 RRUM #1,X \ X=1/2 cycle |
36289 ADD X,Y \ Y=3/4 cycle
36290 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
36292 \ ******************************\
36293 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
36294 \ ******************************\
36295 BIT.B #RC5,&IR_IN \ C_flag = IR bit
36296 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
36297 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
36298 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
36299 SUB #1,W \ decrement count loop
36300 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
36301 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
36302 0<> WHILE \ ----> out of loop ----+
36303 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
36305 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
36306 CMP Y,X \ 1 | cycle time out of bound ?
36307 U>= IF \ 2 ^ | yes:
36308 BIC #$30,&RC5_TIM_CTL \ | | stop timer
36309 GOTO BW1 \ | | quit on truncated RC5 message
36311 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
36313 REPEAT \ ----> loop back --+ | with X = new RC5_period value
36314 \ ******************************\ |
36315 \ RC5_SampleEndOf: \ <---------------------+
36316 \ ******************************\
36317 BIC #$30,&RC5_TIM_CTL \ stop timer
36318 \ ******************************\
36319 \ RC5_ComputeNewRC5word \
36320 \ ******************************\
36321 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
36322 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
36323 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
36324 \ ******************************\
36325 \ RC5_ComputeC6bit \
36326 \ ******************************\
36327 BIT #BIT14,T \ test /C6 bit in T
36328 0= IF BIS #BIT6,X \ set C6 bit in X
36329 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
36330 \ ******************************\
36331 \ RC5_CommandByteIsDone \ -- BASE RC5_code
36332 \ ******************************\
36333 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
36334 \ ******************************\
36335 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
36336 XOR @RSP,T \ (new XOR old) Toggle bits
36337 BIT #UF10,T \ repeated RC5_command ?
36338 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
36339 XOR #UF10,0(RSP) \ 5 toggle bit memory
36340 \ ******************************\
36341 \ Display IR_RC5 code \ X = RC5 code
36342 \ ******************************\
36344 MOV &BASE,2(PSP) \ save current base
36345 MOV #$10,&BASE \ set hex base
36346 MOV TOS,0(PSP) \ save TOS
36348 LO2HI \ switch from assembler to FORTH
36349 ['] LCD_CLEAR IS CR \ redirects CR
36350 ['] LCD_WrC IS EMIT \ redirects EMIT
36351 CR ." $" 2 U.R \ print IR_RC5 code
36352 ['] CR >BODY IS CR \ restore CR
36353 ['] EMIT >BODY IS EMIT \ restore EMIT
36354 HI2LO \ switch from FORTH to assembler
36355 MOV TOS,&BASE \ restore current BASE
36357 \ ******************************\
36359 \ ******************************\
36363 \ ------------------------------\
36365 \ ------------------------------\
36366 \ ... \ insert here your background task
36369 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
36370 ADD #4,X \ 1 X = BODY of SLEEP
36373 \ ------------------------------\
36377 \ ------------------------------\
36378 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
36379 \ - - \CNTL Counter lentgh \ 00 = 16 bits
36380 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
36381 \ -- \ID input divider \ 10 = /4
36382 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
36383 \ - \TBCLR TimerB Clear
36386 \ -------------------------------\
36387 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
36388 \ -- \CM Capture Mode
36393 \ --- \OUTMOD \ 011 = set/reset
36399 \ -------------------------------\
36401 \ -------------------------------\
36403 \ ------------------------------\
36404 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
36405 \ ------------------------------\
36406 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
36407 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
36408 \ ------------------------------\
36409 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
36410 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
36411 \ ------------------------------\
36412 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
36413 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
36414 \ ------------------------------\
36415 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
36416 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
36417 \ ------------------------------\
36418 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
36419 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
36420 \ ------------------------------\
36421 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
36422 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
36423 \ ------------------------------\
36424 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
36425 \ ------------------------------\
36426 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
36427 \ ------------------------------\
36428 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
36429 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
36430 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
36431 \ ------------------------------\
36432 BIS.B #LCDVo,&LCDVo_DIR \
36433 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
36434 \ ------------------------------\
36435 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
36436 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
36437 \ ------------------------------\
36438 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
36439 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
36440 \ ******************************\
36442 \ ******************************\
36443 BIS.B #RC5,&IR_IE \ enable RC5_Int
36444 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
36445 MOV #RC5_INT,&IR_Vec \ init interrupt vector
36446 \ ******************************\
36447 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
36448 \ ******************************\
36449 \ %01 0001 0100 \ TAxCTL
36450 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
36451 \ -- \ ID divided by 1
36452 \ -- \ MC MODE = up to TAxCCRn
36453 \ - \ TACLR clear timer count
36456 \ ------------------------------\
36457 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
36458 \ ------------------------------\
36460 \ --- \ TAIDEX pre divisor
36461 \ ------------------------------\
36462 \ %0000 0000 0000 0101 \ TAxCCR0
36463 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
36464 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
36465 \ ------------------------------\
36466 \ %0000 0000 0001 0000 \ TAxCCTL0
36467 \ - \ CAP capture/compare mode = compare
36470 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
36471 \ ------------------------------\
36472 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
36473 \ ------------------------------\
36474 \ define LPM mode for ACCEPT \
36475 \ ------------------------------\
36476 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
36477 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
36478 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
36480 \ ------------------------------\
36481 \ redirects to background task \
36482 \ ------------------------------\
36484 MOV #BACKGROUND,2(X) \
36485 \ ------------------------------\
36487 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
36489 \ ------------------------------\
36491 \ ------------------------------\
36492 $03E8 20_US \ 1- wait 20 ms
36493 $03 TOP_LCD \ 2- send DB5=DB4=1
36494 $CD 20_US \ 3- wait 4,1 ms
36495 $03 TOP_LCD \ 4- send again DB5=DB4=1
36496 $5 20_US \ 5- wait 0,1 ms
36497 $03 TOP_LCD \ 6- send again again DB5=DB4=1
36498 $2 20_US \ wait 40 us = LCD cycle
36499 $02 TOP_LCD \ 7- send DB5=1 DB4=0
36500 $2 20_US \ wait 40 us = LCD cycle
36501 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
36502 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
36503 LCD_Clear \ 10- "LCD_Clear"
36504 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
36505 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
36506 LCD_Clear \ 10- "LCD_Clear"
36507 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
36508 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
36510 ['] CR >BODY IS CR \
36511 ['] EMIT >BODY IS EMIT \
36512 ." RC5toLCD is running. Type STOP to quit"
36513 LIT RECURSE IS WARM \ replace WARM by this START routine
36514 ABORT \ and continue with the next word after WARM...
36515 ; \ ...until interpreter falls in sleep mode within ACCEPT.
36518 CODE STOP \ stops multitasking, must to be used before downloading app
36519 \ restore default action of primary DEFERred word SLEEP, assembly version
36520 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
36521 ADD #4,X \ X = BODY of SLEEP
36522 MOV X,-2(X) \ restore the default background
36525 \ restore default action of primary DEFERred word WARM, FORTH version
36526 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
36528 COLD \ because we want to reset CPU and interrupt vectors
36533 ; downloading RC5toLCD.4th is done
36534 RST_HERE ; this app is protected against <reset>
36542 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
36544 [DEFINED] ASM [IF] \ security test
36548 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
36550 CODE MAX \ n1 n2 -- n3 signed maximum
36551 CMP @PSP,TOS \ n2-n1
36552 S< ?GOTO FW1 \ n2<n1
36558 CODE MIN \ n1 n2 -- n3 signed minimum
36559 CMP @PSP,TOS \ n2-n1
36560 S< ?GOTO BW1 \ n2<n1
36568 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
36569 : U.R \ u n -- display u unsigned in n width (n >= 2)
36571 R> OVER - 0 MAX SPACES TYPE
36576 \ CODE 20_US \ n -- n * 20 us
36577 \ BEGIN \ 3 cycles loop + 6~
36578 \ \ MOV #5,W \ 3 MCLK = 1 MHz
36579 \ \ MOV #23,W \ 3 MCLK = 4 MHz
36580 \ \ MOV #51,W \ 3 MCLK = 8 MHz
36581 \ MOV #104,W \ 3 MCLK = 16 MHz
36582 \ \ MOV #158,W \ 3 MCLK = 24 MHz
36583 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
36588 \ MOV @PSP+,TOS \ 2
36593 CODE 20_US \ n -- n * 20 us
36594 BEGIN \ here we presume that LCD_TIM_IFG = 1...
36596 BIT #1,&LCD_TIM_CTL \ 3
36597 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
36598 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
36600 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
36606 CODE TOP_LCD \ LCD Sample
36607 \ \ if write : %xxxxWWWW --
36608 \ \ if read : -- %0000RRRR
36609 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
36610 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
36611 0= IF \ write LCD bits pattern
36612 AND.B #LCD_DB,TOS \
36613 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
36614 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
36617 THEN \ read LCD bits pattern
36620 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
36621 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
36622 AND.B #LCD_DB,TOS \
36627 CODE LCD_W \ byte -- write byte to LCD
36629 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
36630 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
36631 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
36632 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
36633 COLON \ high level word starts here
36634 TOP_LCD 2 20_US \ write high nibble first
36639 CODE LCD_WrC \ char -- Write Char
36640 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
36645 CODE LCD_WrF \ func -- Write Fonction
36646 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
36652 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
36657 $02 LCD_WrF 100 20_us
36661 [UNDEFINED] OR [IF]
36663 \ https://forth-standard.org/standard/core/OR
36664 \ C OR x1 x2 -- x3 logical OR
36673 : LCD_Entry_set $04 OR LCD_WrF ;
36675 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
36677 : LCD_DSP_Shift $10 OR LCD_WrF ;
36679 : LCD_Fn_Set $20 OR LCD_WrF ;
36681 : LCD_CGRAM_Set $40 OR LCD_WrF ;
36683 : LCD_Goto $80 OR LCD_WrF ;
36685 CODE LCD_R \ -- byte read byte from LCD
36686 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
36687 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
36688 COLON \ starts a FORTH word
36689 TOP_LCD 2 20_us \ -- %0000HHHH
36690 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
36691 HI2LO \ switch from FORTH to assembler
36692 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
36693 ADD.B @PSP+,TOS \ -- %HHHHLLLL
36694 MOV @RSP+,IP \ restore IP saved by COLON
36699 CODE LCD_RdS \ -- status Read Status
36700 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
36705 CODE LCD_RdC \ -- char Read Char
36706 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
36712 \ ******************************\
36713 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
36714 \ ******************************\
36715 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
36716 BIT.B #SW2,&SW2_IN \ test switch S2
36717 0= IF \ case of switch S2 pressed
36718 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
36720 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
36723 BIT.B #SW1,&SW1_IN \ test switch S1 input
36724 0= IF \ case of Switch S1 pressed
36725 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
36727 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
36731 BW1 \ from quit on truncated RC5 message
36732 BW2 \ from repeated RC5 command
36733 BW3 \ from end of RC5_INT
36734 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
36739 \ ******************************\
36740 ASM RC5_INT \ wake up on Px.RC5 change interrupt
36741 \ ******************************\
36742 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
36743 \ ******************************\
36744 \ \ in : SR(9)=old Toggle bit memory (ADD on)
36745 \ \ SMclock = 8|16|24 MHz
36746 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
36747 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
36748 \ \ SR(9)=new Toggle bit memory (ADD on)
36749 \ ******************************\
36750 \ RC5_FirstStartBitHalfCycle: \
36751 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
36752 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
36753 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
36754 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
36755 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
36756 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
36757 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
36758 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
36759 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
36760 MOV #1778,X \ RC5_Period * 1us
36761 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
36762 MOV #14,W \ count of loop
36764 \ ******************************\
36765 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
36766 \ ******************************\ |
36767 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
36768 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
36769 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
36770 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
36771 \ RC5_Compute_3/4_Period: \ |
36772 RRUM #1,X \ X=1/2 cycle |
36775 ADD X,Y \ Y=3/4 cycle
36776 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
36778 \ ******************************\
36779 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
36780 \ ******************************\
36781 BIT.B #RC5,&IR_IN \ C_flag = IR bit
36782 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
36783 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
36784 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
36785 SUB #1,W \ decrement count loop
36786 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
36787 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
36788 0<> WHILE \ ----> out of loop ----+
36789 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
36791 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
36792 CMP Y,X \ 1 | cycle time out of bound ?
36793 U>= IF \ 2 ^ | yes:
36794 BIC #$30,&RC5_TIM_CTL \ | | stop timer
36795 GOTO BW1 \ | | quit on truncated RC5 message
36797 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
36799 REPEAT \ ----> loop back --+ | with X = new RC5_period value
36800 \ ******************************\ |
36801 \ RC5_SampleEndOf: \ <---------------------+
36802 \ ******************************\
36803 BIC #$30,&RC5_TIM_CTL \ stop timer
36804 \ ******************************\
36805 \ RC5_ComputeNewRC5word \
36806 \ ******************************\
36807 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
36808 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
36809 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
36810 \ ******************************\
36811 \ RC5_ComputeC6bit \
36812 \ ******************************\
36813 BIT #BIT14,T \ test /C6 bit in T
36814 0= IF BIS #BIT6,X \ set C6 bit in X
36815 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
36816 \ ******************************\
36817 \ RC5_CommandByteIsDone \ -- BASE RC5_code
36818 \ ******************************\
36819 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
36820 \ ******************************\
36821 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
36822 XOR @RSP,T \ (new XOR old) Toggle bits
36823 BIT #UF10,T \ repeated RC5_command ?
36824 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
36825 XOR #UF10,0(RSP) \ 5 toggle bit memory
36826 \ ******************************\
36827 \ Display IR_RC5 code \ X = RC5 code
36828 \ ******************************\
36830 MOV &BASE,2(PSP) \ save current base
36831 MOV #$10,&BASE \ set hex base
36832 MOV TOS,0(PSP) \ save TOS
36834 LO2HI \ switch from assembler to FORTH
36835 ['] LCD_CLEAR IS CR \ redirects CR
36836 ['] LCD_WrC IS EMIT \ redirects EMIT
36837 CR ." $" 2 U.R \ print IR_RC5 code
36838 ['] CR >BODY IS CR \ restore CR
36839 ['] EMIT >BODY IS EMIT \ restore EMIT
36840 HI2LO \ switch from FORTH to assembler
36841 MOV TOS,&BASE \ restore current BASE
36843 \ ******************************\
36845 \ ******************************\
36849 \ ------------------------------\
36851 \ ------------------------------\
36852 \ ... \ insert here your background task
36855 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
36856 ADD #4,X \ 1 X = BODY of SLEEP
36859 \ ------------------------------\
36863 \ ------------------------------\
36864 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
36865 \ - - \CNTL Counter lentgh \ 00 = 16 bits
36866 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
36867 \ -- \ID input divider \ 10 = /4
36868 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
36869 \ - \TBCLR TimerB Clear
36872 \ -------------------------------\
36873 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
36874 \ -- \CM Capture Mode
36879 \ --- \OUTMOD \ 011 = set/reset
36885 \ -------------------------------\
36887 \ -------------------------------\
36889 \ ------------------------------\
36890 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
36891 \ ------------------------------\
36892 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
36893 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
36894 \ ------------------------------\
36895 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
36896 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
36897 \ ------------------------------\
36898 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
36899 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
36900 \ ------------------------------\
36901 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
36902 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
36903 \ ------------------------------\
36904 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
36905 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
36906 \ ------------------------------\
36907 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
36908 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
36909 \ ------------------------------\
36910 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
36911 \ ------------------------------\
36912 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
36913 \ ------------------------------\
36914 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
36915 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
36916 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
36917 \ ------------------------------\
36918 BIS.B #LCDVo,&LCDVo_DIR \
36919 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
36920 \ ------------------------------\
36921 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
36922 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
36923 \ ------------------------------\
36924 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
36925 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
36926 \ ******************************\
36928 \ ******************************\
36929 BIS.B #RC5,&IR_IE \ enable RC5_Int
36930 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
36931 MOV #RC5_INT,&IR_Vec \ init interrupt vector
36932 \ ******************************\
36933 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
36934 \ ******************************\
36935 \ %01 0001 0100 \ TAxCTL
36936 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
36937 \ -- \ ID divided by 1
36938 \ -- \ MC MODE = up to TAxCCRn
36939 \ - \ TACLR clear timer count
36942 \ ------------------------------\
36943 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
36944 \ ------------------------------\
36946 \ --- \ TAIDEX pre divisor
36947 \ ------------------------------\
36948 \ %0000 0000 0000 0101 \ TAxCCR0
36949 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
36950 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
36951 \ ------------------------------\
36952 \ %0000 0000 0001 0000 \ TAxCCTL0
36953 \ - \ CAP capture/compare mode = compare
36956 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
36957 \ ------------------------------\
36958 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
36959 \ ------------------------------\
36960 \ define LPM mode for ACCEPT \
36961 \ ------------------------------\
36962 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
36963 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
36964 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
36966 \ ------------------------------\
36967 \ redirects to background task \
36968 \ ------------------------------\
36970 MOV #BACKGROUND,2(X) \
36971 \ ------------------------------\
36973 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
36975 \ ------------------------------\
36977 \ ------------------------------\
36978 $03E8 20_US \ 1- wait 20 ms
36979 $03 TOP_LCD \ 2- send DB5=DB4=1
36980 $CD 20_US \ 3- wait 4,1 ms
36981 $03 TOP_LCD \ 4- send again DB5=DB4=1
36982 $5 20_US \ 5- wait 0,1 ms
36983 $03 TOP_LCD \ 6- send again again DB5=DB4=1
36984 $2 20_US \ wait 40 us = LCD cycle
36985 $02 TOP_LCD \ 7- send DB5=1 DB4=0
36986 $2 20_US \ wait 40 us = LCD cycle
36987 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
36988 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
36989 LCD_Clear \ 10- "LCD_Clear"
36990 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
36991 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
36992 LCD_Clear \ 10- "LCD_Clear"
36993 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
36994 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
36996 ['] CR >BODY IS CR \
36997 ['] EMIT >BODY IS EMIT \
36998 ." RC5toLCD is running. Type STOP to quit"
36999 LIT RECURSE IS WARM \ replace WARM by this START routine
37000 ABORT \ and continue with the next word after WARM...
37001 ; \ ...until interpreter falls in sleep mode within ACCEPT.
37004 CODE STOP \ stops multitasking, must to be used before downloading app
37005 \ restore default action of primary DEFERred word SLEEP, assembly version
37006 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
37007 ADD #4,X \ X = BODY of SLEEP
37008 MOV X,-2(X) \ restore the default background
37011 \ restore default action of primary DEFERred word WARM, FORTH version
37012 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
37014 COLD \ because we want to reset CPU and interrupt vectors
37019 ; downloading RC5toLCD.4th is done
37020 RST_HERE ; this app is protected against <reset>
37028 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
37030 [DEFINED] ASM [IF] \ security test
37034 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
37036 CODE MAX \ n1 n2 -- n3 signed maximum
37037 CMP @PSP,TOS \ n2-n1
37038 S< ?GOTO FW1 \ n2<n1
37044 CODE MIN \ n1 n2 -- n3 signed minimum
37045 CMP @PSP,TOS \ n2-n1
37046 S< ?GOTO BW1 \ n2<n1
37054 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
37055 : U.R \ u n -- display u unsigned in n width (n >= 2)
37057 R> OVER - 0 MAX SPACES TYPE
37062 \ CODE 20_US \ n -- n * 20 us
37063 \ BEGIN \ 3 cycles loop + 6~
37064 \ \ MOV #5,W \ 3 MCLK = 1 MHz
37065 \ \ MOV #23,W \ 3 MCLK = 4 MHz
37066 \ \ MOV #51,W \ 3 MCLK = 8 MHz
37067 \ MOV #104,W \ 3 MCLK = 16 MHz
37068 \ \ MOV #158,W \ 3 MCLK = 24 MHz
37069 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
37074 \ MOV @PSP+,TOS \ 2
37079 CODE 20_US \ n -- n * 20 us
37080 BEGIN \ here we presume that LCD_TIM_IFG = 1...
37082 BIT #1,&LCD_TIM_CTL \ 3
37083 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
37084 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
37086 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
37092 CODE TOP_LCD \ LCD Sample
37093 \ \ if write : %xxxxWWWW --
37094 \ \ if read : -- %0000RRRR
37095 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
37096 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
37097 0= IF \ write LCD bits pattern
37098 AND.B #LCD_DB,TOS \
37099 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
37100 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
37103 THEN \ read LCD bits pattern
37106 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
37107 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
37108 AND.B #LCD_DB,TOS \
37113 CODE LCD_W \ byte -- write byte to LCD
37115 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
37116 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
37117 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
37118 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
37119 COLON \ high level word starts here
37120 TOP_LCD 2 20_US \ write high nibble first
37125 CODE LCD_WrC \ char -- Write Char
37126 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
37131 CODE LCD_WrF \ func -- Write Fonction
37132 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
37138 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
37143 $02 LCD_WrF 100 20_us
37147 [UNDEFINED] OR [IF]
37149 \ https://forth-standard.org/standard/core/OR
37150 \ C OR x1 x2 -- x3 logical OR
37159 : LCD_Entry_set $04 OR LCD_WrF ;
37161 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
37163 : LCD_DSP_Shift $10 OR LCD_WrF ;
37165 : LCD_Fn_Set $20 OR LCD_WrF ;
37167 : LCD_CGRAM_Set $40 OR LCD_WrF ;
37169 : LCD_Goto $80 OR LCD_WrF ;
37171 CODE LCD_R \ -- byte read byte from LCD
37172 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
37173 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
37174 COLON \ starts a FORTH word
37175 TOP_LCD 2 20_us \ -- %0000HHHH
37176 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
37177 HI2LO \ switch from FORTH to assembler
37178 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
37179 ADD.B @PSP+,TOS \ -- %HHHHLLLL
37180 MOV @RSP+,IP \ restore IP saved by COLON
37185 CODE LCD_RdS \ -- status Read Status
37186 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
37191 CODE LCD_RdC \ -- char Read Char
37192 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
37198 \ ******************************\
37199 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
37200 \ ******************************\
37201 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
37202 BIT.B #SW2,&SW2_IN \ test switch S2
37203 0= IF \ case of switch S2 pressed
37204 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
37206 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
37209 BIT.B #SW1,&SW1_IN \ test switch S1 input
37210 0= IF \ case of Switch S1 pressed
37211 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
37213 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
37217 BW1 \ from quit on truncated RC5 message
37218 BW2 \ from repeated RC5 command
37219 BW3 \ from end of RC5_INT
37220 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
37225 \ ******************************\
37226 ASM RC5_INT \ wake up on Px.RC5 change interrupt
37227 \ ******************************\
37228 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
37229 \ ******************************\
37230 \ \ in : SR(9)=old Toggle bit memory (ADD on)
37231 \ \ SMclock = 8|16|24 MHz
37232 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
37233 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
37234 \ \ SR(9)=new Toggle bit memory (ADD on)
37235 \ ******************************\
37236 \ RC5_FirstStartBitHalfCycle: \
37237 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
37238 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
37239 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
37240 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
37241 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
37242 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
37243 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
37244 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
37245 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
37246 MOV #1778,X \ RC5_Period * 1us
37247 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
37248 MOV #14,W \ count of loop
37250 \ ******************************\
37251 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
37252 \ ******************************\ |
37253 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
37254 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
37255 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
37256 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
37257 \ RC5_Compute_3/4_Period: \ |
37258 RRUM #1,X \ X=1/2 cycle |
37261 ADD X,Y \ Y=3/4 cycle
37262 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
37264 \ ******************************\
37265 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
37266 \ ******************************\
37267 BIT.B #RC5,&IR_IN \ C_flag = IR bit
37268 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
37269 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
37270 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
37271 SUB #1,W \ decrement count loop
37272 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
37273 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
37274 0<> WHILE \ ----> out of loop ----+
37275 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
37277 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
37278 CMP Y,X \ 1 | cycle time out of bound ?
37279 U>= IF \ 2 ^ | yes:
37280 BIC #$30,&RC5_TIM_CTL \ | | stop timer
37281 GOTO BW1 \ | | quit on truncated RC5 message
37283 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
37285 REPEAT \ ----> loop back --+ | with X = new RC5_period value
37286 \ ******************************\ |
37287 \ RC5_SampleEndOf: \ <---------------------+
37288 \ ******************************\
37289 BIC #$30,&RC5_TIM_CTL \ stop timer
37290 \ ******************************\
37291 \ RC5_ComputeNewRC5word \
37292 \ ******************************\
37293 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
37294 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
37295 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
37296 \ ******************************\
37297 \ RC5_ComputeC6bit \
37298 \ ******************************\
37299 BIT #BIT14,T \ test /C6 bit in T
37300 0= IF BIS #BIT6,X \ set C6 bit in X
37301 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
37302 \ ******************************\
37303 \ RC5_CommandByteIsDone \ -- BASE RC5_code
37304 \ ******************************\
37305 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
37306 \ ******************************\
37307 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
37308 XOR @RSP,T \ (new XOR old) Toggle bits
37309 BIT #UF10,T \ repeated RC5_command ?
37310 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
37311 XOR #UF10,0(RSP) \ 5 toggle bit memory
37312 \ ******************************\
37313 \ Display IR_RC5 code \ X = RC5 code
37314 \ ******************************\
37316 MOV &BASE,2(PSP) \ save current base
37317 MOV #$10,&BASE \ set hex base
37318 MOV TOS,0(PSP) \ save TOS
37320 LO2HI \ switch from assembler to FORTH
37321 ['] LCD_CLEAR IS CR \ redirects CR
37322 ['] LCD_WrC IS EMIT \ redirects EMIT
37323 CR ." $" 2 U.R \ print IR_RC5 code
37324 ['] CR >BODY IS CR \ restore CR
37325 ['] EMIT >BODY IS EMIT \ restore EMIT
37326 HI2LO \ switch from FORTH to assembler
37327 MOV TOS,&BASE \ restore current BASE
37329 \ ******************************\
37331 \ ******************************\
37335 \ ------------------------------\
37337 \ ------------------------------\
37338 \ ... \ insert here your background task
37341 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
37342 ADD #4,X \ 1 X = BODY of SLEEP
37345 \ ------------------------------\
37349 \ ------------------------------\
37350 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
37351 \ - - \CNTL Counter lentgh \ 00 = 16 bits
37352 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
37353 \ -- \ID input divider \ 10 = /4
37354 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
37355 \ - \TBCLR TimerB Clear
37358 \ -------------------------------\
37359 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
37360 \ -- \CM Capture Mode
37365 \ --- \OUTMOD \ 011 = set/reset
37371 \ -------------------------------\
37373 \ -------------------------------\
37375 \ ------------------------------\
37376 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
37377 \ ------------------------------\
37378 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
37379 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
37380 \ ------------------------------\
37381 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
37382 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
37383 \ ------------------------------\
37384 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
37385 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
37386 \ ------------------------------\
37387 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
37388 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
37389 \ ------------------------------\
37390 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
37391 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
37392 \ ------------------------------\
37393 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
37394 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
37395 \ ------------------------------\
37396 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
37397 \ ------------------------------\
37398 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
37399 \ ------------------------------\
37400 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
37401 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
37402 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
37403 \ ------------------------------\
37404 BIS.B #LCDVo,&LCDVo_DIR \
37405 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
37406 \ ------------------------------\
37407 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
37408 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
37409 \ ------------------------------\
37410 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
37411 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
37412 \ ******************************\
37414 \ ******************************\
37415 BIS.B #RC5,&IR_IE \ enable RC5_Int
37416 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
37417 MOV #RC5_INT,&IR_Vec \ init interrupt vector
37418 \ ******************************\
37419 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
37420 \ ******************************\
37421 \ %01 0001 0100 \ TAxCTL
37422 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
37423 \ -- \ ID divided by 1
37424 \ -- \ MC MODE = up to TAxCCRn
37425 \ - \ TACLR clear timer count
37428 \ ------------------------------\
37429 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
37430 \ ------------------------------\
37432 \ --- \ TAIDEX pre divisor
37433 \ ------------------------------\
37434 \ %0000 0000 0000 0101 \ TAxCCR0
37435 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
37436 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
37437 \ ------------------------------\
37438 \ %0000 0000 0001 0000 \ TAxCCTL0
37439 \ - \ CAP capture/compare mode = compare
37442 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
37443 \ ------------------------------\
37444 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
37445 \ ------------------------------\
37446 \ define LPM mode for ACCEPT \
37447 \ ------------------------------\
37448 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
37449 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
37450 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
37452 \ ------------------------------\
37453 \ redirects to background task \
37454 \ ------------------------------\
37456 MOV #BACKGROUND,2(X) \
37457 \ ------------------------------\
37459 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
37461 \ ------------------------------\
37463 \ ------------------------------\
37464 $03E8 20_US \ 1- wait 20 ms
37465 $03 TOP_LCD \ 2- send DB5=DB4=1
37466 $CD 20_US \ 3- wait 4,1 ms
37467 $03 TOP_LCD \ 4- send again DB5=DB4=1
37468 $5 20_US \ 5- wait 0,1 ms
37469 $03 TOP_LCD \ 6- send again again DB5=DB4=1
37470 $2 20_US \ wait 40 us = LCD cycle
37471 $02 TOP_LCD \ 7- send DB5=1 DB4=0
37472 $2 20_US \ wait 40 us = LCD cycle
37473 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
37474 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
37475 LCD_Clear \ 10- "LCD_Clear"
37476 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
37477 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
37478 LCD_Clear \ 10- "LCD_Clear"
37479 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
37480 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
37482 ['] CR >BODY IS CR \
37483 ['] EMIT >BODY IS EMIT \
37484 ." RC5toLCD is running. Type STOP to quit"
37485 LIT RECURSE IS WARM \ replace WARM by this START routine
37486 ABORT \ and continue with the next word after WARM...
37487 ; \ ...until interpreter falls in sleep mode within ACCEPT.
37490 CODE STOP \ stops multitasking, must to be used before downloading app
37491 \ restore default action of primary DEFERred word SLEEP, assembly version
37492 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
37493 ADD #4,X \ X = BODY of SLEEP
37494 MOV X,-2(X) \ restore the default background
37497 \ restore default action of primary DEFERred word WARM, FORTH version
37498 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
37500 COLD \ because we want to reset CPU and interrupt vectors
37505 ; downloading RC5toLCD.4th is done
37506 RST_HERE ; this app is protected against <reset>
37514 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
37516 [DEFINED] ASM [IF] \ security test
37520 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
37522 CODE MAX \ n1 n2 -- n3 signed maximum
37523 CMP @PSP,TOS \ n2-n1
37524 S< ?GOTO FW1 \ n2<n1
37530 CODE MIN \ n1 n2 -- n3 signed minimum
37531 CMP @PSP,TOS \ n2-n1
37532 S< ?GOTO BW1 \ n2<n1
37540 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
37541 : U.R \ u n -- display u unsigned in n width (n >= 2)
37543 R> OVER - 0 MAX SPACES TYPE
37548 \ CODE 20_US \ n -- n * 20 us
37549 \ BEGIN \ 3 cycles loop + 6~
37550 \ \ MOV #5,W \ 3 MCLK = 1 MHz
37551 \ \ MOV #23,W \ 3 MCLK = 4 MHz
37552 \ \ MOV #51,W \ 3 MCLK = 8 MHz
37553 \ MOV #104,W \ 3 MCLK = 16 MHz
37554 \ \ MOV #158,W \ 3 MCLK = 24 MHz
37555 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
37560 \ MOV @PSP+,TOS \ 2
37565 CODE 20_US \ n -- n * 20 us
37566 BEGIN \ here we presume that LCD_TIM_IFG = 1...
37568 BIT #1,&LCD_TIM_CTL \ 3
37569 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
37570 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
37572 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
37578 CODE TOP_LCD \ LCD Sample
37579 \ \ if write : %xxxxWWWW --
37580 \ \ if read : -- %0000RRRR
37581 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
37582 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
37583 0= IF \ write LCD bits pattern
37584 AND.B #LCD_DB,TOS \
37585 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
37586 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
37589 THEN \ read LCD bits pattern
37592 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
37593 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
37594 AND.B #LCD_DB,TOS \
37599 CODE LCD_W \ byte -- write byte to LCD
37601 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
37602 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
37603 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
37604 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
37605 COLON \ high level word starts here
37606 TOP_LCD 2 20_US \ write high nibble first
37611 CODE LCD_WrC \ char -- Write Char
37612 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
37617 CODE LCD_WrF \ func -- Write Fonction
37618 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
37624 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
37629 $02 LCD_WrF 100 20_us
37633 [UNDEFINED] OR [IF]
37635 \ https://forth-standard.org/standard/core/OR
37636 \ C OR x1 x2 -- x3 logical OR
37645 : LCD_Entry_set $04 OR LCD_WrF ;
37647 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
37649 : LCD_DSP_Shift $10 OR LCD_WrF ;
37651 : LCD_Fn_Set $20 OR LCD_WrF ;
37653 : LCD_CGRAM_Set $40 OR LCD_WrF ;
37655 : LCD_Goto $80 OR LCD_WrF ;
37657 CODE LCD_R \ -- byte read byte from LCD
37658 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
37659 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
37660 COLON \ starts a FORTH word
37661 TOP_LCD 2 20_us \ -- %0000HHHH
37662 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
37663 HI2LO \ switch from FORTH to assembler
37664 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
37665 ADD.B @PSP+,TOS \ -- %HHHHLLLL
37666 MOV @RSP+,IP \ restore IP saved by COLON
37671 CODE LCD_RdS \ -- status Read Status
37672 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
37677 CODE LCD_RdC \ -- char Read Char
37678 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
37684 \ ******************************\
37685 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
37686 \ ******************************\
37687 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
37688 BIT.B #SW2,&SW2_IN \ test switch S2
37689 0= IF \ case of switch S2 pressed
37690 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
37692 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
37695 BIT.B #SW1,&SW1_IN \ test switch S1 input
37696 0= IF \ case of Switch S1 pressed
37697 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
37699 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
37703 BW1 \ from quit on truncated RC5 message
37704 BW2 \ from repeated RC5 command
37705 BW3 \ from end of RC5_INT
37706 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
37711 \ ******************************\
37712 ASM RC5_INT \ wake up on Px.RC5 change interrupt
37713 \ ******************************\
37714 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
37715 \ ******************************\
37716 \ \ in : SR(9)=old Toggle bit memory (ADD on)
37717 \ \ SMclock = 8|16|24 MHz
37718 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
37719 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
37720 \ \ SR(9)=new Toggle bit memory (ADD on)
37721 \ ******************************\
37722 \ RC5_FirstStartBitHalfCycle: \
37723 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
37724 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
37725 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
37726 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
37727 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
37728 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
37729 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
37730 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
37731 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
37732 MOV #1778,X \ RC5_Period * 1us
37733 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
37734 MOV #14,W \ count of loop
37736 \ ******************************\
37737 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
37738 \ ******************************\ |
37739 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
37740 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
37741 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
37742 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
37743 \ RC5_Compute_3/4_Period: \ |
37744 RRUM #1,X \ X=1/2 cycle |
37747 ADD X,Y \ Y=3/4 cycle
37748 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
37750 \ ******************************\
37751 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
37752 \ ******************************\
37753 BIT.B #RC5,&IR_IN \ C_flag = IR bit
37754 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
37755 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
37756 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
37757 SUB #1,W \ decrement count loop
37758 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
37759 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
37760 0<> WHILE \ ----> out of loop ----+
37761 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
37763 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
37764 CMP Y,X \ 1 | cycle time out of bound ?
37765 U>= IF \ 2 ^ | yes:
37766 BIC #$30,&RC5_TIM_CTL \ | | stop timer
37767 GOTO BW1 \ | | quit on truncated RC5 message
37769 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
37771 REPEAT \ ----> loop back --+ | with X = new RC5_period value
37772 \ ******************************\ |
37773 \ RC5_SampleEndOf: \ <---------------------+
37774 \ ******************************\
37775 BIC #$30,&RC5_TIM_CTL \ stop timer
37776 \ ******************************\
37777 \ RC5_ComputeNewRC5word \
37778 \ ******************************\
37779 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
37780 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
37781 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
37782 \ ******************************\
37783 \ RC5_ComputeC6bit \
37784 \ ******************************\
37785 BIT #BIT14,T \ test /C6 bit in T
37786 0= IF BIS #BIT6,X \ set C6 bit in X
37787 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
37788 \ ******************************\
37789 \ RC5_CommandByteIsDone \ -- BASE RC5_code
37790 \ ******************************\
37791 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
37792 \ ******************************\
37793 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
37794 XOR @RSP,T \ (new XOR old) Toggle bits
37795 BIT #UF10,T \ repeated RC5_command ?
37796 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
37797 XOR #UF10,0(RSP) \ 5 toggle bit memory
37798 \ ******************************\
37799 \ Display IR_RC5 code \ X = RC5 code
37800 \ ******************************\
37802 MOV &BASE,2(PSP) \ save current base
37803 MOV #$10,&BASE \ set hex base
37804 MOV TOS,0(PSP) \ save TOS
37806 LO2HI \ switch from assembler to FORTH
37807 ['] LCD_CLEAR IS CR \ redirects CR
37808 ['] LCD_WrC IS EMIT \ redirects EMIT
37809 CR ." $" 2 U.R \ print IR_RC5 code
37810 ['] CR >BODY IS CR \ restore CR
37811 ['] EMIT >BODY IS EMIT \ restore EMIT
37812 HI2LO \ switch from FORTH to assembler
37813 MOV TOS,&BASE \ restore current BASE
37815 \ ******************************\
37817 \ ******************************\
37821 \ ------------------------------\
37823 \ ------------------------------\
37824 \ ... \ insert here your background task
37827 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
37828 ADD #4,X \ 1 X = BODY of SLEEP
37831 \ ------------------------------\
37835 \ ------------------------------\
37836 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
37837 \ - - \CNTL Counter lentgh \ 00 = 16 bits
37838 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
37839 \ -- \ID input divider \ 10 = /4
37840 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
37841 \ - \TBCLR TimerB Clear
37844 \ -------------------------------\
37845 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
37846 \ -- \CM Capture Mode
37851 \ --- \OUTMOD \ 011 = set/reset
37857 \ -------------------------------\
37859 \ -------------------------------\
37861 \ ------------------------------\
37862 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
37863 \ ------------------------------\
37864 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
37865 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
37866 \ ------------------------------\
37867 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
37868 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
37869 \ ------------------------------\
37870 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
37871 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
37872 \ ------------------------------\
37873 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
37874 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
37875 \ ------------------------------\
37876 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
37877 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
37878 \ ------------------------------\
37879 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
37880 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
37881 \ ------------------------------\
37882 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
37883 \ ------------------------------\
37884 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
37885 \ ------------------------------\
37886 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
37887 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
37888 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
37889 \ ------------------------------\
37890 BIS.B #LCDVo,&LCDVo_DIR \
37891 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
37892 \ ------------------------------\
37893 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
37894 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
37895 \ ------------------------------\
37896 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
37897 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
37898 \ ******************************\
37900 \ ******************************\
37901 BIS.B #RC5,&IR_IE \ enable RC5_Int
37902 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
37903 MOV #RC5_INT,&IR_Vec \ init interrupt vector
37904 \ ******************************\
37905 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
37906 \ ******************************\
37907 \ %01 0001 0100 \ TAxCTL
37908 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
37909 \ -- \ ID divided by 1
37910 \ -- \ MC MODE = up to TAxCCRn
37911 \ - \ TACLR clear timer count
37914 \ ------------------------------\
37915 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
37916 \ ------------------------------\
37918 \ --- \ TAIDEX pre divisor
37919 \ ------------------------------\
37920 \ %0000 0000 0000 0101 \ TAxCCR0
37921 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
37922 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
37923 \ ------------------------------\
37924 \ %0000 0000 0001 0000 \ TAxCCTL0
37925 \ - \ CAP capture/compare mode = compare
37928 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
37929 \ ------------------------------\
37930 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
37931 \ ------------------------------\
37932 \ define LPM mode for ACCEPT \
37933 \ ------------------------------\
37934 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
37935 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
37936 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
37938 \ ------------------------------\
37939 \ redirects to background task \
37940 \ ------------------------------\
37942 MOV #BACKGROUND,2(X) \
37943 \ ------------------------------\
37945 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
37947 \ ------------------------------\
37949 \ ------------------------------\
37950 $03E8 20_US \ 1- wait 20 ms
37951 $03 TOP_LCD \ 2- send DB5=DB4=1
37952 $CD 20_US \ 3- wait 4,1 ms
37953 $03 TOP_LCD \ 4- send again DB5=DB4=1
37954 $5 20_US \ 5- wait 0,1 ms
37955 $03 TOP_LCD \ 6- send again again DB5=DB4=1
37956 $2 20_US \ wait 40 us = LCD cycle
37957 $02 TOP_LCD \ 7- send DB5=1 DB4=0
37958 $2 20_US \ wait 40 us = LCD cycle
37959 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
37960 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
37961 LCD_Clear \ 10- "LCD_Clear"
37962 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
37963 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
37964 LCD_Clear \ 10- "LCD_Clear"
37965 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
37966 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
37968 ['] CR >BODY IS CR \
37969 ['] EMIT >BODY IS EMIT \
37970 ." RC5toLCD is running. Type STOP to quit"
37971 LIT RECURSE IS WARM \ replace WARM by this START routine
37972 ABORT \ and continue with the next word after WARM...
37973 ; \ ...until interpreter falls in sleep mode within ACCEPT.
37976 CODE STOP \ stops multitasking, must to be used before downloading app
37977 \ restore default action of primary DEFERred word SLEEP, assembly version
37978 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
37979 ADD #4,X \ X = BODY of SLEEP
37980 MOV X,-2(X) \ restore the default background
37983 \ restore default action of primary DEFERred word WARM, FORTH version
37984 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
37986 COLD \ because we want to reset CPU and interrupt vectors
37991 ; downloading RC5toLCD.4th is done
37992 RST_HERE ; this app is protected against <reset>
38000 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
38002 [DEFINED] ASM [IF] \ security test
38006 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
38008 CODE MAX \ n1 n2 -- n3 signed maximum
38009 CMP @PSP,TOS \ n2-n1
38010 S< ?GOTO FW1 \ n2<n1
38016 CODE MIN \ n1 n2 -- n3 signed minimum
38017 CMP @PSP,TOS \ n2-n1
38018 S< ?GOTO BW1 \ n2<n1
38026 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
38027 : U.R \ u n -- display u unsigned in n width (n >= 2)
38029 R> OVER - 0 MAX SPACES TYPE
38034 \ CODE 20_US \ n -- n * 20 us
38035 \ BEGIN \ 3 cycles loop + 6~
38036 \ \ MOV #5,W \ 3 MCLK = 1 MHz
38037 \ \ MOV #23,W \ 3 MCLK = 4 MHz
38038 \ \ MOV #51,W \ 3 MCLK = 8 MHz
38039 \ MOV #104,W \ 3 MCLK = 16 MHz
38040 \ \ MOV #158,W \ 3 MCLK = 24 MHz
38041 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
38046 \ MOV @PSP+,TOS \ 2
38051 CODE 20_US \ n -- n * 20 us
38052 BEGIN \ here we presume that LCD_TIM_IFG = 1...
38054 BIT #1,&LCD_TIM_CTL \ 3
38055 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
38056 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
38058 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
38064 CODE TOP_LCD \ LCD Sample
38065 \ \ if write : %xxxxWWWW --
38066 \ \ if read : -- %0000RRRR
38067 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
38068 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
38069 0= IF \ write LCD bits pattern
38070 AND.B #LCD_DB,TOS \
38071 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
38072 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
38075 THEN \ read LCD bits pattern
38078 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
38079 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
38080 AND.B #LCD_DB,TOS \
38085 CODE LCD_W \ byte -- write byte to LCD
38087 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
38088 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
38089 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
38090 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
38091 COLON \ high level word starts here
38092 TOP_LCD 2 20_US \ write high nibble first
38097 CODE LCD_WrC \ char -- Write Char
38098 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
38103 CODE LCD_WrF \ func -- Write Fonction
38104 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
38110 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
38115 $02 LCD_WrF 100 20_us
38119 [UNDEFINED] OR [IF]
38121 \ https://forth-standard.org/standard/core/OR
38122 \ C OR x1 x2 -- x3 logical OR
38131 : LCD_Entry_set $04 OR LCD_WrF ;
38133 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
38135 : LCD_DSP_Shift $10 OR LCD_WrF ;
38137 : LCD_Fn_Set $20 OR LCD_WrF ;
38139 : LCD_CGRAM_Set $40 OR LCD_WrF ;
38141 : LCD_Goto $80 OR LCD_WrF ;
38143 CODE LCD_R \ -- byte read byte from LCD
38144 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
38145 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
38146 COLON \ starts a FORTH word
38147 TOP_LCD 2 20_us \ -- %0000HHHH
38148 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
38149 HI2LO \ switch from FORTH to assembler
38150 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
38151 ADD.B @PSP+,TOS \ -- %HHHHLLLL
38152 MOV @RSP+,IP \ restore IP saved by COLON
38157 CODE LCD_RdS \ -- status Read Status
38158 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
38163 CODE LCD_RdC \ -- char Read Char
38164 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
38170 \ ******************************\
38171 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
38172 \ ******************************\
38173 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
38174 BIT.B #SW2,&SW2_IN \ test switch S2
38175 0= IF \ case of switch S2 pressed
38176 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
38178 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
38181 BIT.B #SW1,&SW1_IN \ test switch S1 input
38182 0= IF \ case of Switch S1 pressed
38183 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
38185 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
38189 BW1 \ from quit on truncated RC5 message
38190 BW2 \ from repeated RC5 command
38191 BW3 \ from end of RC5_INT
38192 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
38197 \ ******************************\
38198 ASM RC5_INT \ wake up on Px.RC5 change interrupt
38199 \ ******************************\
38200 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
38201 \ ******************************\
38202 \ \ in : SR(9)=old Toggle bit memory (ADD on)
38203 \ \ SMclock = 8|16|24 MHz
38204 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
38205 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
38206 \ \ SR(9)=new Toggle bit memory (ADD on)
38207 \ ******************************\
38208 \ RC5_FirstStartBitHalfCycle: \
38209 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
38210 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
38211 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
38212 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
38213 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
38214 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
38215 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
38216 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
38217 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
38218 MOV #1778,X \ RC5_Period * 1us
38219 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
38220 MOV #14,W \ count of loop
38222 \ ******************************\
38223 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
38224 \ ******************************\ |
38225 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
38226 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
38227 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
38228 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
38229 \ RC5_Compute_3/4_Period: \ |
38230 RRUM #1,X \ X=1/2 cycle |
38233 ADD X,Y \ Y=3/4 cycle
38234 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
38236 \ ******************************\
38237 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
38238 \ ******************************\
38239 BIT.B #RC5,&IR_IN \ C_flag = IR bit
38240 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
38241 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
38242 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
38243 SUB #1,W \ decrement count loop
38244 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
38245 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
38246 0<> WHILE \ ----> out of loop ----+
38247 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
38249 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
38250 CMP Y,X \ 1 | cycle time out of bound ?
38251 U>= IF \ 2 ^ | yes:
38252 BIC #$30,&RC5_TIM_CTL \ | | stop timer
38253 GOTO BW1 \ | | quit on truncated RC5 message
38255 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
38257 REPEAT \ ----> loop back --+ | with X = new RC5_period value
38258 \ ******************************\ |
38259 \ RC5_SampleEndOf: \ <---------------------+
38260 \ ******************************\
38261 BIC #$30,&RC5_TIM_CTL \ stop timer
38262 \ ******************************\
38263 \ RC5_ComputeNewRC5word \
38264 \ ******************************\
38265 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
38266 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
38267 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
38268 \ ******************************\
38269 \ RC5_ComputeC6bit \
38270 \ ******************************\
38271 BIT #BIT14,T \ test /C6 bit in T
38272 0= IF BIS #BIT6,X \ set C6 bit in X
38273 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
38274 \ ******************************\
38275 \ RC5_CommandByteIsDone \ -- BASE RC5_code
38276 \ ******************************\
38277 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
38278 \ ******************************\
38279 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
38280 XOR @RSP,T \ (new XOR old) Toggle bits
38281 BIT #UF10,T \ repeated RC5_command ?
38282 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
38283 XOR #UF10,0(RSP) \ 5 toggle bit memory
38284 \ ******************************\
38285 \ Display IR_RC5 code \ X = RC5 code
38286 \ ******************************\
38288 MOV &BASE,2(PSP) \ save current base
38289 MOV #$10,&BASE \ set hex base
38290 MOV TOS,0(PSP) \ save TOS
38292 LO2HI \ switch from assembler to FORTH
38293 ['] LCD_CLEAR IS CR \ redirects CR
38294 ['] LCD_WrC IS EMIT \ redirects EMIT
38295 CR ." $" 2 U.R \ print IR_RC5 code
38296 ['] CR >BODY IS CR \ restore CR
38297 ['] EMIT >BODY IS EMIT \ restore EMIT
38298 HI2LO \ switch from FORTH to assembler
38299 MOV TOS,&BASE \ restore current BASE
38301 \ ******************************\
38303 \ ******************************\
38307 \ ------------------------------\
38309 \ ------------------------------\
38310 \ ... \ insert here your background task
38313 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
38314 ADD #4,X \ 1 X = BODY of SLEEP
38317 \ ------------------------------\
38321 \ ------------------------------\
38322 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
38323 \ - - \CNTL Counter lentgh \ 00 = 16 bits
38324 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
38325 \ -- \ID input divider \ 10 = /4
38326 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
38327 \ - \TBCLR TimerB Clear
38330 \ -------------------------------\
38331 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
38332 \ -- \CM Capture Mode
38337 \ --- \OUTMOD \ 011 = set/reset
38343 \ -------------------------------\
38345 \ -------------------------------\
38347 \ ------------------------------\
38348 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
38349 \ ------------------------------\
38350 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
38351 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
38352 \ ------------------------------\
38353 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
38354 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
38355 \ ------------------------------\
38356 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
38357 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
38358 \ ------------------------------\
38359 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
38360 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
38361 \ ------------------------------\
38362 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
38363 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
38364 \ ------------------------------\
38365 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
38366 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
38367 \ ------------------------------\
38368 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
38369 \ ------------------------------\
38370 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
38371 \ ------------------------------\
38372 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
38373 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
38374 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
38375 \ ------------------------------\
38376 BIS.B #LCDVo,&LCDVo_DIR \
38377 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
38378 \ ------------------------------\
38379 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
38380 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
38381 \ ------------------------------\
38382 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
38383 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
38384 \ ******************************\
38386 \ ******************************\
38387 BIS.B #RC5,&IR_IE \ enable RC5_Int
38388 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
38389 MOV #RC5_INT,&IR_Vec \ init interrupt vector
38390 \ ******************************\
38391 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
38392 \ ******************************\
38393 \ %01 0001 0100 \ TAxCTL
38394 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
38395 \ -- \ ID divided by 1
38396 \ -- \ MC MODE = up to TAxCCRn
38397 \ - \ TACLR clear timer count
38400 \ ------------------------------\
38401 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
38402 \ ------------------------------\
38404 \ --- \ TAIDEX pre divisor
38405 \ ------------------------------\
38406 \ %0000 0000 0000 0101 \ TAxCCR0
38407 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
38408 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
38409 \ ------------------------------\
38410 \ %0000 0000 0001 0000 \ TAxCCTL0
38411 \ - \ CAP capture/compare mode = compare
38414 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
38415 \ ------------------------------\
38416 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
38417 \ ------------------------------\
38418 \ define LPM mode for ACCEPT \
38419 \ ------------------------------\
38420 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
38421 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
38422 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
38424 \ ------------------------------\
38425 \ redirects to background task \
38426 \ ------------------------------\
38428 MOV #BACKGROUND,2(X) \
38429 \ ------------------------------\
38431 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
38433 \ ------------------------------\
38435 \ ------------------------------\
38436 $03E8 20_US \ 1- wait 20 ms
38437 $03 TOP_LCD \ 2- send DB5=DB4=1
38438 $CD 20_US \ 3- wait 4,1 ms
38439 $03 TOP_LCD \ 4- send again DB5=DB4=1
38440 $5 20_US \ 5- wait 0,1 ms
38441 $03 TOP_LCD \ 6- send again again DB5=DB4=1
38442 $2 20_US \ wait 40 us = LCD cycle
38443 $02 TOP_LCD \ 7- send DB5=1 DB4=0
38444 $2 20_US \ wait 40 us = LCD cycle
38445 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
38446 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
38447 LCD_Clear \ 10- "LCD_Clear"
38448 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
38449 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
38450 LCD_Clear \ 10- "LCD_Clear"
38451 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
38452 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
38454 ['] CR >BODY IS CR \
38455 ['] EMIT >BODY IS EMIT \
38456 ." RC5toLCD is running. Type STOP to quit"
38457 LIT RECURSE IS WARM \ replace WARM by this START routine
38458 ABORT \ and continue with the next word after WARM...
38459 ; \ ...until interpreter falls in sleep mode within ACCEPT.
38462 CODE STOP \ stops multitasking, must to be used before downloading app
38463 \ restore default action of primary DEFERred word SLEEP, assembly version
38464 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
38465 ADD #4,X \ X = BODY of SLEEP
38466 MOV X,-2(X) \ restore the default background
38469 \ restore default action of primary DEFERred word WARM, FORTH version
38470 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
38472 COLD \ because we want to reset CPU and interrupt vectors
38477 ; downloading RC5toLCD.4th is done
38478 RST_HERE ; this app is protected against <reset>
38486 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
38488 [DEFINED] ASM [IF] \ security test
38492 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
38494 CODE MAX \ n1 n2 -- n3 signed maximum
38495 CMP @PSP,TOS \ n2-n1
38496 S< ?GOTO FW1 \ n2<n1
38502 CODE MIN \ n1 n2 -- n3 signed minimum
38503 CMP @PSP,TOS \ n2-n1
38504 S< ?GOTO BW1 \ n2<n1
38512 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
38513 : U.R \ u n -- display u unsigned in n width (n >= 2)
38515 R> OVER - 0 MAX SPACES TYPE
38520 \ CODE 20_US \ n -- n * 20 us
38521 \ BEGIN \ 3 cycles loop + 6~
38522 \ \ MOV #5,W \ 3 MCLK = 1 MHz
38523 \ \ MOV #23,W \ 3 MCLK = 4 MHz
38524 \ \ MOV #51,W \ 3 MCLK = 8 MHz
38525 \ MOV #104,W \ 3 MCLK = 16 MHz
38526 \ \ MOV #158,W \ 3 MCLK = 24 MHz
38527 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
38532 \ MOV @PSP+,TOS \ 2
38537 CODE 20_US \ n -- n * 20 us
38538 BEGIN \ here we presume that LCD_TIM_IFG = 1...
38540 BIT #1,&LCD_TIM_CTL \ 3
38541 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
38542 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
38544 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
38550 CODE TOP_LCD \ LCD Sample
38551 \ \ if write : %xxxxWWWW --
38552 \ \ if read : -- %0000RRRR
38553 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
38554 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
38555 0= IF \ write LCD bits pattern
38556 AND.B #LCD_DB,TOS \
38557 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
38558 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
38561 THEN \ read LCD bits pattern
38564 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
38565 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
38566 AND.B #LCD_DB,TOS \
38571 CODE LCD_W \ byte -- write byte to LCD
38573 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
38574 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
38575 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
38576 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
38577 COLON \ high level word starts here
38578 TOP_LCD 2 20_US \ write high nibble first
38583 CODE LCD_WrC \ char -- Write Char
38584 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
38589 CODE LCD_WrF \ func -- Write Fonction
38590 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
38596 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
38601 $02 LCD_WrF 100 20_us
38605 [UNDEFINED] OR [IF]
38607 \ https://forth-standard.org/standard/core/OR
38608 \ C OR x1 x2 -- x3 logical OR
38617 : LCD_Entry_set $04 OR LCD_WrF ;
38619 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
38621 : LCD_DSP_Shift $10 OR LCD_WrF ;
38623 : LCD_Fn_Set $20 OR LCD_WrF ;
38625 : LCD_CGRAM_Set $40 OR LCD_WrF ;
38627 : LCD_Goto $80 OR LCD_WrF ;
38629 CODE LCD_R \ -- byte read byte from LCD
38630 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
38631 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
38632 COLON \ starts a FORTH word
38633 TOP_LCD 2 20_us \ -- %0000HHHH
38634 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
38635 HI2LO \ switch from FORTH to assembler
38636 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
38637 ADD.B @PSP+,TOS \ -- %HHHHLLLL
38638 MOV @RSP+,IP \ restore IP saved by COLON
38643 CODE LCD_RdS \ -- status Read Status
38644 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
38649 CODE LCD_RdC \ -- char Read Char
38650 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
38656 \ ******************************\
38657 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
38658 \ ******************************\
38659 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
38660 BIT.B #SW2,&SW2_IN \ test switch S2
38661 0= IF \ case of switch S2 pressed
38662 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
38664 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
38667 BIT.B #SW1,&SW1_IN \ test switch S1 input
38668 0= IF \ case of Switch S1 pressed
38669 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
38671 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
38675 BW1 \ from quit on truncated RC5 message
38676 BW2 \ from repeated RC5 command
38677 BW3 \ from end of RC5_INT
38678 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
38683 \ ******************************\
38684 ASM RC5_INT \ wake up on Px.RC5 change interrupt
38685 \ ******************************\
38686 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
38687 \ ******************************\
38688 \ \ in : SR(9)=old Toggle bit memory (ADD on)
38689 \ \ SMclock = 8|16|24 MHz
38690 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
38691 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
38692 \ \ SR(9)=new Toggle bit memory (ADD on)
38693 \ ******************************\
38694 \ RC5_FirstStartBitHalfCycle: \
38695 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
38696 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
38697 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
38698 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
38699 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
38700 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
38701 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
38702 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
38703 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
38704 MOV #1778,X \ RC5_Period * 1us
38705 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
38706 MOV #14,W \ count of loop
38708 \ ******************************\
38709 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
38710 \ ******************************\ |
38711 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
38712 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
38713 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
38714 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
38715 \ RC5_Compute_3/4_Period: \ |
38716 RRUM #1,X \ X=1/2 cycle |
38719 ADD X,Y \ Y=3/4 cycle
38720 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
38722 \ ******************************\
38723 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
38724 \ ******************************\
38725 BIT.B #RC5,&IR_IN \ C_flag = IR bit
38726 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
38727 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
38728 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
38729 SUB #1,W \ decrement count loop
38730 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
38731 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
38732 0<> WHILE \ ----> out of loop ----+
38733 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
38735 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
38736 CMP Y,X \ 1 | cycle time out of bound ?
38737 U>= IF \ 2 ^ | yes:
38738 BIC #$30,&RC5_TIM_CTL \ | | stop timer
38739 GOTO BW1 \ | | quit on truncated RC5 message
38741 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
38743 REPEAT \ ----> loop back --+ | with X = new RC5_period value
38744 \ ******************************\ |
38745 \ RC5_SampleEndOf: \ <---------------------+
38746 \ ******************************\
38747 BIC #$30,&RC5_TIM_CTL \ stop timer
38748 \ ******************************\
38749 \ RC5_ComputeNewRC5word \
38750 \ ******************************\
38751 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
38752 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
38753 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
38754 \ ******************************\
38755 \ RC5_ComputeC6bit \
38756 \ ******************************\
38757 BIT #BIT14,T \ test /C6 bit in T
38758 0= IF BIS #BIT6,X \ set C6 bit in X
38759 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
38760 \ ******************************\
38761 \ RC5_CommandByteIsDone \ -- BASE RC5_code
38762 \ ******************************\
38763 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
38764 \ ******************************\
38765 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
38766 XOR @RSP,T \ (new XOR old) Toggle bits
38767 BIT #UF10,T \ repeated RC5_command ?
38768 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
38769 XOR #UF10,0(RSP) \ 5 toggle bit memory
38770 \ ******************************\
38771 \ Display IR_RC5 code \ X = RC5 code
38772 \ ******************************\
38774 MOV &BASE,2(PSP) \ save current base
38775 MOV #$10,&BASE \ set hex base
38776 MOV TOS,0(PSP) \ save TOS
38778 LO2HI \ switch from assembler to FORTH
38779 ['] LCD_CLEAR IS CR \ redirects CR
38780 ['] LCD_WrC IS EMIT \ redirects EMIT
38781 CR ." $" 2 U.R \ print IR_RC5 code
38782 ['] CR >BODY IS CR \ restore CR
38783 ['] EMIT >BODY IS EMIT \ restore EMIT
38784 HI2LO \ switch from FORTH to assembler
38785 MOV TOS,&BASE \ restore current BASE
38787 \ ******************************\
38789 \ ******************************\
38793 \ ------------------------------\
38795 \ ------------------------------\
38796 \ ... \ insert here your background task
38799 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
38800 ADD #4,X \ 1 X = BODY of SLEEP
38803 \ ------------------------------\
38807 \ ------------------------------\
38808 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
38809 \ - - \CNTL Counter lentgh \ 00 = 16 bits
38810 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
38811 \ -- \ID input divider \ 10 = /4
38812 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
38813 \ - \TBCLR TimerB Clear
38816 \ -------------------------------\
38817 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
38818 \ -- \CM Capture Mode
38823 \ --- \OUTMOD \ 011 = set/reset
38829 \ -------------------------------\
38831 \ -------------------------------\
38833 \ ------------------------------\
38834 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
38835 \ ------------------------------\
38836 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
38837 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
38838 \ ------------------------------\
38839 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
38840 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
38841 \ ------------------------------\
38842 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
38843 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
38844 \ ------------------------------\
38845 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
38846 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
38847 \ ------------------------------\
38848 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
38849 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
38850 \ ------------------------------\
38851 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
38852 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
38853 \ ------------------------------\
38854 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
38855 \ ------------------------------\
38856 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
38857 \ ------------------------------\
38858 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
38859 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
38860 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
38861 \ ------------------------------\
38862 BIS.B #LCDVo,&LCDVo_DIR \
38863 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
38864 \ ------------------------------\
38865 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
38866 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
38867 \ ------------------------------\
38868 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
38869 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
38870 \ ******************************\
38872 \ ******************************\
38873 BIS.B #RC5,&IR_IE \ enable RC5_Int
38874 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
38875 MOV #RC5_INT,&IR_Vec \ init interrupt vector
38876 \ ******************************\
38877 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
38878 \ ******************************\
38879 \ %01 0001 0100 \ TAxCTL
38880 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
38881 \ -- \ ID divided by 1
38882 \ -- \ MC MODE = up to TAxCCRn
38883 \ - \ TACLR clear timer count
38886 \ ------------------------------\
38887 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
38888 \ ------------------------------\
38890 \ --- \ TAIDEX pre divisor
38891 \ ------------------------------\
38892 \ %0000 0000 0000 0101 \ TAxCCR0
38893 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
38894 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
38895 \ ------------------------------\
38896 \ %0000 0000 0001 0000 \ TAxCCTL0
38897 \ - \ CAP capture/compare mode = compare
38900 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
38901 \ ------------------------------\
38902 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
38903 \ ------------------------------\
38904 \ define LPM mode for ACCEPT \
38905 \ ------------------------------\
38906 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
38907 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
38908 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
38910 \ ------------------------------\
38911 \ redirects to background task \
38912 \ ------------------------------\
38914 MOV #BACKGROUND,2(X) \
38915 \ ------------------------------\
38917 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
38919 \ ------------------------------\
38921 \ ------------------------------\
38922 $03E8 20_US \ 1- wait 20 ms
38923 $03 TOP_LCD \ 2- send DB5=DB4=1
38924 $CD 20_US \ 3- wait 4,1 ms
38925 $03 TOP_LCD \ 4- send again DB5=DB4=1
38926 $5 20_US \ 5- wait 0,1 ms
38927 $03 TOP_LCD \ 6- send again again DB5=DB4=1
38928 $2 20_US \ wait 40 us = LCD cycle
38929 $02 TOP_LCD \ 7- send DB5=1 DB4=0
38930 $2 20_US \ wait 40 us = LCD cycle
38931 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
38932 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
38933 LCD_Clear \ 10- "LCD_Clear"
38934 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
38935 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
38936 LCD_Clear \ 10- "LCD_Clear"
38937 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
38938 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
38940 ['] CR >BODY IS CR \
38941 ['] EMIT >BODY IS EMIT \
38942 ." RC5toLCD is running. Type STOP to quit"
38943 LIT RECURSE IS WARM \ replace WARM by this START routine
38944 ABORT \ and continue with the next word after WARM...
38945 ; \ ...until interpreter falls in sleep mode within ACCEPT.
38948 CODE STOP \ stops multitasking, must to be used before downloading app
38949 \ restore default action of primary DEFERred word SLEEP, assembly version
38950 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
38951 ADD #4,X \ X = BODY of SLEEP
38952 MOV X,-2(X) \ restore the default background
38955 \ restore default action of primary DEFERred word WARM, FORTH version
38956 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
38958 COLD \ because we want to reset CPU and interrupt vectors
38963 ; downloading RC5toLCD.4th is done
38964 RST_HERE ; this app is protected against <reset>
38972 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
38974 [DEFINED] ASM [IF] \ security test
38978 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
38980 CODE MAX \ n1 n2 -- n3 signed maximum
38981 CMP @PSP,TOS \ n2-n1
38982 S< ?GOTO FW1 \ n2<n1
38988 CODE MIN \ n1 n2 -- n3 signed minimum
38989 CMP @PSP,TOS \ n2-n1
38990 S< ?GOTO BW1 \ n2<n1
38998 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
38999 : U.R \ u n -- display u unsigned in n width (n >= 2)
39001 R> OVER - 0 MAX SPACES TYPE
39006 \ CODE 20_US \ n -- n * 20 us
39007 \ BEGIN \ 3 cycles loop + 6~
39008 \ \ MOV #5,W \ 3 MCLK = 1 MHz
39009 \ \ MOV #23,W \ 3 MCLK = 4 MHz
39010 \ \ MOV #51,W \ 3 MCLK = 8 MHz
39011 \ MOV #104,W \ 3 MCLK = 16 MHz
39012 \ \ MOV #158,W \ 3 MCLK = 24 MHz
39013 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
39018 \ MOV @PSP+,TOS \ 2
39023 CODE 20_US \ n -- n * 20 us
39024 BEGIN \ here we presume that LCD_TIM_IFG = 1...
39026 BIT #1,&LCD_TIM_CTL \ 3
39027 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
39028 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
39030 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
39036 CODE TOP_LCD \ LCD Sample
39037 \ \ if write : %xxxxWWWW --
39038 \ \ if read : -- %0000RRRR
39039 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
39040 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
39041 0= IF \ write LCD bits pattern
39042 AND.B #LCD_DB,TOS \
39043 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
39044 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
39047 THEN \ read LCD bits pattern
39050 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
39051 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
39052 AND.B #LCD_DB,TOS \
39057 CODE LCD_W \ byte -- write byte to LCD
39059 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
39060 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
39061 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
39062 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
39063 COLON \ high level word starts here
39064 TOP_LCD 2 20_US \ write high nibble first
39069 CODE LCD_WrC \ char -- Write Char
39070 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
39075 CODE LCD_WrF \ func -- Write Fonction
39076 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
39082 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
39087 $02 LCD_WrF 100 20_us
39091 [UNDEFINED] OR [IF]
39093 \ https://forth-standard.org/standard/core/OR
39094 \ C OR x1 x2 -- x3 logical OR
39103 : LCD_Entry_set $04 OR LCD_WrF ;
39105 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
39107 : LCD_DSP_Shift $10 OR LCD_WrF ;
39109 : LCD_Fn_Set $20 OR LCD_WrF ;
39111 : LCD_CGRAM_Set $40 OR LCD_WrF ;
39113 : LCD_Goto $80 OR LCD_WrF ;
39115 CODE LCD_R \ -- byte read byte from LCD
39116 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
39117 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
39118 COLON \ starts a FORTH word
39119 TOP_LCD 2 20_us \ -- %0000HHHH
39120 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
39121 HI2LO \ switch from FORTH to assembler
39122 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
39123 ADD.B @PSP+,TOS \ -- %HHHHLLLL
39124 MOV @RSP+,IP \ restore IP saved by COLON
39129 CODE LCD_RdS \ -- status Read Status
39130 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
39135 CODE LCD_RdC \ -- char Read Char
39136 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
39142 \ ******************************\
39143 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
39144 \ ******************************\
39145 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
39146 BIT.B #SW2,&SW2_IN \ test switch S2
39147 0= IF \ case of switch S2 pressed
39148 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
39150 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
39153 BIT.B #SW1,&SW1_IN \ test switch S1 input
39154 0= IF \ case of Switch S1 pressed
39155 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
39157 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
39161 BW1 \ from quit on truncated RC5 message
39162 BW2 \ from repeated RC5 command
39163 BW3 \ from end of RC5_INT
39164 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
39169 \ ******************************\
39170 ASM RC5_INT \ wake up on Px.RC5 change interrupt
39171 \ ******************************\
39172 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
39173 \ ******************************\
39174 \ \ in : SR(9)=old Toggle bit memory (ADD on)
39175 \ \ SMclock = 8|16|24 MHz
39176 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
39177 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
39178 \ \ SR(9)=new Toggle bit memory (ADD on)
39179 \ ******************************\
39180 \ RC5_FirstStartBitHalfCycle: \
39181 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
39182 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
39183 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
39184 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
39185 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
39186 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
39187 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
39188 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
39189 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
39190 MOV #1778,X \ RC5_Period * 1us
39191 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
39192 MOV #14,W \ count of loop
39194 \ ******************************\
39195 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
39196 \ ******************************\ |
39197 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
39198 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
39199 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
39200 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
39201 \ RC5_Compute_3/4_Period: \ |
39202 RRUM #1,X \ X=1/2 cycle |
39205 ADD X,Y \ Y=3/4 cycle
39206 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
39208 \ ******************************\
39209 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
39210 \ ******************************\
39211 BIT.B #RC5,&IR_IN \ C_flag = IR bit
39212 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
39213 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
39214 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
39215 SUB #1,W \ decrement count loop
39216 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
39217 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
39218 0<> WHILE \ ----> out of loop ----+
39219 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
39221 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
39222 CMP Y,X \ 1 | cycle time out of bound ?
39223 U>= IF \ 2 ^ | yes:
39224 BIC #$30,&RC5_TIM_CTL \ | | stop timer
39225 GOTO BW1 \ | | quit on truncated RC5 message
39227 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
39229 REPEAT \ ----> loop back --+ | with X = new RC5_period value
39230 \ ******************************\ |
39231 \ RC5_SampleEndOf: \ <---------------------+
39232 \ ******************************\
39233 BIC #$30,&RC5_TIM_CTL \ stop timer
39234 \ ******************************\
39235 \ RC5_ComputeNewRC5word \
39236 \ ******************************\
39237 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
39238 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
39239 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
39240 \ ******************************\
39241 \ RC5_ComputeC6bit \
39242 \ ******************************\
39243 BIT #BIT14,T \ test /C6 bit in T
39244 0= IF BIS #BIT6,X \ set C6 bit in X
39245 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
39246 \ ******************************\
39247 \ RC5_CommandByteIsDone \ -- BASE RC5_code
39248 \ ******************************\
39249 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
39250 \ ******************************\
39251 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
39252 XOR @RSP,T \ (new XOR old) Toggle bits
39253 BIT #UF10,T \ repeated RC5_command ?
39254 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
39255 XOR #UF10,0(RSP) \ 5 toggle bit memory
39256 \ ******************************\
39257 \ Display IR_RC5 code \ X = RC5 code
39258 \ ******************************\
39260 MOV &BASE,2(PSP) \ save current base
39261 MOV #$10,&BASE \ set hex base
39262 MOV TOS,0(PSP) \ save TOS
39264 LO2HI \ switch from assembler to FORTH
39265 ['] LCD_CLEAR IS CR \ redirects CR
39266 ['] LCD_WrC IS EMIT \ redirects EMIT
39267 CR ." $" 2 U.R \ print IR_RC5 code
39268 ['] CR >BODY IS CR \ restore CR
39269 ['] EMIT >BODY IS EMIT \ restore EMIT
39270 HI2LO \ switch from FORTH to assembler
39271 MOV TOS,&BASE \ restore current BASE
39273 \ ******************************\
39275 \ ******************************\
39279 \ ------------------------------\
39281 \ ------------------------------\
39282 \ ... \ insert here your background task
39285 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
39286 ADD #4,X \ 1 X = BODY of SLEEP
39289 \ ------------------------------\
39293 \ ------------------------------\
39294 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
39295 \ - - \CNTL Counter lentgh \ 00 = 16 bits
39296 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
39297 \ -- \ID input divider \ 10 = /4
39298 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
39299 \ - \TBCLR TimerB Clear
39302 \ -------------------------------\
39303 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
39304 \ -- \CM Capture Mode
39309 \ --- \OUTMOD \ 011 = set/reset
39315 \ -------------------------------\
39317 \ -------------------------------\
39319 \ ------------------------------\
39320 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
39321 \ ------------------------------\
39322 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
39323 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
39324 \ ------------------------------\
39325 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
39326 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
39327 \ ------------------------------\
39328 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
39329 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
39330 \ ------------------------------\
39331 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
39332 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
39333 \ ------------------------------\
39334 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
39335 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
39336 \ ------------------------------\
39337 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
39338 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
39339 \ ------------------------------\
39340 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
39341 \ ------------------------------\
39342 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
39343 \ ------------------------------\
39344 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
39345 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
39346 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
39347 \ ------------------------------\
39348 BIS.B #LCDVo,&LCDVo_DIR \
39349 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
39350 \ ------------------------------\
39351 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
39352 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
39353 \ ------------------------------\
39354 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
39355 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
39356 \ ******************************\
39358 \ ******************************\
39359 BIS.B #RC5,&IR_IE \ enable RC5_Int
39360 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
39361 MOV #RC5_INT,&IR_Vec \ init interrupt vector
39362 \ ******************************\
39363 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
39364 \ ******************************\
39365 \ %01 0001 0100 \ TAxCTL
39366 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
39367 \ -- \ ID divided by 1
39368 \ -- \ MC MODE = up to TAxCCRn
39369 \ - \ TACLR clear timer count
39372 \ ------------------------------\
39373 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
39374 \ ------------------------------\
39376 \ --- \ TAIDEX pre divisor
39377 \ ------------------------------\
39378 \ %0000 0000 0000 0101 \ TAxCCR0
39379 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
39380 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
39381 \ ------------------------------\
39382 \ %0000 0000 0001 0000 \ TAxCCTL0
39383 \ - \ CAP capture/compare mode = compare
39386 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
39387 \ ------------------------------\
39388 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
39389 \ ------------------------------\
39390 \ define LPM mode for ACCEPT \
39391 \ ------------------------------\
39392 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
39393 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
39394 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
39396 \ ------------------------------\
39397 \ redirects to background task \
39398 \ ------------------------------\
39400 MOV #BACKGROUND,2(X) \
39401 \ ------------------------------\
39403 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
39405 \ ------------------------------\
39407 \ ------------------------------\
39408 $03E8 20_US \ 1- wait 20 ms
39409 $03 TOP_LCD \ 2- send DB5=DB4=1
39410 $CD 20_US \ 3- wait 4,1 ms
39411 $03 TOP_LCD \ 4- send again DB5=DB4=1
39412 $5 20_US \ 5- wait 0,1 ms
39413 $03 TOP_LCD \ 6- send again again DB5=DB4=1
39414 $2 20_US \ wait 40 us = LCD cycle
39415 $02 TOP_LCD \ 7- send DB5=1 DB4=0
39416 $2 20_US \ wait 40 us = LCD cycle
39417 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
39418 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
39419 LCD_Clear \ 10- "LCD_Clear"
39420 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
39421 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
39422 LCD_Clear \ 10- "LCD_Clear"
39423 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
39424 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
39426 ['] CR >BODY IS CR \
39427 ['] EMIT >BODY IS EMIT \
39428 ." RC5toLCD is running. Type STOP to quit"
39429 LIT RECURSE IS WARM \ replace WARM by this START routine
39430 ABORT \ and continue with the next word after WARM...
39431 ; \ ...until interpreter falls in sleep mode within ACCEPT.
39434 CODE STOP \ stops multitasking, must to be used before downloading app
39435 \ restore default action of primary DEFERred word SLEEP, assembly version
39436 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
39437 ADD #4,X \ X = BODY of SLEEP
39438 MOV X,-2(X) \ restore the default background
39441 \ restore default action of primary DEFERred word WARM, FORTH version
39442 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
39444 COLD \ because we want to reset CPU and interrupt vectors
39449 ; downloading RC5toLCD.4th is done
39450 RST_HERE ; this app is protected against <reset>
39458 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
39460 [DEFINED] ASM [IF] \ security test
39464 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
39466 CODE MAX \ n1 n2 -- n3 signed maximum
39467 CMP @PSP,TOS \ n2-n1
39468 S< ?GOTO FW1 \ n2<n1
39474 CODE MIN \ n1 n2 -- n3 signed minimum
39475 CMP @PSP,TOS \ n2-n1
39476 S< ?GOTO BW1 \ n2<n1
39484 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
39485 : U.R \ u n -- display u unsigned in n width (n >= 2)
39487 R> OVER - 0 MAX SPACES TYPE
39492 \ CODE 20_US \ n -- n * 20 us
39493 \ BEGIN \ 3 cycles loop + 6~
39494 \ \ MOV #5,W \ 3 MCLK = 1 MHz
39495 \ \ MOV #23,W \ 3 MCLK = 4 MHz
39496 \ \ MOV #51,W \ 3 MCLK = 8 MHz
39497 \ MOV #104,W \ 3 MCLK = 16 MHz
39498 \ \ MOV #158,W \ 3 MCLK = 24 MHz
39499 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
39504 \ MOV @PSP+,TOS \ 2
39509 CODE 20_US \ n -- n * 20 us
39510 BEGIN \ here we presume that LCD_TIM_IFG = 1...
39512 BIT #1,&LCD_TIM_CTL \ 3
39513 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
39514 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
39516 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
39522 CODE TOP_LCD \ LCD Sample
39523 \ \ if write : %xxxxWWWW --
39524 \ \ if read : -- %0000RRRR
39525 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
39526 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
39527 0= IF \ write LCD bits pattern
39528 AND.B #LCD_DB,TOS \
39529 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
39530 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
39533 THEN \ read LCD bits pattern
39536 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
39537 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
39538 AND.B #LCD_DB,TOS \
39543 CODE LCD_W \ byte -- write byte to LCD
39545 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
39546 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
39547 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
39548 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
39549 COLON \ high level word starts here
39550 TOP_LCD 2 20_US \ write high nibble first
39555 CODE LCD_WrC \ char -- Write Char
39556 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
39561 CODE LCD_WrF \ func -- Write Fonction
39562 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
39568 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
39573 $02 LCD_WrF 100 20_us
39577 [UNDEFINED] OR [IF]
39579 \ https://forth-standard.org/standard/core/OR
39580 \ C OR x1 x2 -- x3 logical OR
39589 : LCD_Entry_set $04 OR LCD_WrF ;
39591 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
39593 : LCD_DSP_Shift $10 OR LCD_WrF ;
39595 : LCD_Fn_Set $20 OR LCD_WrF ;
39597 : LCD_CGRAM_Set $40 OR LCD_WrF ;
39599 : LCD_Goto $80 OR LCD_WrF ;
39601 CODE LCD_R \ -- byte read byte from LCD
39602 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
39603 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
39604 COLON \ starts a FORTH word
39605 TOP_LCD 2 20_us \ -- %0000HHHH
39606 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
39607 HI2LO \ switch from FORTH to assembler
39608 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
39609 ADD.B @PSP+,TOS \ -- %HHHHLLLL
39610 MOV @RSP+,IP \ restore IP saved by COLON
39615 CODE LCD_RdS \ -- status Read Status
39616 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
39621 CODE LCD_RdC \ -- char Read Char
39622 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
39628 \ ******************************\
39629 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
39630 \ ******************************\
39631 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
39632 BIT.B #SW2,&SW2_IN \ test switch S2
39633 0= IF \ case of switch S2 pressed
39634 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
39636 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
39639 BIT.B #SW1,&SW1_IN \ test switch S1 input
39640 0= IF \ case of Switch S1 pressed
39641 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
39643 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
39647 BW1 \ from quit on truncated RC5 message
39648 BW2 \ from repeated RC5 command
39649 BW3 \ from end of RC5_INT
39650 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
39655 \ ******************************\
39656 ASM RC5_INT \ wake up on Px.RC5 change interrupt
39657 \ ******************************\
39658 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
39659 \ ******************************\
39660 \ \ in : SR(9)=old Toggle bit memory (ADD on)
39661 \ \ SMclock = 8|16|24 MHz
39662 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
39663 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
39664 \ \ SR(9)=new Toggle bit memory (ADD on)
39665 \ ******************************\
39666 \ RC5_FirstStartBitHalfCycle: \
39667 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
39668 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
39669 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
39670 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
39671 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
39672 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
39673 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
39674 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
39675 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
39676 MOV #1778,X \ RC5_Period * 1us
39677 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
39678 MOV #14,W \ count of loop
39680 \ ******************************\
39681 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
39682 \ ******************************\ |
39683 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
39684 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
39685 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
39686 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
39687 \ RC5_Compute_3/4_Period: \ |
39688 RRUM #1,X \ X=1/2 cycle |
39691 ADD X,Y \ Y=3/4 cycle
39692 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
39694 \ ******************************\
39695 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
39696 \ ******************************\
39697 BIT.B #RC5,&IR_IN \ C_flag = IR bit
39698 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
39699 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
39700 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
39701 SUB #1,W \ decrement count loop
39702 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
39703 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
39704 0<> WHILE \ ----> out of loop ----+
39705 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
39707 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
39708 CMP Y,X \ 1 | cycle time out of bound ?
39709 U>= IF \ 2 ^ | yes:
39710 BIC #$30,&RC5_TIM_CTL \ | | stop timer
39711 GOTO BW1 \ | | quit on truncated RC5 message
39713 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
39715 REPEAT \ ----> loop back --+ | with X = new RC5_period value
39716 \ ******************************\ |
39717 \ RC5_SampleEndOf: \ <---------------------+
39718 \ ******************************\
39719 BIC #$30,&RC5_TIM_CTL \ stop timer
39720 \ ******************************\
39721 \ RC5_ComputeNewRC5word \
39722 \ ******************************\
39723 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
39724 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
39725 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
39726 \ ******************************\
39727 \ RC5_ComputeC6bit \
39728 \ ******************************\
39729 BIT #BIT14,T \ test /C6 bit in T
39730 0= IF BIS #BIT6,X \ set C6 bit in X
39731 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
39732 \ ******************************\
39733 \ RC5_CommandByteIsDone \ -- BASE RC5_code
39734 \ ******************************\
39735 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
39736 \ ******************************\
39737 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
39738 XOR @RSP,T \ (new XOR old) Toggle bits
39739 BIT #UF10,T \ repeated RC5_command ?
39740 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
39741 XOR #UF10,0(RSP) \ 5 toggle bit memory
39742 \ ******************************\
39743 \ Display IR_RC5 code \ X = RC5 code
39744 \ ******************************\
39746 MOV &BASE,2(PSP) \ save current base
39747 MOV #$10,&BASE \ set hex base
39748 MOV TOS,0(PSP) \ save TOS
39750 LO2HI \ switch from assembler to FORTH
39751 ['] LCD_CLEAR IS CR \ redirects CR
39752 ['] LCD_WrC IS EMIT \ redirects EMIT
39753 CR ." $" 2 U.R \ print IR_RC5 code
39754 ['] CR >BODY IS CR \ restore CR
39755 ['] EMIT >BODY IS EMIT \ restore EMIT
39756 HI2LO \ switch from FORTH to assembler
39757 MOV TOS,&BASE \ restore current BASE
39759 \ ******************************\
39761 \ ******************************\
39765 \ ------------------------------\
39767 \ ------------------------------\
39768 \ ... \ insert here your background task
39771 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
39772 ADD #4,X \ 1 X = BODY of SLEEP
39775 \ ------------------------------\
39779 \ ------------------------------\
39780 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
39781 \ - - \CNTL Counter lentgh \ 00 = 16 bits
39782 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
39783 \ -- \ID input divider \ 10 = /4
39784 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
39785 \ - \TBCLR TimerB Clear
39788 \ -------------------------------\
39789 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
39790 \ -- \CM Capture Mode
39795 \ --- \OUTMOD \ 011 = set/reset
39801 \ -------------------------------\
39803 \ -------------------------------\
39805 \ ------------------------------\
39806 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
39807 \ ------------------------------\
39808 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
39809 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
39810 \ ------------------------------\
39811 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
39812 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
39813 \ ------------------------------\
39814 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
39815 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
39816 \ ------------------------------\
39817 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
39818 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
39819 \ ------------------------------\
39820 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
39821 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
39822 \ ------------------------------\
39823 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
39824 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
39825 \ ------------------------------\
39826 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
39827 \ ------------------------------\
39828 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
39829 \ ------------------------------\
39830 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
39831 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
39832 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
39833 \ ------------------------------\
39834 BIS.B #LCDVo,&LCDVo_DIR \
39835 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
39836 \ ------------------------------\
39837 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
39838 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
39839 \ ------------------------------\
39840 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
39841 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
39842 \ ******************************\
39844 \ ******************************\
39845 BIS.B #RC5,&IR_IE \ enable RC5_Int
39846 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
39847 MOV #RC5_INT,&IR_Vec \ init interrupt vector
39848 \ ******************************\
39849 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
39850 \ ******************************\
39851 \ %01 0001 0100 \ TAxCTL
39852 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
39853 \ -- \ ID divided by 1
39854 \ -- \ MC MODE = up to TAxCCRn
39855 \ - \ TACLR clear timer count
39858 \ ------------------------------\
39859 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
39860 \ ------------------------------\
39862 \ --- \ TAIDEX pre divisor
39863 \ ------------------------------\
39864 \ %0000 0000 0000 0101 \ TAxCCR0
39865 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
39866 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
39867 \ ------------------------------\
39868 \ %0000 0000 0001 0000 \ TAxCCTL0
39869 \ - \ CAP capture/compare mode = compare
39872 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
39873 \ ------------------------------\
39874 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
39875 \ ------------------------------\
39876 \ define LPM mode for ACCEPT \
39877 \ ------------------------------\
39878 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
39879 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
39880 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
39882 \ ------------------------------\
39883 \ redirects to background task \
39884 \ ------------------------------\
39886 MOV #BACKGROUND,2(X) \
39887 \ ------------------------------\
39889 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
39891 \ ------------------------------\
39893 \ ------------------------------\
39894 $03E8 20_US \ 1- wait 20 ms
39895 $03 TOP_LCD \ 2- send DB5=DB4=1
39896 $CD 20_US \ 3- wait 4,1 ms
39897 $03 TOP_LCD \ 4- send again DB5=DB4=1
39898 $5 20_US \ 5- wait 0,1 ms
39899 $03 TOP_LCD \ 6- send again again DB5=DB4=1
39900 $2 20_US \ wait 40 us = LCD cycle
39901 $02 TOP_LCD \ 7- send DB5=1 DB4=0
39902 $2 20_US \ wait 40 us = LCD cycle
39903 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
39904 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
39905 LCD_Clear \ 10- "LCD_Clear"
39906 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
39907 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
39908 LCD_Clear \ 10- "LCD_Clear"
39909 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
39910 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
39912 ['] CR >BODY IS CR \
39913 ['] EMIT >BODY IS EMIT \
39914 ." RC5toLCD is running. Type STOP to quit"
39915 LIT RECURSE IS WARM \ replace WARM by this START routine
39916 ABORT \ and continue with the next word after WARM...
39917 ; \ ...until interpreter falls in sleep mode within ACCEPT.
39920 CODE STOP \ stops multitasking, must to be used before downloading app
39921 \ restore default action of primary DEFERred word SLEEP, assembly version
39922 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
39923 ADD #4,X \ X = BODY of SLEEP
39924 MOV X,-2(X) \ restore the default background
39927 \ restore default action of primary DEFERred word WARM, FORTH version
39928 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
39930 COLD \ because we want to reset CPU and interrupt vectors
39935 ; downloading RC5toLCD.4th is done
39936 RST_HERE ; this app is protected against <reset>
39944 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
39946 [DEFINED] ASM [IF] \ security test
39950 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
39952 CODE MAX \ n1 n2 -- n3 signed maximum
39953 CMP @PSP,TOS \ n2-n1
39954 S< ?GOTO FW1 \ n2<n1
39960 CODE MIN \ n1 n2 -- n3 signed minimum
39961 CMP @PSP,TOS \ n2-n1
39962 S< ?GOTO BW1 \ n2<n1
39970 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
39971 : U.R \ u n -- display u unsigned in n width (n >= 2)
39973 R> OVER - 0 MAX SPACES TYPE
39978 \ CODE 20_US \ n -- n * 20 us
39979 \ BEGIN \ 3 cycles loop + 6~
39980 \ \ MOV #5,W \ 3 MCLK = 1 MHz
39981 \ \ MOV #23,W \ 3 MCLK = 4 MHz
39982 \ \ MOV #51,W \ 3 MCLK = 8 MHz
39983 \ MOV #104,W \ 3 MCLK = 16 MHz
39984 \ \ MOV #158,W \ 3 MCLK = 24 MHz
39985 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
39990 \ MOV @PSP+,TOS \ 2
39995 CODE 20_US \ n -- n * 20 us
39996 BEGIN \ here we presume that LCD_TIM_IFG = 1...
39998 BIT #1,&LCD_TIM_CTL \ 3
39999 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
40000 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
40002 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
40008 CODE TOP_LCD \ LCD Sample
40009 \ \ if write : %xxxxWWWW --
40010 \ \ if read : -- %0000RRRR
40011 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
40012 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
40013 0= IF \ write LCD bits pattern
40014 AND.B #LCD_DB,TOS \
40015 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
40016 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
40019 THEN \ read LCD bits pattern
40022 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
40023 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
40024 AND.B #LCD_DB,TOS \
40029 CODE LCD_W \ byte -- write byte to LCD
40031 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
40032 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
40033 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
40034 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
40035 COLON \ high level word starts here
40036 TOP_LCD 2 20_US \ write high nibble first
40041 CODE LCD_WrC \ char -- Write Char
40042 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
40047 CODE LCD_WrF \ func -- Write Fonction
40048 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
40054 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
40059 $02 LCD_WrF 100 20_us
40063 [UNDEFINED] OR [IF]
40065 \ https://forth-standard.org/standard/core/OR
40066 \ C OR x1 x2 -- x3 logical OR
40075 : LCD_Entry_set $04 OR LCD_WrF ;
40077 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
40079 : LCD_DSP_Shift $10 OR LCD_WrF ;
40081 : LCD_Fn_Set $20 OR LCD_WrF ;
40083 : LCD_CGRAM_Set $40 OR LCD_WrF ;
40085 : LCD_Goto $80 OR LCD_WrF ;
40087 CODE LCD_R \ -- byte read byte from LCD
40088 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
40089 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
40090 COLON \ starts a FORTH word
40091 TOP_LCD 2 20_us \ -- %0000HHHH
40092 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
40093 HI2LO \ switch from FORTH to assembler
40094 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
40095 ADD.B @PSP+,TOS \ -- %HHHHLLLL
40096 MOV @RSP+,IP \ restore IP saved by COLON
40101 CODE LCD_RdS \ -- status Read Status
40102 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
40107 CODE LCD_RdC \ -- char Read Char
40108 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
40114 \ ******************************\
40115 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
40116 \ ******************************\
40117 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
40118 BIT.B #SW2,&SW2_IN \ test switch S2
40119 0= IF \ case of switch S2 pressed
40120 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
40122 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
40125 BIT.B #SW1,&SW1_IN \ test switch S1 input
40126 0= IF \ case of Switch S1 pressed
40127 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
40129 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
40133 BW1 \ from quit on truncated RC5 message
40134 BW2 \ from repeated RC5 command
40135 BW3 \ from end of RC5_INT
40136 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
40141 \ ******************************\
40142 ASM RC5_INT \ wake up on Px.RC5 change interrupt
40143 \ ******************************\
40144 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
40145 \ ******************************\
40146 \ \ in : SR(9)=old Toggle bit memory (ADD on)
40147 \ \ SMclock = 8|16|24 MHz
40148 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
40149 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
40150 \ \ SR(9)=new Toggle bit memory (ADD on)
40151 \ ******************************\
40152 \ RC5_FirstStartBitHalfCycle: \
40153 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
40154 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
40155 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
40156 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
40157 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
40158 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
40159 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
40160 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
40161 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
40162 MOV #1778,X \ RC5_Period * 1us
40163 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
40164 MOV #14,W \ count of loop
40166 \ ******************************\
40167 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
40168 \ ******************************\ |
40169 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
40170 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
40171 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
40172 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
40173 \ RC5_Compute_3/4_Period: \ |
40174 RRUM #1,X \ X=1/2 cycle |
40177 ADD X,Y \ Y=3/4 cycle
40178 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
40180 \ ******************************\
40181 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
40182 \ ******************************\
40183 BIT.B #RC5,&IR_IN \ C_flag = IR bit
40184 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
40185 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
40186 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
40187 SUB #1,W \ decrement count loop
40188 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
40189 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
40190 0<> WHILE \ ----> out of loop ----+
40191 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
40193 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
40194 CMP Y,X \ 1 | cycle time out of bound ?
40195 U>= IF \ 2 ^ | yes:
40196 BIC #$30,&RC5_TIM_CTL \ | | stop timer
40197 GOTO BW1 \ | | quit on truncated RC5 message
40199 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
40201 REPEAT \ ----> loop back --+ | with X = new RC5_period value
40202 \ ******************************\ |
40203 \ RC5_SampleEndOf: \ <---------------------+
40204 \ ******************************\
40205 BIC #$30,&RC5_TIM_CTL \ stop timer
40206 \ ******************************\
40207 \ RC5_ComputeNewRC5word \
40208 \ ******************************\
40209 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
40210 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
40211 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
40212 \ ******************************\
40213 \ RC5_ComputeC6bit \
40214 \ ******************************\
40215 BIT #BIT14,T \ test /C6 bit in T
40216 0= IF BIS #BIT6,X \ set C6 bit in X
40217 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
40218 \ ******************************\
40219 \ RC5_CommandByteIsDone \ -- BASE RC5_code
40220 \ ******************************\
40221 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
40222 \ ******************************\
40223 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
40224 XOR @RSP,T \ (new XOR old) Toggle bits
40225 BIT #UF10,T \ repeated RC5_command ?
40226 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
40227 XOR #UF10,0(RSP) \ 5 toggle bit memory
40228 \ ******************************\
40229 \ Display IR_RC5 code \ X = RC5 code
40230 \ ******************************\
40232 MOV &BASE,2(PSP) \ save current base
40233 MOV #$10,&BASE \ set hex base
40234 MOV TOS,0(PSP) \ save TOS
40236 LO2HI \ switch from assembler to FORTH
40237 ['] LCD_CLEAR IS CR \ redirects CR
40238 ['] LCD_WrC IS EMIT \ redirects EMIT
40239 CR ." $" 2 U.R \ print IR_RC5 code
40240 ['] CR >BODY IS CR \ restore CR
40241 ['] EMIT >BODY IS EMIT \ restore EMIT
40242 HI2LO \ switch from FORTH to assembler
40243 MOV TOS,&BASE \ restore current BASE
40245 \ ******************************\
40247 \ ******************************\
40251 \ ------------------------------\
40253 \ ------------------------------\
40254 \ ... \ insert here your background task
40257 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
40258 ADD #4,X \ 1 X = BODY of SLEEP
40261 \ ------------------------------\
40265 \ ------------------------------\
40266 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
40267 \ - - \CNTL Counter lentgh \ 00 = 16 bits
40268 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
40269 \ -- \ID input divider \ 10 = /4
40270 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
40271 \ - \TBCLR TimerB Clear
40274 \ -------------------------------\
40275 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
40276 \ -- \CM Capture Mode
40281 \ --- \OUTMOD \ 011 = set/reset
40287 \ -------------------------------\
40289 \ -------------------------------\
40291 \ ------------------------------\
40292 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
40293 \ ------------------------------\
40294 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
40295 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
40296 \ ------------------------------\
40297 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
40298 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
40299 \ ------------------------------\
40300 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
40301 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
40302 \ ------------------------------\
40303 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
40304 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
40305 \ ------------------------------\
40306 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
40307 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
40308 \ ------------------------------\
40309 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
40310 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
40311 \ ------------------------------\
40312 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
40313 \ ------------------------------\
40314 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
40315 \ ------------------------------\
40316 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
40317 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
40318 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
40319 \ ------------------------------\
40320 BIS.B #LCDVo,&LCDVo_DIR \
40321 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
40322 \ ------------------------------\
40323 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
40324 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
40325 \ ------------------------------\
40326 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
40327 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
40328 \ ******************************\
40330 \ ******************************\
40331 BIS.B #RC5,&IR_IE \ enable RC5_Int
40332 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
40333 MOV #RC5_INT,&IR_Vec \ init interrupt vector
40334 \ ******************************\
40335 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
40336 \ ******************************\
40337 \ %01 0001 0100 \ TAxCTL
40338 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
40339 \ -- \ ID divided by 1
40340 \ -- \ MC MODE = up to TAxCCRn
40341 \ - \ TACLR clear timer count
40344 \ ------------------------------\
40345 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
40346 \ ------------------------------\
40348 \ --- \ TAIDEX pre divisor
40349 \ ------------------------------\
40350 \ %0000 0000 0000 0101 \ TAxCCR0
40351 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
40352 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
40353 \ ------------------------------\
40354 \ %0000 0000 0001 0000 \ TAxCCTL0
40355 \ - \ CAP capture/compare mode = compare
40358 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
40359 \ ------------------------------\
40360 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
40361 \ ------------------------------\
40362 \ define LPM mode for ACCEPT \
40363 \ ------------------------------\
40364 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
40365 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
40366 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
40368 \ ------------------------------\
40369 \ redirects to background task \
40370 \ ------------------------------\
40372 MOV #BACKGROUND,2(X) \
40373 \ ------------------------------\
40375 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
40377 \ ------------------------------\
40379 \ ------------------------------\
40380 $03E8 20_US \ 1- wait 20 ms
40381 $03 TOP_LCD \ 2- send DB5=DB4=1
40382 $CD 20_US \ 3- wait 4,1 ms
40383 $03 TOP_LCD \ 4- send again DB5=DB4=1
40384 $5 20_US \ 5- wait 0,1 ms
40385 $03 TOP_LCD \ 6- send again again DB5=DB4=1
40386 $2 20_US \ wait 40 us = LCD cycle
40387 $02 TOP_LCD \ 7- send DB5=1 DB4=0
40388 $2 20_US \ wait 40 us = LCD cycle
40389 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
40390 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
40391 LCD_Clear \ 10- "LCD_Clear"
40392 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
40393 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
40394 LCD_Clear \ 10- "LCD_Clear"
40395 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
40396 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
40398 ['] CR >BODY IS CR \
40399 ['] EMIT >BODY IS EMIT \
40400 ." RC5toLCD is running. Type STOP to quit"
40401 LIT RECURSE IS WARM \ replace WARM by this START routine
40402 ABORT \ and continue with the next word after WARM...
40403 ; \ ...until interpreter falls in sleep mode within ACCEPT.
40406 CODE STOP \ stops multitasking, must to be used before downloading app
40407 \ restore default action of primary DEFERred word SLEEP, assembly version
40408 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
40409 ADD #4,X \ X = BODY of SLEEP
40410 MOV X,-2(X) \ restore the default background
40413 \ restore default action of primary DEFERred word WARM, FORTH version
40414 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
40416 COLD \ because we want to reset CPU and interrupt vectors
40421 ; downloading RC5toLCD.4th is done
40422 RST_HERE ; this app is protected against <reset>
40430 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
40432 [DEFINED] ASM [IF] \ security test
40436 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
40438 CODE MAX \ n1 n2 -- n3 signed maximum
40439 CMP @PSP,TOS \ n2-n1
40440 S< ?GOTO FW1 \ n2<n1
40446 CODE MIN \ n1 n2 -- n3 signed minimum
40447 CMP @PSP,TOS \ n2-n1
40448 S< ?GOTO BW1 \ n2<n1
40456 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
40457 : U.R \ u n -- display u unsigned in n width (n >= 2)
40459 R> OVER - 0 MAX SPACES TYPE
40464 \ CODE 20_US \ n -- n * 20 us
40465 \ BEGIN \ 3 cycles loop + 6~
40466 \ \ MOV #5,W \ 3 MCLK = 1 MHz
40467 \ \ MOV #23,W \ 3 MCLK = 4 MHz
40468 \ \ MOV #51,W \ 3 MCLK = 8 MHz
40469 \ MOV #104,W \ 3 MCLK = 16 MHz
40470 \ \ MOV #158,W \ 3 MCLK = 24 MHz
40471 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
40476 \ MOV @PSP+,TOS \ 2
40481 CODE 20_US \ n -- n * 20 us
40482 BEGIN \ here we presume that LCD_TIM_IFG = 1...
40484 BIT #1,&LCD_TIM_CTL \ 3
40485 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
40486 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
40488 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
40494 CODE TOP_LCD \ LCD Sample
40495 \ \ if write : %xxxxWWWW --
40496 \ \ if read : -- %0000RRRR
40497 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
40498 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
40499 0= IF \ write LCD bits pattern
40500 AND.B #LCD_DB,TOS \
40501 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
40502 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
40505 THEN \ read LCD bits pattern
40508 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
40509 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
40510 AND.B #LCD_DB,TOS \
40515 CODE LCD_W \ byte -- write byte to LCD
40517 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
40518 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
40519 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
40520 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
40521 COLON \ high level word starts here
40522 TOP_LCD 2 20_US \ write high nibble first
40527 CODE LCD_WrC \ char -- Write Char
40528 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
40533 CODE LCD_WrF \ func -- Write Fonction
40534 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
40540 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
40545 $02 LCD_WrF 100 20_us
40549 [UNDEFINED] OR [IF]
40551 \ https://forth-standard.org/standard/core/OR
40552 \ C OR x1 x2 -- x3 logical OR
40561 : LCD_Entry_set $04 OR LCD_WrF ;
40563 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
40565 : LCD_DSP_Shift $10 OR LCD_WrF ;
40567 : LCD_Fn_Set $20 OR LCD_WrF ;
40569 : LCD_CGRAM_Set $40 OR LCD_WrF ;
40571 : LCD_Goto $80 OR LCD_WrF ;
40573 CODE LCD_R \ -- byte read byte from LCD
40574 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
40575 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
40576 COLON \ starts a FORTH word
40577 TOP_LCD 2 20_us \ -- %0000HHHH
40578 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
40579 HI2LO \ switch from FORTH to assembler
40580 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
40581 ADD.B @PSP+,TOS \ -- %HHHHLLLL
40582 MOV @RSP+,IP \ restore IP saved by COLON
40587 CODE LCD_RdS \ -- status Read Status
40588 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
40593 CODE LCD_RdC \ -- char Read Char
40594 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
40600 \ ******************************\
40601 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
40602 \ ******************************\
40603 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
40604 BIT.B #SW2,&SW2_IN \ test switch S2
40605 0= IF \ case of switch S2 pressed
40606 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
40608 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
40611 BIT.B #SW1,&SW1_IN \ test switch S1 input
40612 0= IF \ case of Switch S1 pressed
40613 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
40615 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
40619 BW1 \ from quit on truncated RC5 message
40620 BW2 \ from repeated RC5 command
40621 BW3 \ from end of RC5_INT
40622 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
40627 \ ******************************\
40628 ASM RC5_INT \ wake up on Px.RC5 change interrupt
40629 \ ******************************\
40630 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
40631 \ ******************************\
40632 \ \ in : SR(9)=old Toggle bit memory (ADD on)
40633 \ \ SMclock = 8|16|24 MHz
40634 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
40635 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
40636 \ \ SR(9)=new Toggle bit memory (ADD on)
40637 \ ******************************\
40638 \ RC5_FirstStartBitHalfCycle: \
40639 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
40640 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
40641 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
40642 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
40643 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
40644 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
40645 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
40646 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
40647 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
40648 MOV #1778,X \ RC5_Period * 1us
40649 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
40650 MOV #14,W \ count of loop
40652 \ ******************************\
40653 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
40654 \ ******************************\ |
40655 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
40656 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
40657 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
40658 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
40659 \ RC5_Compute_3/4_Period: \ |
40660 RRUM #1,X \ X=1/2 cycle |
40663 ADD X,Y \ Y=3/4 cycle
40664 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
40666 \ ******************************\
40667 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
40668 \ ******************************\
40669 BIT.B #RC5,&IR_IN \ C_flag = IR bit
40670 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
40671 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
40672 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
40673 SUB #1,W \ decrement count loop
40674 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
40675 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
40676 0<> WHILE \ ----> out of loop ----+
40677 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
40679 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
40680 CMP Y,X \ 1 | cycle time out of bound ?
40681 U>= IF \ 2 ^ | yes:
40682 BIC #$30,&RC5_TIM_CTL \ | | stop timer
40683 GOTO BW1 \ | | quit on truncated RC5 message
40685 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
40687 REPEAT \ ----> loop back --+ | with X = new RC5_period value
40688 \ ******************************\ |
40689 \ RC5_SampleEndOf: \ <---------------------+
40690 \ ******************************\
40691 BIC #$30,&RC5_TIM_CTL \ stop timer
40692 \ ******************************\
40693 \ RC5_ComputeNewRC5word \
40694 \ ******************************\
40695 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
40696 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
40697 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
40698 \ ******************************\
40699 \ RC5_ComputeC6bit \
40700 \ ******************************\
40701 BIT #BIT14,T \ test /C6 bit in T
40702 0= IF BIS #BIT6,X \ set C6 bit in X
40703 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
40704 \ ******************************\
40705 \ RC5_CommandByteIsDone \ -- BASE RC5_code
40706 \ ******************************\
40707 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
40708 \ ******************************\
40709 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
40710 XOR @RSP,T \ (new XOR old) Toggle bits
40711 BIT #UF10,T \ repeated RC5_command ?
40712 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
40713 XOR #UF10,0(RSP) \ 5 toggle bit memory
40714 \ ******************************\
40715 \ Display IR_RC5 code \ X = RC5 code
40716 \ ******************************\
40718 MOV &BASE,2(PSP) \ save current base
40719 MOV #$10,&BASE \ set hex base
40720 MOV TOS,0(PSP) \ save TOS
40722 LO2HI \ switch from assembler to FORTH
40723 ['] LCD_CLEAR IS CR \ redirects CR
40724 ['] LCD_WrC IS EMIT \ redirects EMIT
40725 CR ." $" 2 U.R \ print IR_RC5 code
40726 ['] CR >BODY IS CR \ restore CR
40727 ['] EMIT >BODY IS EMIT \ restore EMIT
40728 HI2LO \ switch from FORTH to assembler
40729 MOV TOS,&BASE \ restore current BASE
40731 \ ******************************\
40733 \ ******************************\
40737 \ ------------------------------\
40739 \ ------------------------------\
40740 \ ... \ insert here your background task
40743 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
40744 ADD #4,X \ 1 X = BODY of SLEEP
40747 \ ------------------------------\
40751 \ ------------------------------\
40752 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
40753 \ - - \CNTL Counter lentgh \ 00 = 16 bits
40754 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
40755 \ -- \ID input divider \ 10 = /4
40756 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
40757 \ - \TBCLR TimerB Clear
40760 \ -------------------------------\
40761 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
40762 \ -- \CM Capture Mode
40767 \ --- \OUTMOD \ 011 = set/reset
40773 \ -------------------------------\
40775 \ -------------------------------\
40777 \ ------------------------------\
40778 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
40779 \ ------------------------------\
40780 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
40781 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
40782 \ ------------------------------\
40783 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
40784 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
40785 \ ------------------------------\
40786 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
40787 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
40788 \ ------------------------------\
40789 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
40790 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
40791 \ ------------------------------\
40792 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
40793 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
40794 \ ------------------------------\
40795 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
40796 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
40797 \ ------------------------------\
40798 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
40799 \ ------------------------------\
40800 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
40801 \ ------------------------------\
40802 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
40803 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
40804 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
40805 \ ------------------------------\
40806 BIS.B #LCDVo,&LCDVo_DIR \
40807 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
40808 \ ------------------------------\
40809 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
40810 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
40811 \ ------------------------------\
40812 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
40813 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
40814 \ ******************************\
40816 \ ******************************\
40817 BIS.B #RC5,&IR_IE \ enable RC5_Int
40818 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
40819 MOV #RC5_INT,&IR_Vec \ init interrupt vector
40820 \ ******************************\
40821 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
40822 \ ******************************\
40823 \ %01 0001 0100 \ TAxCTL
40824 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
40825 \ -- \ ID divided by 1
40826 \ -- \ MC MODE = up to TAxCCRn
40827 \ - \ TACLR clear timer count
40830 \ ------------------------------\
40831 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
40832 \ ------------------------------\
40834 \ --- \ TAIDEX pre divisor
40835 \ ------------------------------\
40836 \ %0000 0000 0000 0101 \ TAxCCR0
40837 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
40838 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
40839 \ ------------------------------\
40840 \ %0000 0000 0001 0000 \ TAxCCTL0
40841 \ - \ CAP capture/compare mode = compare
40844 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
40845 \ ------------------------------\
40846 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
40847 \ ------------------------------\
40848 \ define LPM mode for ACCEPT \
40849 \ ------------------------------\
40850 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
40851 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
40852 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
40854 \ ------------------------------\
40855 \ redirects to background task \
40856 \ ------------------------------\
40858 MOV #BACKGROUND,2(X) \
40859 \ ------------------------------\
40861 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
40863 \ ------------------------------\
40865 \ ------------------------------\
40866 $03E8 20_US \ 1- wait 20 ms
40867 $03 TOP_LCD \ 2- send DB5=DB4=1
40868 $CD 20_US \ 3- wait 4,1 ms
40869 $03 TOP_LCD \ 4- send again DB5=DB4=1
40870 $5 20_US \ 5- wait 0,1 ms
40871 $03 TOP_LCD \ 6- send again again DB5=DB4=1
40872 $2 20_US \ wait 40 us = LCD cycle
40873 $02 TOP_LCD \ 7- send DB5=1 DB4=0
40874 $2 20_US \ wait 40 us = LCD cycle
40875 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
40876 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
40877 LCD_Clear \ 10- "LCD_Clear"
40878 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
40879 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
40880 LCD_Clear \ 10- "LCD_Clear"
40881 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
40882 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
40884 ['] CR >BODY IS CR \
40885 ['] EMIT >BODY IS EMIT \
40886 ." RC5toLCD is running. Type STOP to quit"
40887 LIT RECURSE IS WARM \ replace WARM by this START routine
40888 ABORT \ and continue with the next word after WARM...
40889 ; \ ...until interpreter falls in sleep mode within ACCEPT.
40892 CODE STOP \ stops multitasking, must to be used before downloading app
40893 \ restore default action of primary DEFERred word SLEEP, assembly version
40894 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
40895 ADD #4,X \ X = BODY of SLEEP
40896 MOV X,-2(X) \ restore the default background
40899 \ restore default action of primary DEFERred word WARM, FORTH version
40900 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
40902 COLD \ because we want to reset CPU and interrupt vectors
40907 ; downloading RC5toLCD.4th is done
40908 RST_HERE ; this app is protected against <reset>
40916 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
40918 [DEFINED] ASM [IF] \ security test
40922 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
40924 CODE MAX \ n1 n2 -- n3 signed maximum
40925 CMP @PSP,TOS \ n2-n1
40926 S< ?GOTO FW1 \ n2<n1
40932 CODE MIN \ n1 n2 -- n3 signed minimum
40933 CMP @PSP,TOS \ n2-n1
40934 S< ?GOTO BW1 \ n2<n1
40942 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
40943 : U.R \ u n -- display u unsigned in n width (n >= 2)
40945 R> OVER - 0 MAX SPACES TYPE
40950 \ CODE 20_US \ n -- n * 20 us
40951 \ BEGIN \ 3 cycles loop + 6~
40952 \ \ MOV #5,W \ 3 MCLK = 1 MHz
40953 \ \ MOV #23,W \ 3 MCLK = 4 MHz
40954 \ \ MOV #51,W \ 3 MCLK = 8 MHz
40955 \ MOV #104,W \ 3 MCLK = 16 MHz
40956 \ \ MOV #158,W \ 3 MCLK = 24 MHz
40957 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
40962 \ MOV @PSP+,TOS \ 2
40967 CODE 20_US \ n -- n * 20 us
40968 BEGIN \ here we presume that LCD_TIM_IFG = 1...
40970 BIT #1,&LCD_TIM_CTL \ 3
40971 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
40972 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
40974 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
40980 CODE TOP_LCD \ LCD Sample
40981 \ \ if write : %xxxxWWWW --
40982 \ \ if read : -- %0000RRRR
40983 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
40984 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
40985 0= IF \ write LCD bits pattern
40986 AND.B #LCD_DB,TOS \
40987 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
40988 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
40991 THEN \ read LCD bits pattern
40994 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
40995 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
40996 AND.B #LCD_DB,TOS \
41001 CODE LCD_W \ byte -- write byte to LCD
41003 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
41004 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
41005 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
41006 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
41007 COLON \ high level word starts here
41008 TOP_LCD 2 20_US \ write high nibble first
41013 CODE LCD_WrC \ char -- Write Char
41014 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
41019 CODE LCD_WrF \ func -- Write Fonction
41020 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
41026 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
41031 $02 LCD_WrF 100 20_us
41035 [UNDEFINED] OR [IF]
41037 \ https://forth-standard.org/standard/core/OR
41038 \ C OR x1 x2 -- x3 logical OR
41047 : LCD_Entry_set $04 OR LCD_WrF ;
41049 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
41051 : LCD_DSP_Shift $10 OR LCD_WrF ;
41053 : LCD_Fn_Set $20 OR LCD_WrF ;
41055 : LCD_CGRAM_Set $40 OR LCD_WrF ;
41057 : LCD_Goto $80 OR LCD_WrF ;
41059 CODE LCD_R \ -- byte read byte from LCD
41060 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
41061 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
41062 COLON \ starts a FORTH word
41063 TOP_LCD 2 20_us \ -- %0000HHHH
41064 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
41065 HI2LO \ switch from FORTH to assembler
41066 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
41067 ADD.B @PSP+,TOS \ -- %HHHHLLLL
41068 MOV @RSP+,IP \ restore IP saved by COLON
41073 CODE LCD_RdS \ -- status Read Status
41074 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
41079 CODE LCD_RdC \ -- char Read Char
41080 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
41086 \ ******************************\
41087 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
41088 \ ******************************\
41089 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
41090 BIT.B #SW2,&SW2_IN \ test switch S2
41091 0= IF \ case of switch S2 pressed
41092 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
41094 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
41097 BIT.B #SW1,&SW1_IN \ test switch S1 input
41098 0= IF \ case of Switch S1 pressed
41099 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
41101 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
41105 BW1 \ from quit on truncated RC5 message
41106 BW2 \ from repeated RC5 command
41107 BW3 \ from end of RC5_INT
41108 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
41113 \ ******************************\
41114 ASM RC5_INT \ wake up on Px.RC5 change interrupt
41115 \ ******************************\
41116 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
41117 \ ******************************\
41118 \ \ in : SR(9)=old Toggle bit memory (ADD on)
41119 \ \ SMclock = 8|16|24 MHz
41120 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
41121 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
41122 \ \ SR(9)=new Toggle bit memory (ADD on)
41123 \ ******************************\
41124 \ RC5_FirstStartBitHalfCycle: \
41125 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
41126 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
41127 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
41128 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
41129 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
41130 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
41131 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
41132 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
41133 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
41134 MOV #1778,X \ RC5_Period * 1us
41135 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
41136 MOV #14,W \ count of loop
41138 \ ******************************\
41139 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
41140 \ ******************************\ |
41141 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
41142 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
41143 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
41144 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
41145 \ RC5_Compute_3/4_Period: \ |
41146 RRUM #1,X \ X=1/2 cycle |
41149 ADD X,Y \ Y=3/4 cycle
41150 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
41152 \ ******************************\
41153 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
41154 \ ******************************\
41155 BIT.B #RC5,&IR_IN \ C_flag = IR bit
41156 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
41157 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
41158 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
41159 SUB #1,W \ decrement count loop
41160 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
41161 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
41162 0<> WHILE \ ----> out of loop ----+
41163 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
41165 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
41166 CMP Y,X \ 1 | cycle time out of bound ?
41167 U>= IF \ 2 ^ | yes:
41168 BIC #$30,&RC5_TIM_CTL \ | | stop timer
41169 GOTO BW1 \ | | quit on truncated RC5 message
41171 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
41173 REPEAT \ ----> loop back --+ | with X = new RC5_period value
41174 \ ******************************\ |
41175 \ RC5_SampleEndOf: \ <---------------------+
41176 \ ******************************\
41177 BIC #$30,&RC5_TIM_CTL \ stop timer
41178 \ ******************************\
41179 \ RC5_ComputeNewRC5word \
41180 \ ******************************\
41181 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
41182 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
41183 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
41184 \ ******************************\
41185 \ RC5_ComputeC6bit \
41186 \ ******************************\
41187 BIT #BIT14,T \ test /C6 bit in T
41188 0= IF BIS #BIT6,X \ set C6 bit in X
41189 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
41190 \ ******************************\
41191 \ RC5_CommandByteIsDone \ -- BASE RC5_code
41192 \ ******************************\
41193 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
41194 \ ******************************\
41195 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
41196 XOR @RSP,T \ (new XOR old) Toggle bits
41197 BIT #UF10,T \ repeated RC5_command ?
41198 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
41199 XOR #UF10,0(RSP) \ 5 toggle bit memory
41200 \ ******************************\
41201 \ Display IR_RC5 code \ X = RC5 code
41202 \ ******************************\
41204 MOV &BASE,2(PSP) \ save current base
41205 MOV #$10,&BASE \ set hex base
41206 MOV TOS,0(PSP) \ save TOS
41208 LO2HI \ switch from assembler to FORTH
41209 ['] LCD_CLEAR IS CR \ redirects CR
41210 ['] LCD_WrC IS EMIT \ redirects EMIT
41211 CR ." $" 2 U.R \ print IR_RC5 code
41212 ['] CR >BODY IS CR \ restore CR
41213 ['] EMIT >BODY IS EMIT \ restore EMIT
41214 HI2LO \ switch from FORTH to assembler
41215 MOV TOS,&BASE \ restore current BASE
41217 \ ******************************\
41219 \ ******************************\
41223 \ ------------------------------\
41225 \ ------------------------------\
41226 \ ... \ insert here your background task
41229 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
41230 ADD #4,X \ 1 X = BODY of SLEEP
41233 \ ------------------------------\
41237 \ ------------------------------\
41238 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
41239 \ - - \CNTL Counter lentgh \ 00 = 16 bits
41240 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
41241 \ -- \ID input divider \ 10 = /4
41242 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
41243 \ - \TBCLR TimerB Clear
41246 \ -------------------------------\
41247 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
41248 \ -- \CM Capture Mode
41253 \ --- \OUTMOD \ 011 = set/reset
41259 \ -------------------------------\
41261 \ -------------------------------\
41263 \ ------------------------------\
41264 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
41265 \ ------------------------------\
41266 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
41267 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
41268 \ ------------------------------\
41269 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
41270 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
41271 \ ------------------------------\
41272 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
41273 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
41274 \ ------------------------------\
41275 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
41276 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
41277 \ ------------------------------\
41278 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
41279 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
41280 \ ------------------------------\
41281 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
41282 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
41283 \ ------------------------------\
41284 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
41285 \ ------------------------------\
41286 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
41287 \ ------------------------------\
41288 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
41289 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
41290 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
41291 \ ------------------------------\
41292 BIS.B #LCDVo,&LCDVo_DIR \
41293 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
41294 \ ------------------------------\
41295 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
41296 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
41297 \ ------------------------------\
41298 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
41299 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
41300 \ ******************************\
41302 \ ******************************\
41303 BIS.B #RC5,&IR_IE \ enable RC5_Int
41304 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
41305 MOV #RC5_INT,&IR_Vec \ init interrupt vector
41306 \ ******************************\
41307 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
41308 \ ******************************\
41309 \ %01 0001 0100 \ TAxCTL
41310 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
41311 \ -- \ ID divided by 1
41312 \ -- \ MC MODE = up to TAxCCRn
41313 \ - \ TACLR clear timer count
41316 \ ------------------------------\
41317 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
41318 \ ------------------------------\
41320 \ --- \ TAIDEX pre divisor
41321 \ ------------------------------\
41322 \ %0000 0000 0000 0101 \ TAxCCR0
41323 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
41324 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
41325 \ ------------------------------\
41326 \ %0000 0000 0001 0000 \ TAxCCTL0
41327 \ - \ CAP capture/compare mode = compare
41330 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
41331 \ ------------------------------\
41332 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
41333 \ ------------------------------\
41334 \ define LPM mode for ACCEPT \
41335 \ ------------------------------\
41336 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
41337 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
41338 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
41340 \ ------------------------------\
41341 \ redirects to background task \
41342 \ ------------------------------\
41344 MOV #BACKGROUND,2(X) \
41345 \ ------------------------------\
41347 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
41349 \ ------------------------------\
41351 \ ------------------------------\
41352 $03E8 20_US \ 1- wait 20 ms
41353 $03 TOP_LCD \ 2- send DB5=DB4=1
41354 $CD 20_US \ 3- wait 4,1 ms
41355 $03 TOP_LCD \ 4- send again DB5=DB4=1
41356 $5 20_US \ 5- wait 0,1 ms
41357 $03 TOP_LCD \ 6- send again again DB5=DB4=1
41358 $2 20_US \ wait 40 us = LCD cycle
41359 $02 TOP_LCD \ 7- send DB5=1 DB4=0
41360 $2 20_US \ wait 40 us = LCD cycle
41361 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
41362 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
41363 LCD_Clear \ 10- "LCD_Clear"
41364 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
41365 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
41366 LCD_Clear \ 10- "LCD_Clear"
41367 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
41368 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
41370 ['] CR >BODY IS CR \
41371 ['] EMIT >BODY IS EMIT \
41372 ." RC5toLCD is running. Type STOP to quit"
41373 LIT RECURSE IS WARM \ replace WARM by this START routine
41374 ABORT \ and continue with the next word after WARM...
41375 ; \ ...until interpreter falls in sleep mode within ACCEPT.
41378 CODE STOP \ stops multitasking, must to be used before downloading app
41379 \ restore default action of primary DEFERred word SLEEP, assembly version
41380 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
41381 ADD #4,X \ X = BODY of SLEEP
41382 MOV X,-2(X) \ restore the default background
41385 \ restore default action of primary DEFERred word WARM, FORTH version
41386 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
41388 COLD \ because we want to reset CPU and interrupt vectors
41393 ; downloading RC5toLCD.4th is done
41394 RST_HERE ; this app is protected against <reset>
41402 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
41404 [DEFINED] ASM [IF] \ security test
41408 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
41410 CODE MAX \ n1 n2 -- n3 signed maximum
41411 CMP @PSP,TOS \ n2-n1
41412 S< ?GOTO FW1 \ n2<n1
41418 CODE MIN \ n1 n2 -- n3 signed minimum
41419 CMP @PSP,TOS \ n2-n1
41420 S< ?GOTO BW1 \ n2<n1
41428 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
41429 : U.R \ u n -- display u unsigned in n width (n >= 2)
41431 R> OVER - 0 MAX SPACES TYPE
41436 \ CODE 20_US \ n -- n * 20 us
41437 \ BEGIN \ 3 cycles loop + 6~
41438 \ \ MOV #5,W \ 3 MCLK = 1 MHz
41439 \ \ MOV #23,W \ 3 MCLK = 4 MHz
41440 \ \ MOV #51,W \ 3 MCLK = 8 MHz
41441 \ MOV #104,W \ 3 MCLK = 16 MHz
41442 \ \ MOV #158,W \ 3 MCLK = 24 MHz
41443 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
41448 \ MOV @PSP+,TOS \ 2
41453 CODE 20_US \ n -- n * 20 us
41454 BEGIN \ here we presume that LCD_TIM_IFG = 1...
41456 BIT #1,&LCD_TIM_CTL \ 3
41457 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
41458 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
41460 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
41466 CODE TOP_LCD \ LCD Sample
41467 \ \ if write : %xxxxWWWW --
41468 \ \ if read : -- %0000RRRR
41469 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
41470 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
41471 0= IF \ write LCD bits pattern
41472 AND.B #LCD_DB,TOS \
41473 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
41474 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
41477 THEN \ read LCD bits pattern
41480 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
41481 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
41482 AND.B #LCD_DB,TOS \
41487 CODE LCD_W \ byte -- write byte to LCD
41489 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
41490 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
41491 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
41492 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
41493 COLON \ high level word starts here
41494 TOP_LCD 2 20_US \ write high nibble first
41499 CODE LCD_WrC \ char -- Write Char
41500 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
41505 CODE LCD_WrF \ func -- Write Fonction
41506 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
41512 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
41517 $02 LCD_WrF 100 20_us
41521 [UNDEFINED] OR [IF]
41523 \ https://forth-standard.org/standard/core/OR
41524 \ C OR x1 x2 -- x3 logical OR
41533 : LCD_Entry_set $04 OR LCD_WrF ;
41535 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
41537 : LCD_DSP_Shift $10 OR LCD_WrF ;
41539 : LCD_Fn_Set $20 OR LCD_WrF ;
41541 : LCD_CGRAM_Set $40 OR LCD_WrF ;
41543 : LCD_Goto $80 OR LCD_WrF ;
41545 CODE LCD_R \ -- byte read byte from LCD
41546 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
41547 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
41548 COLON \ starts a FORTH word
41549 TOP_LCD 2 20_us \ -- %0000HHHH
41550 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
41551 HI2LO \ switch from FORTH to assembler
41552 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
41553 ADD.B @PSP+,TOS \ -- %HHHHLLLL
41554 MOV @RSP+,IP \ restore IP saved by COLON
41559 CODE LCD_RdS \ -- status Read Status
41560 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
41565 CODE LCD_RdC \ -- char Read Char
41566 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
41572 \ ******************************\
41573 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
41574 \ ******************************\
41575 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
41576 BIT.B #SW2,&SW2_IN \ test switch S2
41577 0= IF \ case of switch S2 pressed
41578 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
41580 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
41583 BIT.B #SW1,&SW1_IN \ test switch S1 input
41584 0= IF \ case of Switch S1 pressed
41585 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
41587 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
41591 BW1 \ from quit on truncated RC5 message
41592 BW2 \ from repeated RC5 command
41593 BW3 \ from end of RC5_INT
41594 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
41599 \ ******************************\
41600 ASM RC5_INT \ wake up on Px.RC5 change interrupt
41601 \ ******************************\
41602 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
41603 \ ******************************\
41604 \ \ in : SR(9)=old Toggle bit memory (ADD on)
41605 \ \ SMclock = 8|16|24 MHz
41606 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
41607 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
41608 \ \ SR(9)=new Toggle bit memory (ADD on)
41609 \ ******************************\
41610 \ RC5_FirstStartBitHalfCycle: \
41611 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
41612 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
41613 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
41614 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
41615 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
41616 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
41617 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
41618 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
41619 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
41620 MOV #1778,X \ RC5_Period * 1us
41621 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
41622 MOV #14,W \ count of loop
41624 \ ******************************\
41625 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
41626 \ ******************************\ |
41627 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
41628 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
41629 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
41630 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
41631 \ RC5_Compute_3/4_Period: \ |
41632 RRUM #1,X \ X=1/2 cycle |
41635 ADD X,Y \ Y=3/4 cycle
41636 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
41638 \ ******************************\
41639 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
41640 \ ******************************\
41641 BIT.B #RC5,&IR_IN \ C_flag = IR bit
41642 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
41643 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
41644 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
41645 SUB #1,W \ decrement count loop
41646 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
41647 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
41648 0<> WHILE \ ----> out of loop ----+
41649 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
41651 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
41652 CMP Y,X \ 1 | cycle time out of bound ?
41653 U>= IF \ 2 ^ | yes:
41654 BIC #$30,&RC5_TIM_CTL \ | | stop timer
41655 GOTO BW1 \ | | quit on truncated RC5 message
41657 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
41659 REPEAT \ ----> loop back --+ | with X = new RC5_period value
41660 \ ******************************\ |
41661 \ RC5_SampleEndOf: \ <---------------------+
41662 \ ******************************\
41663 BIC #$30,&RC5_TIM_CTL \ stop timer
41664 \ ******************************\
41665 \ RC5_ComputeNewRC5word \
41666 \ ******************************\
41667 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
41668 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
41669 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
41670 \ ******************************\
41671 \ RC5_ComputeC6bit \
41672 \ ******************************\
41673 BIT #BIT14,T \ test /C6 bit in T
41674 0= IF BIS #BIT6,X \ set C6 bit in X
41675 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
41676 \ ******************************\
41677 \ RC5_CommandByteIsDone \ -- BASE RC5_code
41678 \ ******************************\
41679 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
41680 \ ******************************\
41681 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
41682 XOR @RSP,T \ (new XOR old) Toggle bits
41683 BIT #UF10,T \ repeated RC5_command ?
41684 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
41685 XOR #UF10,0(RSP) \ 5 toggle bit memory
41686 \ ******************************\
41687 \ Display IR_RC5 code \ X = RC5 code
41688 \ ******************************\
41690 MOV &BASE,2(PSP) \ save current base
41691 MOV #$10,&BASE \ set hex base
41692 MOV TOS,0(PSP) \ save TOS
41694 LO2HI \ switch from assembler to FORTH
41695 ['] LCD_CLEAR IS CR \ redirects CR
41696 ['] LCD_WrC IS EMIT \ redirects EMIT
41697 CR ." $" 2 U.R \ print IR_RC5 code
41698 ['] CR >BODY IS CR \ restore CR
41699 ['] EMIT >BODY IS EMIT \ restore EMIT
41700 HI2LO \ switch from FORTH to assembler
41701 MOV TOS,&BASE \ restore current BASE
41703 \ ******************************\
41705 \ ******************************\
41709 \ ------------------------------\
41711 \ ------------------------------\
41712 \ ... \ insert here your background task
41715 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
41716 ADD #4,X \ 1 X = BODY of SLEEP
41719 \ ------------------------------\
41723 \ ------------------------------\
41724 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
41725 \ - - \CNTL Counter lentgh \ 00 = 16 bits
41726 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
41727 \ -- \ID input divider \ 10 = /4
41728 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
41729 \ - \TBCLR TimerB Clear
41732 \ -------------------------------\
41733 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
41734 \ -- \CM Capture Mode
41739 \ --- \OUTMOD \ 011 = set/reset
41745 \ -------------------------------\
41747 \ -------------------------------\
41749 \ ------------------------------\
41750 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
41751 \ ------------------------------\
41752 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
41753 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
41754 \ ------------------------------\
41755 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
41756 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
41757 \ ------------------------------\
41758 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
41759 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
41760 \ ------------------------------\
41761 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
41762 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
41763 \ ------------------------------\
41764 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
41765 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
41766 \ ------------------------------\
41767 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
41768 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
41769 \ ------------------------------\
41770 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
41771 \ ------------------------------\
41772 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
41773 \ ------------------------------\
41774 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
41775 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
41776 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
41777 \ ------------------------------\
41778 BIS.B #LCDVo,&LCDVo_DIR \
41779 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
41780 \ ------------------------------\
41781 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
41782 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
41783 \ ------------------------------\
41784 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
41785 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
41786 \ ******************************\
41788 \ ******************************\
41789 BIS.B #RC5,&IR_IE \ enable RC5_Int
41790 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
41791 MOV #RC5_INT,&IR_Vec \ init interrupt vector
41792 \ ******************************\
41793 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
41794 \ ******************************\
41795 \ %01 0001 0100 \ TAxCTL
41796 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
41797 \ -- \ ID divided by 1
41798 \ -- \ MC MODE = up to TAxCCRn
41799 \ - \ TACLR clear timer count
41802 \ ------------------------------\
41803 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
41804 \ ------------------------------\
41806 \ --- \ TAIDEX pre divisor
41807 \ ------------------------------\
41808 \ %0000 0000 0000 0101 \ TAxCCR0
41809 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
41810 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
41811 \ ------------------------------\
41812 \ %0000 0000 0001 0000 \ TAxCCTL0
41813 \ - \ CAP capture/compare mode = compare
41816 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
41817 \ ------------------------------\
41818 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
41819 \ ------------------------------\
41820 \ define LPM mode for ACCEPT \
41821 \ ------------------------------\
41822 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
41823 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
41824 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
41826 \ ------------------------------\
41827 \ redirects to background task \
41828 \ ------------------------------\
41830 MOV #BACKGROUND,2(X) \
41831 \ ------------------------------\
41833 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
41835 \ ------------------------------\
41837 \ ------------------------------\
41838 $03E8 20_US \ 1- wait 20 ms
41839 $03 TOP_LCD \ 2- send DB5=DB4=1
41840 $CD 20_US \ 3- wait 4,1 ms
41841 $03 TOP_LCD \ 4- send again DB5=DB4=1
41842 $5 20_US \ 5- wait 0,1 ms
41843 $03 TOP_LCD \ 6- send again again DB5=DB4=1
41844 $2 20_US \ wait 40 us = LCD cycle
41845 $02 TOP_LCD \ 7- send DB5=1 DB4=0
41846 $2 20_US \ wait 40 us = LCD cycle
41847 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
41848 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
41849 LCD_Clear \ 10- "LCD_Clear"
41850 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
41851 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
41852 LCD_Clear \ 10- "LCD_Clear"
41853 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
41854 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
41856 ['] CR >BODY IS CR \
41857 ['] EMIT >BODY IS EMIT \
41858 ." RC5toLCD is running. Type STOP to quit"
41859 LIT RECURSE IS WARM \ replace WARM by this START routine
41860 ABORT \ and continue with the next word after WARM...
41861 ; \ ...until interpreter falls in sleep mode within ACCEPT.
41864 CODE STOP \ stops multitasking, must to be used before downloading app
41865 \ restore default action of primary DEFERred word SLEEP, assembly version
41866 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
41867 ADD #4,X \ X = BODY of SLEEP
41868 MOV X,-2(X) \ restore the default background
41871 \ restore default action of primary DEFERred word WARM, FORTH version
41872 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
41874 COLD \ because we want to reset CPU and interrupt vectors
41879 ; downloading RC5toLCD.4th is done
41880 RST_HERE ; this app is protected against <reset>
41888 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
41890 [DEFINED] ASM [IF] \ security test
41894 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
41896 CODE MAX \ n1 n2 -- n3 signed maximum
41897 CMP @PSP,TOS \ n2-n1
41898 S< ?GOTO FW1 \ n2<n1
41904 CODE MIN \ n1 n2 -- n3 signed minimum
41905 CMP @PSP,TOS \ n2-n1
41906 S< ?GOTO BW1 \ n2<n1
41914 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
41915 : U.R \ u n -- display u unsigned in n width (n >= 2)
41917 R> OVER - 0 MAX SPACES TYPE
41922 \ CODE 20_US \ n -- n * 20 us
41923 \ BEGIN \ 3 cycles loop + 6~
41924 \ \ MOV #5,W \ 3 MCLK = 1 MHz
41925 \ \ MOV #23,W \ 3 MCLK = 4 MHz
41926 \ \ MOV #51,W \ 3 MCLK = 8 MHz
41927 \ MOV #104,W \ 3 MCLK = 16 MHz
41928 \ \ MOV #158,W \ 3 MCLK = 24 MHz
41929 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
41934 \ MOV @PSP+,TOS \ 2
41939 CODE 20_US \ n -- n * 20 us
41940 BEGIN \ here we presume that LCD_TIM_IFG = 1...
41942 BIT #1,&LCD_TIM_CTL \ 3
41943 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
41944 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
41946 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
41952 CODE TOP_LCD \ LCD Sample
41953 \ \ if write : %xxxxWWWW --
41954 \ \ if read : -- %0000RRRR
41955 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
41956 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
41957 0= IF \ write LCD bits pattern
41958 AND.B #LCD_DB,TOS \
41959 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
41960 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
41963 THEN \ read LCD bits pattern
41966 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
41967 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
41968 AND.B #LCD_DB,TOS \
41973 CODE LCD_W \ byte -- write byte to LCD
41975 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
41976 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
41977 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
41978 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
41979 COLON \ high level word starts here
41980 TOP_LCD 2 20_US \ write high nibble first
41985 CODE LCD_WrC \ char -- Write Char
41986 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
41991 CODE LCD_WrF \ func -- Write Fonction
41992 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
41998 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
42003 $02 LCD_WrF 100 20_us
42007 [UNDEFINED] OR [IF]
42009 \ https://forth-standard.org/standard/core/OR
42010 \ C OR x1 x2 -- x3 logical OR
42019 : LCD_Entry_set $04 OR LCD_WrF ;
42021 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
42023 : LCD_DSP_Shift $10 OR LCD_WrF ;
42025 : LCD_Fn_Set $20 OR LCD_WrF ;
42027 : LCD_CGRAM_Set $40 OR LCD_WrF ;
42029 : LCD_Goto $80 OR LCD_WrF ;
42031 CODE LCD_R \ -- byte read byte from LCD
42032 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
42033 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
42034 COLON \ starts a FORTH word
42035 TOP_LCD 2 20_us \ -- %0000HHHH
42036 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
42037 HI2LO \ switch from FORTH to assembler
42038 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
42039 ADD.B @PSP+,TOS \ -- %HHHHLLLL
42040 MOV @RSP+,IP \ restore IP saved by COLON
42045 CODE LCD_RdS \ -- status Read Status
42046 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
42051 CODE LCD_RdC \ -- char Read Char
42052 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
42058 \ ******************************\
42059 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
42060 \ ******************************\
42061 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
42062 BIT.B #SW2,&SW2_IN \ test switch S2
42063 0= IF \ case of switch S2 pressed
42064 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
42066 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
42069 BIT.B #SW1,&SW1_IN \ test switch S1 input
42070 0= IF \ case of Switch S1 pressed
42071 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
42073 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
42077 BW1 \ from quit on truncated RC5 message
42078 BW2 \ from repeated RC5 command
42079 BW3 \ from end of RC5_INT
42080 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
42085 \ ******************************\
42086 ASM RC5_INT \ wake up on Px.RC5 change interrupt
42087 \ ******************************\
42088 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
42089 \ ******************************\
42090 \ \ in : SR(9)=old Toggle bit memory (ADD on)
42091 \ \ SMclock = 8|16|24 MHz
42092 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
42093 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
42094 \ \ SR(9)=new Toggle bit memory (ADD on)
42095 \ ******************************\
42096 \ RC5_FirstStartBitHalfCycle: \
42097 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
42098 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
42099 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
42100 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
42101 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
42102 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
42103 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
42104 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
42105 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
42106 MOV #1778,X \ RC5_Period * 1us
42107 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
42108 MOV #14,W \ count of loop
42110 \ ******************************\
42111 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
42112 \ ******************************\ |
42113 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
42114 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
42115 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
42116 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
42117 \ RC5_Compute_3/4_Period: \ |
42118 RRUM #1,X \ X=1/2 cycle |
42121 ADD X,Y \ Y=3/4 cycle
42122 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
42124 \ ******************************\
42125 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
42126 \ ******************************\
42127 BIT.B #RC5,&IR_IN \ C_flag = IR bit
42128 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
42129 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
42130 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
42131 SUB #1,W \ decrement count loop
42132 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
42133 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
42134 0<> WHILE \ ----> out of loop ----+
42135 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
42137 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
42138 CMP Y,X \ 1 | cycle time out of bound ?
42139 U>= IF \ 2 ^ | yes:
42140 BIC #$30,&RC5_TIM_CTL \ | | stop timer
42141 GOTO BW1 \ | | quit on truncated RC5 message
42143 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
42145 REPEAT \ ----> loop back --+ | with X = new RC5_period value
42146 \ ******************************\ |
42147 \ RC5_SampleEndOf: \ <---------------------+
42148 \ ******************************\
42149 BIC #$30,&RC5_TIM_CTL \ stop timer
42150 \ ******************************\
42151 \ RC5_ComputeNewRC5word \
42152 \ ******************************\
42153 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
42154 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
42155 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
42156 \ ******************************\
42157 \ RC5_ComputeC6bit \
42158 \ ******************************\
42159 BIT #BIT14,T \ test /C6 bit in T
42160 0= IF BIS #BIT6,X \ set C6 bit in X
42161 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
42162 \ ******************************\
42163 \ RC5_CommandByteIsDone \ -- BASE RC5_code
42164 \ ******************************\
42165 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
42166 \ ******************************\
42167 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
42168 XOR @RSP,T \ (new XOR old) Toggle bits
42169 BIT #UF10,T \ repeated RC5_command ?
42170 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
42171 XOR #UF10,0(RSP) \ 5 toggle bit memory
42172 \ ******************************\
42173 \ Display IR_RC5 code \ X = RC5 code
42174 \ ******************************\
42176 MOV &BASE,2(PSP) \ save current base
42177 MOV #$10,&BASE \ set hex base
42178 MOV TOS,0(PSP) \ save TOS
42180 LO2HI \ switch from assembler to FORTH
42181 ['] LCD_CLEAR IS CR \ redirects CR
42182 ['] LCD_WrC IS EMIT \ redirects EMIT
42183 CR ." $" 2 U.R \ print IR_RC5 code
42184 ['] CR >BODY IS CR \ restore CR
42185 ['] EMIT >BODY IS EMIT \ restore EMIT
42186 HI2LO \ switch from FORTH to assembler
42187 MOV TOS,&BASE \ restore current BASE
42189 \ ******************************\
42191 \ ******************************\
42195 \ ------------------------------\
42197 \ ------------------------------\
42198 \ ... \ insert here your background task
42201 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
42202 ADD #4,X \ 1 X = BODY of SLEEP
42205 \ ------------------------------\
42209 \ ------------------------------\
42210 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
42211 \ - - \CNTL Counter lentgh \ 00 = 16 bits
42212 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
42213 \ -- \ID input divider \ 10 = /4
42214 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
42215 \ - \TBCLR TimerB Clear
42218 \ -------------------------------\
42219 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
42220 \ -- \CM Capture Mode
42225 \ --- \OUTMOD \ 011 = set/reset
42231 \ -------------------------------\
42233 \ -------------------------------\
42235 \ ------------------------------\
42236 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
42237 \ ------------------------------\
42238 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
42239 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
42240 \ ------------------------------\
42241 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
42242 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
42243 \ ------------------------------\
42244 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
42245 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
42246 \ ------------------------------\
42247 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
42248 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
42249 \ ------------------------------\
42250 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
42251 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
42252 \ ------------------------------\
42253 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
42254 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
42255 \ ------------------------------\
42256 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
42257 \ ------------------------------\
42258 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
42259 \ ------------------------------\
42260 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
42261 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
42262 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
42263 \ ------------------------------\
42264 BIS.B #LCDVo,&LCDVo_DIR \
42265 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
42266 \ ------------------------------\
42267 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
42268 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
42269 \ ------------------------------\
42270 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
42271 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
42272 \ ******************************\
42274 \ ******************************\
42275 BIS.B #RC5,&IR_IE \ enable RC5_Int
42276 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
42277 MOV #RC5_INT,&IR_Vec \ init interrupt vector
42278 \ ******************************\
42279 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
42280 \ ******************************\
42281 \ %01 0001 0100 \ TAxCTL
42282 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
42283 \ -- \ ID divided by 1
42284 \ -- \ MC MODE = up to TAxCCRn
42285 \ - \ TACLR clear timer count
42288 \ ------------------------------\
42289 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
42290 \ ------------------------------\
42292 \ --- \ TAIDEX pre divisor
42293 \ ------------------------------\
42294 \ %0000 0000 0000 0101 \ TAxCCR0
42295 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
42296 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
42297 \ ------------------------------\
42298 \ %0000 0000 0001 0000 \ TAxCCTL0
42299 \ - \ CAP capture/compare mode = compare
42302 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
42303 \ ------------------------------\
42304 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
42305 \ ------------------------------\
42306 \ define LPM mode for ACCEPT \
42307 \ ------------------------------\
42308 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
42309 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
42310 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
42312 \ ------------------------------\
42313 \ redirects to background task \
42314 \ ------------------------------\
42316 MOV #BACKGROUND,2(X) \
42317 \ ------------------------------\
42319 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
42321 \ ------------------------------\
42323 \ ------------------------------\
42324 $03E8 20_US \ 1- wait 20 ms
42325 $03 TOP_LCD \ 2- send DB5=DB4=1
42326 $CD 20_US \ 3- wait 4,1 ms
42327 $03 TOP_LCD \ 4- send again DB5=DB4=1
42328 $5 20_US \ 5- wait 0,1 ms
42329 $03 TOP_LCD \ 6- send again again DB5=DB4=1
42330 $2 20_US \ wait 40 us = LCD cycle
42331 $02 TOP_LCD \ 7- send DB5=1 DB4=0
42332 $2 20_US \ wait 40 us = LCD cycle
42333 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
42334 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
42335 LCD_Clear \ 10- "LCD_Clear"
42336 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
42337 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
42338 LCD_Clear \ 10- "LCD_Clear"
42339 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
42340 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
42342 ['] CR >BODY IS CR \
42343 ['] EMIT >BODY IS EMIT \
42344 ." RC5toLCD is running. Type STOP to quit"
42345 LIT RECURSE IS WARM \ replace WARM by this START routine
42346 ABORT \ and continue with the next word after WARM...
42347 ; \ ...until interpreter falls in sleep mode within ACCEPT.
42350 CODE STOP \ stops multitasking, must to be used before downloading app
42351 \ restore default action of primary DEFERred word SLEEP, assembly version
42352 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
42353 ADD #4,X \ X = BODY of SLEEP
42354 MOV X,-2(X) \ restore the default background
42357 \ restore default action of primary DEFERred word WARM, FORTH version
42358 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
42360 COLD \ because we want to reset CPU and interrupt vectors
42365 ; downloading RC5toLCD.4th is done
42366 RST_HERE ; this app is protected against <reset>
42374 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
42376 [DEFINED] ASM [IF] \ security test
42380 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
42382 CODE MAX \ n1 n2 -- n3 signed maximum
42383 CMP @PSP,TOS \ n2-n1
42384 S< ?GOTO FW1 \ n2<n1
42390 CODE MIN \ n1 n2 -- n3 signed minimum
42391 CMP @PSP,TOS \ n2-n1
42392 S< ?GOTO BW1 \ n2<n1
42400 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
42401 : U.R \ u n -- display u unsigned in n width (n >= 2)
42403 R> OVER - 0 MAX SPACES TYPE
42408 \ CODE 20_US \ n -- n * 20 us
42409 \ BEGIN \ 3 cycles loop + 6~
42410 \ \ MOV #5,W \ 3 MCLK = 1 MHz
42411 \ \ MOV #23,W \ 3 MCLK = 4 MHz
42412 \ \ MOV #51,W \ 3 MCLK = 8 MHz
42413 \ MOV #104,W \ 3 MCLK = 16 MHz
42414 \ \ MOV #158,W \ 3 MCLK = 24 MHz
42415 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
42420 \ MOV @PSP+,TOS \ 2
42425 CODE 20_US \ n -- n * 20 us
42426 BEGIN \ here we presume that LCD_TIM_IFG = 1...
42428 BIT #1,&LCD_TIM_CTL \ 3
42429 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
42430 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
42432 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
42438 CODE TOP_LCD \ LCD Sample
42439 \ \ if write : %xxxxWWWW --
42440 \ \ if read : -- %0000RRRR
42441 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
42442 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
42443 0= IF \ write LCD bits pattern
42444 AND.B #LCD_DB,TOS \
42445 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
42446 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
42449 THEN \ read LCD bits pattern
42452 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
42453 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
42454 AND.B #LCD_DB,TOS \
42459 CODE LCD_W \ byte -- write byte to LCD
42461 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
42462 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
42463 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
42464 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
42465 COLON \ high level word starts here
42466 TOP_LCD 2 20_US \ write high nibble first
42471 CODE LCD_WrC \ char -- Write Char
42472 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
42477 CODE LCD_WrF \ func -- Write Fonction
42478 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
42484 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
42489 $02 LCD_WrF 100 20_us
42493 [UNDEFINED] OR [IF]
42495 \ https://forth-standard.org/standard/core/OR
42496 \ C OR x1 x2 -- x3 logical OR
42505 : LCD_Entry_set $04 OR LCD_WrF ;
42507 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
42509 : LCD_DSP_Shift $10 OR LCD_WrF ;
42511 : LCD_Fn_Set $20 OR LCD_WrF ;
42513 : LCD_CGRAM_Set $40 OR LCD_WrF ;
42515 : LCD_Goto $80 OR LCD_WrF ;
42517 CODE LCD_R \ -- byte read byte from LCD
42518 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
42519 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
42520 COLON \ starts a FORTH word
42521 TOP_LCD 2 20_us \ -- %0000HHHH
42522 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
42523 HI2LO \ switch from FORTH to assembler
42524 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
42525 ADD.B @PSP+,TOS \ -- %HHHHLLLL
42526 MOV @RSP+,IP \ restore IP saved by COLON
42531 CODE LCD_RdS \ -- status Read Status
42532 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
42537 CODE LCD_RdC \ -- char Read Char
42538 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
42544 \ ******************************\
42545 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
42546 \ ******************************\
42547 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
42548 BIT.B #SW2,&SW2_IN \ test switch S2
42549 0= IF \ case of switch S2 pressed
42550 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
42552 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
42555 BIT.B #SW1,&SW1_IN \ test switch S1 input
42556 0= IF \ case of Switch S1 pressed
42557 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
42559 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
42563 BW1 \ from quit on truncated RC5 message
42564 BW2 \ from repeated RC5 command
42565 BW3 \ from end of RC5_INT
42566 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
42571 \ ******************************\
42572 ASM RC5_INT \ wake up on Px.RC5 change interrupt
42573 \ ******************************\
42574 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
42575 \ ******************************\
42576 \ \ in : SR(9)=old Toggle bit memory (ADD on)
42577 \ \ SMclock = 8|16|24 MHz
42578 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
42579 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
42580 \ \ SR(9)=new Toggle bit memory (ADD on)
42581 \ ******************************\
42582 \ RC5_FirstStartBitHalfCycle: \
42583 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
42584 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
42585 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
42586 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
42587 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
42588 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
42589 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
42590 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
42591 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
42592 MOV #1778,X \ RC5_Period * 1us
42593 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
42594 MOV #14,W \ count of loop
42596 \ ******************************\
42597 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
42598 \ ******************************\ |
42599 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
42600 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
42601 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
42602 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
42603 \ RC5_Compute_3/4_Period: \ |
42604 RRUM #1,X \ X=1/2 cycle |
42607 ADD X,Y \ Y=3/4 cycle
42608 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
42610 \ ******************************\
42611 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
42612 \ ******************************\
42613 BIT.B #RC5,&IR_IN \ C_flag = IR bit
42614 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
42615 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
42616 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
42617 SUB #1,W \ decrement count loop
42618 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
42619 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
42620 0<> WHILE \ ----> out of loop ----+
42621 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
42623 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
42624 CMP Y,X \ 1 | cycle time out of bound ?
42625 U>= IF \ 2 ^ | yes:
42626 BIC #$30,&RC5_TIM_CTL \ | | stop timer
42627 GOTO BW1 \ | | quit on truncated RC5 message
42629 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
42631 REPEAT \ ----> loop back --+ | with X = new RC5_period value
42632 \ ******************************\ |
42633 \ RC5_SampleEndOf: \ <---------------------+
42634 \ ******************************\
42635 BIC #$30,&RC5_TIM_CTL \ stop timer
42636 \ ******************************\
42637 \ RC5_ComputeNewRC5word \
42638 \ ******************************\
42639 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
42640 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
42641 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
42642 \ ******************************\
42643 \ RC5_ComputeC6bit \
42644 \ ******************************\
42645 BIT #BIT14,T \ test /C6 bit in T
42646 0= IF BIS #BIT6,X \ set C6 bit in X
42647 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
42648 \ ******************************\
42649 \ RC5_CommandByteIsDone \ -- BASE RC5_code
42650 \ ******************************\
42651 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
42652 \ ******************************\
42653 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
42654 XOR @RSP,T \ (new XOR old) Toggle bits
42655 BIT #UF10,T \ repeated RC5_command ?
42656 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
42657 XOR #UF10,0(RSP) \ 5 toggle bit memory
42658 \ ******************************\
42659 \ Display IR_RC5 code \ X = RC5 code
42660 \ ******************************\
42662 MOV &BASE,2(PSP) \ save current base
42663 MOV #$10,&BASE \ set hex base
42664 MOV TOS,0(PSP) \ save TOS
42666 LO2HI \ switch from assembler to FORTH
42667 ['] LCD_CLEAR IS CR \ redirects CR
42668 ['] LCD_WrC IS EMIT \ redirects EMIT
42669 CR ." $" 2 U.R \ print IR_RC5 code
42670 ['] CR >BODY IS CR \ restore CR
42671 ['] EMIT >BODY IS EMIT \ restore EMIT
42672 HI2LO \ switch from FORTH to assembler
42673 MOV TOS,&BASE \ restore current BASE
42675 \ ******************************\
42677 \ ******************************\
42681 \ ------------------------------\
42683 \ ------------------------------\
42684 \ ... \ insert here your background task
42687 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
42688 ADD #4,X \ 1 X = BODY of SLEEP
42691 \ ------------------------------\
42695 \ ------------------------------\
42696 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
42697 \ - - \CNTL Counter lentgh \ 00 = 16 bits
42698 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
42699 \ -- \ID input divider \ 10 = /4
42700 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
42701 \ - \TBCLR TimerB Clear
42704 \ -------------------------------\
42705 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
42706 \ -- \CM Capture Mode
42711 \ --- \OUTMOD \ 011 = set/reset
42717 \ -------------------------------\
42719 \ -------------------------------\
42721 \ ------------------------------\
42722 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
42723 \ ------------------------------\
42724 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
42725 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
42726 \ ------------------------------\
42727 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
42728 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
42729 \ ------------------------------\
42730 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
42731 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
42732 \ ------------------------------\
42733 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
42734 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
42735 \ ------------------------------\
42736 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
42737 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
42738 \ ------------------------------\
42739 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
42740 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
42741 \ ------------------------------\
42742 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
42743 \ ------------------------------\
42744 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
42745 \ ------------------------------\
42746 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
42747 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
42748 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
42749 \ ------------------------------\
42750 BIS.B #LCDVo,&LCDVo_DIR \
42751 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
42752 \ ------------------------------\
42753 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
42754 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
42755 \ ------------------------------\
42756 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
42757 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
42758 \ ******************************\
42760 \ ******************************\
42761 BIS.B #RC5,&IR_IE \ enable RC5_Int
42762 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
42763 MOV #RC5_INT,&IR_Vec \ init interrupt vector
42764 \ ******************************\
42765 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
42766 \ ******************************\
42767 \ %01 0001 0100 \ TAxCTL
42768 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
42769 \ -- \ ID divided by 1
42770 \ -- \ MC MODE = up to TAxCCRn
42771 \ - \ TACLR clear timer count
42774 \ ------------------------------\
42775 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
42776 \ ------------------------------\
42778 \ --- \ TAIDEX pre divisor
42779 \ ------------------------------\
42780 \ %0000 0000 0000 0101 \ TAxCCR0
42781 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
42782 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
42783 \ ------------------------------\
42784 \ %0000 0000 0001 0000 \ TAxCCTL0
42785 \ - \ CAP capture/compare mode = compare
42788 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
42789 \ ------------------------------\
42790 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
42791 \ ------------------------------\
42792 \ define LPM mode for ACCEPT \
42793 \ ------------------------------\
42794 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
42795 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
42796 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
42798 \ ------------------------------\
42799 \ redirects to background task \
42800 \ ------------------------------\
42802 MOV #BACKGROUND,2(X) \
42803 \ ------------------------------\
42805 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
42807 \ ------------------------------\
42809 \ ------------------------------\
42810 $03E8 20_US \ 1- wait 20 ms
42811 $03 TOP_LCD \ 2- send DB5=DB4=1
42812 $CD 20_US \ 3- wait 4,1 ms
42813 $03 TOP_LCD \ 4- send again DB5=DB4=1
42814 $5 20_US \ 5- wait 0,1 ms
42815 $03 TOP_LCD \ 6- send again again DB5=DB4=1
42816 $2 20_US \ wait 40 us = LCD cycle
42817 $02 TOP_LCD \ 7- send DB5=1 DB4=0
42818 $2 20_US \ wait 40 us = LCD cycle
42819 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
42820 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
42821 LCD_Clear \ 10- "LCD_Clear"
42822 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
42823 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
42824 LCD_Clear \ 10- "LCD_Clear"
42825 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
42826 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
42828 ['] CR >BODY IS CR \
42829 ['] EMIT >BODY IS EMIT \
42830 ." RC5toLCD is running. Type STOP to quit"
42831 LIT RECURSE IS WARM \ replace WARM by this START routine
42832 ABORT \ and continue with the next word after WARM...
42833 ; \ ...until interpreter falls in sleep mode within ACCEPT.
42836 CODE STOP \ stops multitasking, must to be used before downloading app
42837 \ restore default action of primary DEFERred word SLEEP, assembly version
42838 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
42839 ADD #4,X \ X = BODY of SLEEP
42840 MOV X,-2(X) \ restore the default background
42843 \ restore default action of primary DEFERred word WARM, FORTH version
42844 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
42846 COLD \ because we want to reset CPU and interrupt vectors
42851 ; downloading RC5toLCD.4th is done
42852 RST_HERE ; this app is protected against <reset>
42860 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
42862 [DEFINED] ASM [IF] \ security test
42866 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
42868 CODE MAX \ n1 n2 -- n3 signed maximum
42869 CMP @PSP,TOS \ n2-n1
42870 S< ?GOTO FW1 \ n2<n1
42876 CODE MIN \ n1 n2 -- n3 signed minimum
42877 CMP @PSP,TOS \ n2-n1
42878 S< ?GOTO BW1 \ n2<n1
42886 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
42887 : U.R \ u n -- display u unsigned in n width (n >= 2)
42889 R> OVER - 0 MAX SPACES TYPE
42894 \ CODE 20_US \ n -- n * 20 us
42895 \ BEGIN \ 3 cycles loop + 6~
42896 \ \ MOV #5,W \ 3 MCLK = 1 MHz
42897 \ \ MOV #23,W \ 3 MCLK = 4 MHz
42898 \ \ MOV #51,W \ 3 MCLK = 8 MHz
42899 \ MOV #104,W \ 3 MCLK = 16 MHz
42900 \ \ MOV #158,W \ 3 MCLK = 24 MHz
42901 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
42906 \ MOV @PSP+,TOS \ 2
42911 CODE 20_US \ n -- n * 20 us
42912 BEGIN \ here we presume that LCD_TIM_IFG = 1...
42914 BIT #1,&LCD_TIM_CTL \ 3
42915 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
42916 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
42918 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
42924 CODE TOP_LCD \ LCD Sample
42925 \ \ if write : %xxxxWWWW --
42926 \ \ if read : -- %0000RRRR
42927 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
42928 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
42929 0= IF \ write LCD bits pattern
42930 AND.B #LCD_DB,TOS \
42931 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
42932 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
42935 THEN \ read LCD bits pattern
42938 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
42939 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
42940 AND.B #LCD_DB,TOS \
42945 CODE LCD_W \ byte -- write byte to LCD
42947 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
42948 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
42949 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
42950 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
42951 COLON \ high level word starts here
42952 TOP_LCD 2 20_US \ write high nibble first
42957 CODE LCD_WrC \ char -- Write Char
42958 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
42963 CODE LCD_WrF \ func -- Write Fonction
42964 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
42970 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
42975 $02 LCD_WrF 100 20_us
42979 [UNDEFINED] OR [IF]
42981 \ https://forth-standard.org/standard/core/OR
42982 \ C OR x1 x2 -- x3 logical OR
42991 : LCD_Entry_set $04 OR LCD_WrF ;
42993 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
42995 : LCD_DSP_Shift $10 OR LCD_WrF ;
42997 : LCD_Fn_Set $20 OR LCD_WrF ;
42999 : LCD_CGRAM_Set $40 OR LCD_WrF ;
43001 : LCD_Goto $80 OR LCD_WrF ;
43003 CODE LCD_R \ -- byte read byte from LCD
43004 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
43005 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
43006 COLON \ starts a FORTH word
43007 TOP_LCD 2 20_us \ -- %0000HHHH
43008 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
43009 HI2LO \ switch from FORTH to assembler
43010 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
43011 ADD.B @PSP+,TOS \ -- %HHHHLLLL
43012 MOV @RSP+,IP \ restore IP saved by COLON
43017 CODE LCD_RdS \ -- status Read Status
43018 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
43023 CODE LCD_RdC \ -- char Read Char
43024 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
43030 \ ******************************\
43031 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
43032 \ ******************************\
43033 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
43034 BIT.B #SW2,&SW2_IN \ test switch S2
43035 0= IF \ case of switch S2 pressed
43036 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
43038 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
43041 BIT.B #SW1,&SW1_IN \ test switch S1 input
43042 0= IF \ case of Switch S1 pressed
43043 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
43045 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
43049 BW1 \ from quit on truncated RC5 message
43050 BW2 \ from repeated RC5 command
43051 BW3 \ from end of RC5_INT
43052 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
43057 \ ******************************\
43058 ASM RC5_INT \ wake up on Px.RC5 change interrupt
43059 \ ******************************\
43060 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
43061 \ ******************************\
43062 \ \ in : SR(9)=old Toggle bit memory (ADD on)
43063 \ \ SMclock = 8|16|24 MHz
43064 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
43065 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
43066 \ \ SR(9)=new Toggle bit memory (ADD on)
43067 \ ******************************\
43068 \ RC5_FirstStartBitHalfCycle: \
43069 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
43070 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
43071 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
43072 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
43073 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
43074 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
43075 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
43076 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
43077 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
43078 MOV #1778,X \ RC5_Period * 1us
43079 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
43080 MOV #14,W \ count of loop
43082 \ ******************************\
43083 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
43084 \ ******************************\ |
43085 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
43086 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
43087 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
43088 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
43089 \ RC5_Compute_3/4_Period: \ |
43090 RRUM #1,X \ X=1/2 cycle |
43093 ADD X,Y \ Y=3/4 cycle
43094 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
43096 \ ******************************\
43097 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
43098 \ ******************************\
43099 BIT.B #RC5,&IR_IN \ C_flag = IR bit
43100 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
43101 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
43102 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
43103 SUB #1,W \ decrement count loop
43104 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
43105 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
43106 0<> WHILE \ ----> out of loop ----+
43107 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
43109 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
43110 CMP Y,X \ 1 | cycle time out of bound ?
43111 U>= IF \ 2 ^ | yes:
43112 BIC #$30,&RC5_TIM_CTL \ | | stop timer
43113 GOTO BW1 \ | | quit on truncated RC5 message
43115 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
43117 REPEAT \ ----> loop back --+ | with X = new RC5_period value
43118 \ ******************************\ |
43119 \ RC5_SampleEndOf: \ <---------------------+
43120 \ ******************************\
43121 BIC #$30,&RC5_TIM_CTL \ stop timer
43122 \ ******************************\
43123 \ RC5_ComputeNewRC5word \
43124 \ ******************************\
43125 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
43126 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
43127 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
43128 \ ******************************\
43129 \ RC5_ComputeC6bit \
43130 \ ******************************\
43131 BIT #BIT14,T \ test /C6 bit in T
43132 0= IF BIS #BIT6,X \ set C6 bit in X
43133 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
43134 \ ******************************\
43135 \ RC5_CommandByteIsDone \ -- BASE RC5_code
43136 \ ******************************\
43137 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
43138 \ ******************************\
43139 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
43140 XOR @RSP,T \ (new XOR old) Toggle bits
43141 BIT #UF10,T \ repeated RC5_command ?
43142 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
43143 XOR #UF10,0(RSP) \ 5 toggle bit memory
43144 \ ******************************\
43145 \ Display IR_RC5 code \ X = RC5 code
43146 \ ******************************\
43148 MOV &BASE,2(PSP) \ save current base
43149 MOV #$10,&BASE \ set hex base
43150 MOV TOS,0(PSP) \ save TOS
43152 LO2HI \ switch from assembler to FORTH
43153 ['] LCD_CLEAR IS CR \ redirects CR
43154 ['] LCD_WrC IS EMIT \ redirects EMIT
43155 CR ." $" 2 U.R \ print IR_RC5 code
43156 ['] CR >BODY IS CR \ restore CR
43157 ['] EMIT >BODY IS EMIT \ restore EMIT
43158 HI2LO \ switch from FORTH to assembler
43159 MOV TOS,&BASE \ restore current BASE
43161 \ ******************************\
43163 \ ******************************\
43167 \ ------------------------------\
43169 \ ------------------------------\
43170 \ ... \ insert here your background task
43173 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
43174 ADD #4,X \ 1 X = BODY of SLEEP
43177 \ ------------------------------\
43181 \ ------------------------------\
43182 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
43183 \ - - \CNTL Counter lentgh \ 00 = 16 bits
43184 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
43185 \ -- \ID input divider \ 10 = /4
43186 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
43187 \ - \TBCLR TimerB Clear
43190 \ -------------------------------\
43191 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
43192 \ -- \CM Capture Mode
43197 \ --- \OUTMOD \ 011 = set/reset
43203 \ -------------------------------\
43205 \ -------------------------------\
43207 \ ------------------------------\
43208 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
43209 \ ------------------------------\
43210 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
43211 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
43212 \ ------------------------------\
43213 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
43214 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
43215 \ ------------------------------\
43216 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
43217 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
43218 \ ------------------------------\
43219 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
43220 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
43221 \ ------------------------------\
43222 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
43223 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
43224 \ ------------------------------\
43225 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
43226 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
43227 \ ------------------------------\
43228 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
43229 \ ------------------------------\
43230 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
43231 \ ------------------------------\
43232 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
43233 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
43234 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
43235 \ ------------------------------\
43236 BIS.B #LCDVo,&LCDVo_DIR \
43237 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
43238 \ ------------------------------\
43239 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
43240 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
43241 \ ------------------------------\
43242 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
43243 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
43244 \ ******************************\
43246 \ ******************************\
43247 BIS.B #RC5,&IR_IE \ enable RC5_Int
43248 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
43249 MOV #RC5_INT,&IR_Vec \ init interrupt vector
43250 \ ******************************\
43251 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
43252 \ ******************************\
43253 \ %01 0001 0100 \ TAxCTL
43254 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
43255 \ -- \ ID divided by 1
43256 \ -- \ MC MODE = up to TAxCCRn
43257 \ - \ TACLR clear timer count
43260 \ ------------------------------\
43261 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
43262 \ ------------------------------\
43264 \ --- \ TAIDEX pre divisor
43265 \ ------------------------------\
43266 \ %0000 0000 0000 0101 \ TAxCCR0
43267 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
43268 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
43269 \ ------------------------------\
43270 \ %0000 0000 0001 0000 \ TAxCCTL0
43271 \ - \ CAP capture/compare mode = compare
43274 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
43275 \ ------------------------------\
43276 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
43277 \ ------------------------------\
43278 \ define LPM mode for ACCEPT \
43279 \ ------------------------------\
43280 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
43281 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
43282 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
43284 \ ------------------------------\
43285 \ redirects to background task \
43286 \ ------------------------------\
43288 MOV #BACKGROUND,2(X) \
43289 \ ------------------------------\
43291 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
43293 \ ------------------------------\
43295 \ ------------------------------\
43296 $03E8 20_US \ 1- wait 20 ms
43297 $03 TOP_LCD \ 2- send DB5=DB4=1
43298 $CD 20_US \ 3- wait 4,1 ms
43299 $03 TOP_LCD \ 4- send again DB5=DB4=1
43300 $5 20_US \ 5- wait 0,1 ms
43301 $03 TOP_LCD \ 6- send again again DB5=DB4=1
43302 $2 20_US \ wait 40 us = LCD cycle
43303 $02 TOP_LCD \ 7- send DB5=1 DB4=0
43304 $2 20_US \ wait 40 us = LCD cycle
43305 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
43306 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
43307 LCD_Clear \ 10- "LCD_Clear"
43308 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
43309 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
43310 LCD_Clear \ 10- "LCD_Clear"
43311 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
43312 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
43314 ['] CR >BODY IS CR \
43315 ['] EMIT >BODY IS EMIT \
43316 ." RC5toLCD is running. Type STOP to quit"
43317 LIT RECURSE IS WARM \ replace WARM by this START routine
43318 ABORT \ and continue with the next word after WARM...
43319 ; \ ...until interpreter falls in sleep mode within ACCEPT.
43322 CODE STOP \ stops multitasking, must to be used before downloading app
43323 \ restore default action of primary DEFERred word SLEEP, assembly version
43324 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
43325 ADD #4,X \ X = BODY of SLEEP
43326 MOV X,-2(X) \ restore the default background
43329 \ restore default action of primary DEFERred word WARM, FORTH version
43330 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
43332 COLD \ because we want to reset CPU and interrupt vectors
43337 ; downloading RC5toLCD.4th is done
43338 RST_HERE ; this app is protected against <reset>
43346 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
43348 [DEFINED] ASM [IF] \ security test
43352 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
43354 CODE MAX \ n1 n2 -- n3 signed maximum
43355 CMP @PSP,TOS \ n2-n1
43356 S< ?GOTO FW1 \ n2<n1
43362 CODE MIN \ n1 n2 -- n3 signed minimum
43363 CMP @PSP,TOS \ n2-n1
43364 S< ?GOTO BW1 \ n2<n1
43372 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
43373 : U.R \ u n -- display u unsigned in n width (n >= 2)
43375 R> OVER - 0 MAX SPACES TYPE
43380 \ CODE 20_US \ n -- n * 20 us
43381 \ BEGIN \ 3 cycles loop + 6~
43382 \ \ MOV #5,W \ 3 MCLK = 1 MHz
43383 \ \ MOV #23,W \ 3 MCLK = 4 MHz
43384 \ \ MOV #51,W \ 3 MCLK = 8 MHz
43385 \ MOV #104,W \ 3 MCLK = 16 MHz
43386 \ \ MOV #158,W \ 3 MCLK = 24 MHz
43387 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
43392 \ MOV @PSP+,TOS \ 2
43397 CODE 20_US \ n -- n * 20 us
43398 BEGIN \ here we presume that LCD_TIM_IFG = 1...
43400 BIT #1,&LCD_TIM_CTL \ 3
43401 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
43402 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
43404 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
43410 CODE TOP_LCD \ LCD Sample
43411 \ \ if write : %xxxxWWWW --
43412 \ \ if read : -- %0000RRRR
43413 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
43414 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
43415 0= IF \ write LCD bits pattern
43416 AND.B #LCD_DB,TOS \
43417 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
43418 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
43421 THEN \ read LCD bits pattern
43424 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
43425 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
43426 AND.B #LCD_DB,TOS \
43431 CODE LCD_W \ byte -- write byte to LCD
43433 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
43434 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
43435 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
43436 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
43437 COLON \ high level word starts here
43438 TOP_LCD 2 20_US \ write high nibble first
43443 CODE LCD_WrC \ char -- Write Char
43444 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
43449 CODE LCD_WrF \ func -- Write Fonction
43450 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
43456 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
43461 $02 LCD_WrF 100 20_us
43465 [UNDEFINED] OR [IF]
43467 \ https://forth-standard.org/standard/core/OR
43468 \ C OR x1 x2 -- x3 logical OR
43477 : LCD_Entry_set $04 OR LCD_WrF ;
43479 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
43481 : LCD_DSP_Shift $10 OR LCD_WrF ;
43483 : LCD_Fn_Set $20 OR LCD_WrF ;
43485 : LCD_CGRAM_Set $40 OR LCD_WrF ;
43487 : LCD_Goto $80 OR LCD_WrF ;
43489 CODE LCD_R \ -- byte read byte from LCD
43490 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
43491 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
43492 COLON \ starts a FORTH word
43493 TOP_LCD 2 20_us \ -- %0000HHHH
43494 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
43495 HI2LO \ switch from FORTH to assembler
43496 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
43497 ADD.B @PSP+,TOS \ -- %HHHHLLLL
43498 MOV @RSP+,IP \ restore IP saved by COLON
43503 CODE LCD_RdS \ -- status Read Status
43504 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
43509 CODE LCD_RdC \ -- char Read Char
43510 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
43516 \ ******************************\
43517 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
43518 \ ******************************\
43519 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
43520 BIT.B #SW2,&SW2_IN \ test switch S2
43521 0= IF \ case of switch S2 pressed
43522 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
43524 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
43527 BIT.B #SW1,&SW1_IN \ test switch S1 input
43528 0= IF \ case of Switch S1 pressed
43529 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
43531 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
43535 BW1 \ from quit on truncated RC5 message
43536 BW2 \ from repeated RC5 command
43537 BW3 \ from end of RC5_INT
43538 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
43543 \ ******************************\
43544 ASM RC5_INT \ wake up on Px.RC5 change interrupt
43545 \ ******************************\
43546 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
43547 \ ******************************\
43548 \ \ in : SR(9)=old Toggle bit memory (ADD on)
43549 \ \ SMclock = 8|16|24 MHz
43550 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
43551 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
43552 \ \ SR(9)=new Toggle bit memory (ADD on)
43553 \ ******************************\
43554 \ RC5_FirstStartBitHalfCycle: \
43555 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
43556 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
43557 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
43558 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
43559 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
43560 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
43561 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
43562 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
43563 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
43564 MOV #1778,X \ RC5_Period * 1us
43565 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
43566 MOV #14,W \ count of loop
43568 \ ******************************\
43569 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
43570 \ ******************************\ |
43571 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
43572 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
43573 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
43574 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
43575 \ RC5_Compute_3/4_Period: \ |
43576 RRUM #1,X \ X=1/2 cycle |
43579 ADD X,Y \ Y=3/4 cycle
43580 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
43582 \ ******************************\
43583 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
43584 \ ******************************\
43585 BIT.B #RC5,&IR_IN \ C_flag = IR bit
43586 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
43587 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
43588 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
43589 SUB #1,W \ decrement count loop
43590 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
43591 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
43592 0<> WHILE \ ----> out of loop ----+
43593 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
43595 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
43596 CMP Y,X \ 1 | cycle time out of bound ?
43597 U>= IF \ 2 ^ | yes:
43598 BIC #$30,&RC5_TIM_CTL \ | | stop timer
43599 GOTO BW1 \ | | quit on truncated RC5 message
43601 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
43603 REPEAT \ ----> loop back --+ | with X = new RC5_period value
43604 \ ******************************\ |
43605 \ RC5_SampleEndOf: \ <---------------------+
43606 \ ******************************\
43607 BIC #$30,&RC5_TIM_CTL \ stop timer
43608 \ ******************************\
43609 \ RC5_ComputeNewRC5word \
43610 \ ******************************\
43611 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
43612 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
43613 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
43614 \ ******************************\
43615 \ RC5_ComputeC6bit \
43616 \ ******************************\
43617 BIT #BIT14,T \ test /C6 bit in T
43618 0= IF BIS #BIT6,X \ set C6 bit in X
43619 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
43620 \ ******************************\
43621 \ RC5_CommandByteIsDone \ -- BASE RC5_code
43622 \ ******************************\
43623 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
43624 \ ******************************\
43625 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
43626 XOR @RSP,T \ (new XOR old) Toggle bits
43627 BIT #UF10,T \ repeated RC5_command ?
43628 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
43629 XOR #UF10,0(RSP) \ 5 toggle bit memory
43630 \ ******************************\
43631 \ Display IR_RC5 code \ X = RC5 code
43632 \ ******************************\
43634 MOV &BASE,2(PSP) \ save current base
43635 MOV #$10,&BASE \ set hex base
43636 MOV TOS,0(PSP) \ save TOS
43638 LO2HI \ switch from assembler to FORTH
43639 ['] LCD_CLEAR IS CR \ redirects CR
43640 ['] LCD_WrC IS EMIT \ redirects EMIT
43641 CR ." $" 2 U.R \ print IR_RC5 code
43642 ['] CR >BODY IS CR \ restore CR
43643 ['] EMIT >BODY IS EMIT \ restore EMIT
43644 HI2LO \ switch from FORTH to assembler
43645 MOV TOS,&BASE \ restore current BASE
43647 \ ******************************\
43649 \ ******************************\
43653 \ ------------------------------\
43655 \ ------------------------------\
43656 \ ... \ insert here your background task
43659 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
43660 ADD #4,X \ 1 X = BODY of SLEEP
43663 \ ------------------------------\
43667 \ ------------------------------\
43668 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
43669 \ - - \CNTL Counter lentgh \ 00 = 16 bits
43670 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
43671 \ -- \ID input divider \ 10 = /4
43672 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
43673 \ - \TBCLR TimerB Clear
43676 \ -------------------------------\
43677 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
43678 \ -- \CM Capture Mode
43683 \ --- \OUTMOD \ 011 = set/reset
43689 \ -------------------------------\
43691 \ -------------------------------\
43693 \ ------------------------------\
43694 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
43695 \ ------------------------------\
43696 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
43697 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
43698 \ ------------------------------\
43699 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
43700 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
43701 \ ------------------------------\
43702 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
43703 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
43704 \ ------------------------------\
43705 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
43706 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
43707 \ ------------------------------\
43708 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
43709 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
43710 \ ------------------------------\
43711 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
43712 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
43713 \ ------------------------------\
43714 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
43715 \ ------------------------------\
43716 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
43717 \ ------------------------------\
43718 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
43719 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
43720 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
43721 \ ------------------------------\
43722 BIS.B #LCDVo,&LCDVo_DIR \
43723 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
43724 \ ------------------------------\
43725 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
43726 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
43727 \ ------------------------------\
43728 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
43729 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
43730 \ ******************************\
43732 \ ******************************\
43733 BIS.B #RC5,&IR_IE \ enable RC5_Int
43734 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
43735 MOV #RC5_INT,&IR_Vec \ init interrupt vector
43736 \ ******************************\
43737 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
43738 \ ******************************\
43739 \ %01 0001 0100 \ TAxCTL
43740 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
43741 \ -- \ ID divided by 1
43742 \ -- \ MC MODE = up to TAxCCRn
43743 \ - \ TACLR clear timer count
43746 \ ------------------------------\
43747 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
43748 \ ------------------------------\
43750 \ --- \ TAIDEX pre divisor
43751 \ ------------------------------\
43752 \ %0000 0000 0000 0101 \ TAxCCR0
43753 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
43754 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
43755 \ ------------------------------\
43756 \ %0000 0000 0001 0000 \ TAxCCTL0
43757 \ - \ CAP capture/compare mode = compare
43760 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
43761 \ ------------------------------\
43762 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
43763 \ ------------------------------\
43764 \ define LPM mode for ACCEPT \
43765 \ ------------------------------\
43766 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
43767 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
43768 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
43770 \ ------------------------------\
43771 \ redirects to background task \
43772 \ ------------------------------\
43774 MOV #BACKGROUND,2(X) \
43775 \ ------------------------------\
43777 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
43779 \ ------------------------------\
43781 \ ------------------------------\
43782 $03E8 20_US \ 1- wait 20 ms
43783 $03 TOP_LCD \ 2- send DB5=DB4=1
43784 $CD 20_US \ 3- wait 4,1 ms
43785 $03 TOP_LCD \ 4- send again DB5=DB4=1
43786 $5 20_US \ 5- wait 0,1 ms
43787 $03 TOP_LCD \ 6- send again again DB5=DB4=1
43788 $2 20_US \ wait 40 us = LCD cycle
43789 $02 TOP_LCD \ 7- send DB5=1 DB4=0
43790 $2 20_US \ wait 40 us = LCD cycle
43791 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
43792 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
43793 LCD_Clear \ 10- "LCD_Clear"
43794 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
43795 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
43796 LCD_Clear \ 10- "LCD_Clear"
43797 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
43798 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
43800 ['] CR >BODY IS CR \
43801 ['] EMIT >BODY IS EMIT \
43802 ." RC5toLCD is running. Type STOP to quit"
43803 LIT RECURSE IS WARM \ replace WARM by this START routine
43804 ABORT \ and continue with the next word after WARM...
43805 ; \ ...until interpreter falls in sleep mode within ACCEPT.
43808 CODE STOP \ stops multitasking, must to be used before downloading app
43809 \ restore default action of primary DEFERred word SLEEP, assembly version
43810 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
43811 ADD #4,X \ X = BODY of SLEEP
43812 MOV X,-2(X) \ restore the default background
43815 \ restore default action of primary DEFERred word WARM, FORTH version
43816 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
43818 COLD \ because we want to reset CPU and interrupt vectors
43823 ; downloading RC5toLCD.4th is done
43824 RST_HERE ; this app is protected against <reset>
43832 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
43834 [DEFINED] ASM [IF] \ security test
43838 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
43840 CODE MAX \ n1 n2 -- n3 signed maximum
43841 CMP @PSP,TOS \ n2-n1
43842 S< ?GOTO FW1 \ n2<n1
43848 CODE MIN \ n1 n2 -- n3 signed minimum
43849 CMP @PSP,TOS \ n2-n1
43850 S< ?GOTO BW1 \ n2<n1
43858 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
43859 : U.R \ u n -- display u unsigned in n width (n >= 2)
43861 R> OVER - 0 MAX SPACES TYPE
43866 \ CODE 20_US \ n -- n * 20 us
43867 \ BEGIN \ 3 cycles loop + 6~
43868 \ \ MOV #5,W \ 3 MCLK = 1 MHz
43869 \ \ MOV #23,W \ 3 MCLK = 4 MHz
43870 \ \ MOV #51,W \ 3 MCLK = 8 MHz
43871 \ MOV #104,W \ 3 MCLK = 16 MHz
43872 \ \ MOV #158,W \ 3 MCLK = 24 MHz
43873 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
43878 \ MOV @PSP+,TOS \ 2
43883 CODE 20_US \ n -- n * 20 us
43884 BEGIN \ here we presume that LCD_TIM_IFG = 1...
43886 BIT #1,&LCD_TIM_CTL \ 3
43887 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
43888 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
43890 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
43896 CODE TOP_LCD \ LCD Sample
43897 \ \ if write : %xxxxWWWW --
43898 \ \ if read : -- %0000RRRR
43899 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
43900 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
43901 0= IF \ write LCD bits pattern
43902 AND.B #LCD_DB,TOS \
43903 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
43904 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
43907 THEN \ read LCD bits pattern
43910 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
43911 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
43912 AND.B #LCD_DB,TOS \
43917 CODE LCD_W \ byte -- write byte to LCD
43919 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
43920 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
43921 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
43922 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
43923 COLON \ high level word starts here
43924 TOP_LCD 2 20_US \ write high nibble first
43929 CODE LCD_WrC \ char -- Write Char
43930 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
43935 CODE LCD_WrF \ func -- Write Fonction
43936 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
43942 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
43947 $02 LCD_WrF 100 20_us
43951 [UNDEFINED] OR [IF]
43953 \ https://forth-standard.org/standard/core/OR
43954 \ C OR x1 x2 -- x3 logical OR
43963 : LCD_Entry_set $04 OR LCD_WrF ;
43965 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
43967 : LCD_DSP_Shift $10 OR LCD_WrF ;
43969 : LCD_Fn_Set $20 OR LCD_WrF ;
43971 : LCD_CGRAM_Set $40 OR LCD_WrF ;
43973 : LCD_Goto $80 OR LCD_WrF ;
43975 CODE LCD_R \ -- byte read byte from LCD
43976 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
43977 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
43978 COLON \ starts a FORTH word
43979 TOP_LCD 2 20_us \ -- %0000HHHH
43980 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
43981 HI2LO \ switch from FORTH to assembler
43982 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
43983 ADD.B @PSP+,TOS \ -- %HHHHLLLL
43984 MOV @RSP+,IP \ restore IP saved by COLON
43989 CODE LCD_RdS \ -- status Read Status
43990 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
43995 CODE LCD_RdC \ -- char Read Char
43996 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
44002 \ ******************************\
44003 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
44004 \ ******************************\
44005 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
44006 BIT.B #SW2,&SW2_IN \ test switch S2
44007 0= IF \ case of switch S2 pressed
44008 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
44010 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
44013 BIT.B #SW1,&SW1_IN \ test switch S1 input
44014 0= IF \ case of Switch S1 pressed
44015 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
44017 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
44021 BW1 \ from quit on truncated RC5 message
44022 BW2 \ from repeated RC5 command
44023 BW3 \ from end of RC5_INT
44024 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
44029 \ ******************************\
44030 ASM RC5_INT \ wake up on Px.RC5 change interrupt
44031 \ ******************************\
44032 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
44033 \ ******************************\
44034 \ \ in : SR(9)=old Toggle bit memory (ADD on)
44035 \ \ SMclock = 8|16|24 MHz
44036 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
44037 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
44038 \ \ SR(9)=new Toggle bit memory (ADD on)
44039 \ ******************************\
44040 \ RC5_FirstStartBitHalfCycle: \
44041 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
44042 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
44043 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
44044 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
44045 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
44046 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
44047 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
44048 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
44049 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
44050 MOV #1778,X \ RC5_Period * 1us
44051 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
44052 MOV #14,W \ count of loop
44054 \ ******************************\
44055 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
44056 \ ******************************\ |
44057 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
44058 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
44059 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
44060 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
44061 \ RC5_Compute_3/4_Period: \ |
44062 RRUM #1,X \ X=1/2 cycle |
44065 ADD X,Y \ Y=3/4 cycle
44066 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
44068 \ ******************************\
44069 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
44070 \ ******************************\
44071 BIT.B #RC5,&IR_IN \ C_flag = IR bit
44072 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
44073 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
44074 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
44075 SUB #1,W \ decrement count loop
44076 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
44077 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
44078 0<> WHILE \ ----> out of loop ----+
44079 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
44081 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
44082 CMP Y,X \ 1 | cycle time out of bound ?
44083 U>= IF \ 2 ^ | yes:
44084 BIC #$30,&RC5_TIM_CTL \ | | stop timer
44085 GOTO BW1 \ | | quit on truncated RC5 message
44087 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
44089 REPEAT \ ----> loop back --+ | with X = new RC5_period value
44090 \ ******************************\ |
44091 \ RC5_SampleEndOf: \ <---------------------+
44092 \ ******************************\
44093 BIC #$30,&RC5_TIM_CTL \ stop timer
44094 \ ******************************\
44095 \ RC5_ComputeNewRC5word \
44096 \ ******************************\
44097 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
44098 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
44099 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
44100 \ ******************************\
44101 \ RC5_ComputeC6bit \
44102 \ ******************************\
44103 BIT #BIT14,T \ test /C6 bit in T
44104 0= IF BIS #BIT6,X \ set C6 bit in X
44105 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
44106 \ ******************************\
44107 \ RC5_CommandByteIsDone \ -- BASE RC5_code
44108 \ ******************************\
44109 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
44110 \ ******************************\
44111 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
44112 XOR @RSP,T \ (new XOR old) Toggle bits
44113 BIT #UF10,T \ repeated RC5_command ?
44114 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
44115 XOR #UF10,0(RSP) \ 5 toggle bit memory
44116 \ ******************************\
44117 \ Display IR_RC5 code \ X = RC5 code
44118 \ ******************************\
44120 MOV &BASE,2(PSP) \ save current base
44121 MOV #$10,&BASE \ set hex base
44122 MOV TOS,0(PSP) \ save TOS
44124 LO2HI \ switch from assembler to FORTH
44125 ['] LCD_CLEAR IS CR \ redirects CR
44126 ['] LCD_WrC IS EMIT \ redirects EMIT
44127 CR ." $" 2 U.R \ print IR_RC5 code
44128 ['] CR >BODY IS CR \ restore CR
44129 ['] EMIT >BODY IS EMIT \ restore EMIT
44130 HI2LO \ switch from FORTH to assembler
44131 MOV TOS,&BASE \ restore current BASE
44133 \ ******************************\
44135 \ ******************************\
44139 \ ------------------------------\
44141 \ ------------------------------\
44142 \ ... \ insert here your background task
44145 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
44146 ADD #4,X \ 1 X = BODY of SLEEP
44149 \ ------------------------------\
44153 \ ------------------------------\
44154 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
44155 \ - - \CNTL Counter lentgh \ 00 = 16 bits
44156 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
44157 \ -- \ID input divider \ 10 = /4
44158 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
44159 \ - \TBCLR TimerB Clear
44162 \ -------------------------------\
44163 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
44164 \ -- \CM Capture Mode
44169 \ --- \OUTMOD \ 011 = set/reset
44175 \ -------------------------------\
44177 \ -------------------------------\
44179 \ ------------------------------\
44180 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
44181 \ ------------------------------\
44182 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
44183 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
44184 \ ------------------------------\
44185 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
44186 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
44187 \ ------------------------------\
44188 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
44189 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
44190 \ ------------------------------\
44191 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
44192 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
44193 \ ------------------------------\
44194 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
44195 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
44196 \ ------------------------------\
44197 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
44198 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
44199 \ ------------------------------\
44200 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
44201 \ ------------------------------\
44202 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
44203 \ ------------------------------\
44204 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
44205 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
44206 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
44207 \ ------------------------------\
44208 BIS.B #LCDVo,&LCDVo_DIR \
44209 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
44210 \ ------------------------------\
44211 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
44212 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
44213 \ ------------------------------\
44214 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
44215 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
44216 \ ******************************\
44218 \ ******************************\
44219 BIS.B #RC5,&IR_IE \ enable RC5_Int
44220 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
44221 MOV #RC5_INT,&IR_Vec \ init interrupt vector
44222 \ ******************************\
44223 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
44224 \ ******************************\
44225 \ %01 0001 0100 \ TAxCTL
44226 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
44227 \ -- \ ID divided by 1
44228 \ -- \ MC MODE = up to TAxCCRn
44229 \ - \ TACLR clear timer count
44232 \ ------------------------------\
44233 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
44234 \ ------------------------------\
44236 \ --- \ TAIDEX pre divisor
44237 \ ------------------------------\
44238 \ %0000 0000 0000 0101 \ TAxCCR0
44239 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
44240 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
44241 \ ------------------------------\
44242 \ %0000 0000 0001 0000 \ TAxCCTL0
44243 \ - \ CAP capture/compare mode = compare
44246 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
44247 \ ------------------------------\
44248 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
44249 \ ------------------------------\
44250 \ define LPM mode for ACCEPT \
44251 \ ------------------------------\
44252 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
44253 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
44254 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
44256 \ ------------------------------\
44257 \ redirects to background task \
44258 \ ------------------------------\
44260 MOV #BACKGROUND,2(X) \
44261 \ ------------------------------\
44263 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
44265 \ ------------------------------\
44267 \ ------------------------------\
44268 $03E8 20_US \ 1- wait 20 ms
44269 $03 TOP_LCD \ 2- send DB5=DB4=1
44270 $CD 20_US \ 3- wait 4,1 ms
44271 $03 TOP_LCD \ 4- send again DB5=DB4=1
44272 $5 20_US \ 5- wait 0,1 ms
44273 $03 TOP_LCD \ 6- send again again DB5=DB4=1
44274 $2 20_US \ wait 40 us = LCD cycle
44275 $02 TOP_LCD \ 7- send DB5=1 DB4=0
44276 $2 20_US \ wait 40 us = LCD cycle
44277 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
44278 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
44279 LCD_Clear \ 10- "LCD_Clear"
44280 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
44281 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
44282 LCD_Clear \ 10- "LCD_Clear"
44283 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
44284 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
44286 ['] CR >BODY IS CR \
44287 ['] EMIT >BODY IS EMIT \
44288 ." RC5toLCD is running. Type STOP to quit"
44289 LIT RECURSE IS WARM \ replace WARM by this START routine
44290 ABORT \ and continue with the next word after WARM...
44291 ; \ ...until interpreter falls in sleep mode within ACCEPT.
44294 CODE STOP \ stops multitasking, must to be used before downloading app
44295 \ restore default action of primary DEFERred word SLEEP, assembly version
44296 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
44297 ADD #4,X \ X = BODY of SLEEP
44298 MOV X,-2(X) \ restore the default background
44301 \ restore default action of primary DEFERred word WARM, FORTH version
44302 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
44304 COLD \ because we want to reset CPU and interrupt vectors
44309 ; downloading RC5toLCD.4th is done
44310 RST_HERE ; this app is protected against <reset>
44318 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
44320 [DEFINED] ASM [IF] \ security test
44324 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
44326 CODE MAX \ n1 n2 -- n3 signed maximum
44327 CMP @PSP,TOS \ n2-n1
44328 S< ?GOTO FW1 \ n2<n1
44334 CODE MIN \ n1 n2 -- n3 signed minimum
44335 CMP @PSP,TOS \ n2-n1
44336 S< ?GOTO BW1 \ n2<n1
44344 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
44345 : U.R \ u n -- display u unsigned in n width (n >= 2)
44347 R> OVER - 0 MAX SPACES TYPE
44352 \ CODE 20_US \ n -- n * 20 us
44353 \ BEGIN \ 3 cycles loop + 6~
44354 \ \ MOV #5,W \ 3 MCLK = 1 MHz
44355 \ \ MOV #23,W \ 3 MCLK = 4 MHz
44356 \ \ MOV #51,W \ 3 MCLK = 8 MHz
44357 \ MOV #104,W \ 3 MCLK = 16 MHz
44358 \ \ MOV #158,W \ 3 MCLK = 24 MHz
44359 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
44364 \ MOV @PSP+,TOS \ 2
44369 CODE 20_US \ n -- n * 20 us
44370 BEGIN \ here we presume that LCD_TIM_IFG = 1...
44372 BIT #1,&LCD_TIM_CTL \ 3
44373 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
44374 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
44376 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
44382 CODE TOP_LCD \ LCD Sample
44383 \ \ if write : %xxxxWWWW --
44384 \ \ if read : -- %0000RRRR
44385 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
44386 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
44387 0= IF \ write LCD bits pattern
44388 AND.B #LCD_DB,TOS \
44389 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
44390 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
44393 THEN \ read LCD bits pattern
44396 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
44397 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
44398 AND.B #LCD_DB,TOS \
44403 CODE LCD_W \ byte -- write byte to LCD
44405 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
44406 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
44407 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
44408 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
44409 COLON \ high level word starts here
44410 TOP_LCD 2 20_US \ write high nibble first
44415 CODE LCD_WrC \ char -- Write Char
44416 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
44421 CODE LCD_WrF \ func -- Write Fonction
44422 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
44428 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
44433 $02 LCD_WrF 100 20_us
44437 [UNDEFINED] OR [IF]
44439 \ https://forth-standard.org/standard/core/OR
44440 \ C OR x1 x2 -- x3 logical OR
44449 : LCD_Entry_set $04 OR LCD_WrF ;
44451 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
44453 : LCD_DSP_Shift $10 OR LCD_WrF ;
44455 : LCD_Fn_Set $20 OR LCD_WrF ;
44457 : LCD_CGRAM_Set $40 OR LCD_WrF ;
44459 : LCD_Goto $80 OR LCD_WrF ;
44461 CODE LCD_R \ -- byte read byte from LCD
44462 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
44463 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
44464 COLON \ starts a FORTH word
44465 TOP_LCD 2 20_us \ -- %0000HHHH
44466 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
44467 HI2LO \ switch from FORTH to assembler
44468 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
44469 ADD.B @PSP+,TOS \ -- %HHHHLLLL
44470 MOV @RSP+,IP \ restore IP saved by COLON
44475 CODE LCD_RdS \ -- status Read Status
44476 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
44481 CODE LCD_RdC \ -- char Read Char
44482 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
44488 \ ******************************\
44489 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
44490 \ ******************************\
44491 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
44492 BIT.B #SW2,&SW2_IN \ test switch S2
44493 0= IF \ case of switch S2 pressed
44494 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
44496 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
44499 BIT.B #SW1,&SW1_IN \ test switch S1 input
44500 0= IF \ case of Switch S1 pressed
44501 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
44503 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
44507 BW1 \ from quit on truncated RC5 message
44508 BW2 \ from repeated RC5 command
44509 BW3 \ from end of RC5_INT
44510 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
44515 \ ******************************\
44516 ASM RC5_INT \ wake up on Px.RC5 change interrupt
44517 \ ******************************\
44518 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
44519 \ ******************************\
44520 \ \ in : SR(9)=old Toggle bit memory (ADD on)
44521 \ \ SMclock = 8|16|24 MHz
44522 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
44523 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
44524 \ \ SR(9)=new Toggle bit memory (ADD on)
44525 \ ******************************\
44526 \ RC5_FirstStartBitHalfCycle: \
44527 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
44528 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
44529 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
44530 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
44531 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
44532 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
44533 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
44534 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
44535 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
44536 MOV #1778,X \ RC5_Period * 1us
44537 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
44538 MOV #14,W \ count of loop
44540 \ ******************************\
44541 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
44542 \ ******************************\ |
44543 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
44544 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
44545 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
44546 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
44547 \ RC5_Compute_3/4_Period: \ |
44548 RRUM #1,X \ X=1/2 cycle |
44551 ADD X,Y \ Y=3/4 cycle
44552 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
44554 \ ******************************\
44555 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
44556 \ ******************************\
44557 BIT.B #RC5,&IR_IN \ C_flag = IR bit
44558 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
44559 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
44560 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
44561 SUB #1,W \ decrement count loop
44562 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
44563 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
44564 0<> WHILE \ ----> out of loop ----+
44565 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
44567 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
44568 CMP Y,X \ 1 | cycle time out of bound ?
44569 U>= IF \ 2 ^ | yes:
44570 BIC #$30,&RC5_TIM_CTL \ | | stop timer
44571 GOTO BW1 \ | | quit on truncated RC5 message
44573 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
44575 REPEAT \ ----> loop back --+ | with X = new RC5_period value
44576 \ ******************************\ |
44577 \ RC5_SampleEndOf: \ <---------------------+
44578 \ ******************************\
44579 BIC #$30,&RC5_TIM_CTL \ stop timer
44580 \ ******************************\
44581 \ RC5_ComputeNewRC5word \
44582 \ ******************************\
44583 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
44584 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
44585 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
44586 \ ******************************\
44587 \ RC5_ComputeC6bit \
44588 \ ******************************\
44589 BIT #BIT14,T \ test /C6 bit in T
44590 0= IF BIS #BIT6,X \ set C6 bit in X
44591 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
44592 \ ******************************\
44593 \ RC5_CommandByteIsDone \ -- BASE RC5_code
44594 \ ******************************\
44595 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
44596 \ ******************************\
44597 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
44598 XOR @RSP,T \ (new XOR old) Toggle bits
44599 BIT #UF10,T \ repeated RC5_command ?
44600 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
44601 XOR #UF10,0(RSP) \ 5 toggle bit memory
44602 \ ******************************\
44603 \ Display IR_RC5 code \ X = RC5 code
44604 \ ******************************\
44606 MOV &BASE,2(PSP) \ save current base
44607 MOV #$10,&BASE \ set hex base
44608 MOV TOS,0(PSP) \ save TOS
44610 LO2HI \ switch from assembler to FORTH
44611 ['] LCD_CLEAR IS CR \ redirects CR
44612 ['] LCD_WrC IS EMIT \ redirects EMIT
44613 CR ." $" 2 U.R \ print IR_RC5 code
44614 ['] CR >BODY IS CR \ restore CR
44615 ['] EMIT >BODY IS EMIT \ restore EMIT
44616 HI2LO \ switch from FORTH to assembler
44617 MOV TOS,&BASE \ restore current BASE
44619 \ ******************************\
44621 \ ******************************\
44625 \ ------------------------------\
44627 \ ------------------------------\
44628 \ ... \ insert here your background task
44631 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
44632 ADD #4,X \ 1 X = BODY of SLEEP
44635 \ ------------------------------\
44639 \ ------------------------------\
44640 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
44641 \ - - \CNTL Counter lentgh \ 00 = 16 bits
44642 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
44643 \ -- \ID input divider \ 10 = /4
44644 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
44645 \ - \TBCLR TimerB Clear
44648 \ -------------------------------\
44649 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
44650 \ -- \CM Capture Mode
44655 \ --- \OUTMOD \ 011 = set/reset
44661 \ -------------------------------\
44663 \ -------------------------------\
44665 \ ------------------------------\
44666 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
44667 \ ------------------------------\
44668 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
44669 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
44670 \ ------------------------------\
44671 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
44672 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
44673 \ ------------------------------\
44674 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
44675 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
44676 \ ------------------------------\
44677 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
44678 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
44679 \ ------------------------------\
44680 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
44681 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
44682 \ ------------------------------\
44683 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
44684 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
44685 \ ------------------------------\
44686 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
44687 \ ------------------------------\
44688 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
44689 \ ------------------------------\
44690 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
44691 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
44692 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
44693 \ ------------------------------\
44694 BIS.B #LCDVo,&LCDVo_DIR \
44695 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
44696 \ ------------------------------\
44697 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
44698 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
44699 \ ------------------------------\
44700 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
44701 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
44702 \ ******************************\
44704 \ ******************************\
44705 BIS.B #RC5,&IR_IE \ enable RC5_Int
44706 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
44707 MOV #RC5_INT,&IR_Vec \ init interrupt vector
44708 \ ******************************\
44709 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
44710 \ ******************************\
44711 \ %01 0001 0100 \ TAxCTL
44712 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
44713 \ -- \ ID divided by 1
44714 \ -- \ MC MODE = up to TAxCCRn
44715 \ - \ TACLR clear timer count
44718 \ ------------------------------\
44719 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
44720 \ ------------------------------\
44722 \ --- \ TAIDEX pre divisor
44723 \ ------------------------------\
44724 \ %0000 0000 0000 0101 \ TAxCCR0
44725 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
44726 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
44727 \ ------------------------------\
44728 \ %0000 0000 0001 0000 \ TAxCCTL0
44729 \ - \ CAP capture/compare mode = compare
44732 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
44733 \ ------------------------------\
44734 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
44735 \ ------------------------------\
44736 \ define LPM mode for ACCEPT \
44737 \ ------------------------------\
44738 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
44739 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
44740 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
44742 \ ------------------------------\
44743 \ redirects to background task \
44744 \ ------------------------------\
44746 MOV #BACKGROUND,2(X) \
44747 \ ------------------------------\
44749 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
44751 \ ------------------------------\
44753 \ ------------------------------\
44754 $03E8 20_US \ 1- wait 20 ms
44755 $03 TOP_LCD \ 2- send DB5=DB4=1
44756 $CD 20_US \ 3- wait 4,1 ms
44757 $03 TOP_LCD \ 4- send again DB5=DB4=1
44758 $5 20_US \ 5- wait 0,1 ms
44759 $03 TOP_LCD \ 6- send again again DB5=DB4=1
44760 $2 20_US \ wait 40 us = LCD cycle
44761 $02 TOP_LCD \ 7- send DB5=1 DB4=0
44762 $2 20_US \ wait 40 us = LCD cycle
44763 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
44764 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
44765 LCD_Clear \ 10- "LCD_Clear"
44766 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
44767 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
44768 LCD_Clear \ 10- "LCD_Clear"
44769 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
44770 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
44772 ['] CR >BODY IS CR \
44773 ['] EMIT >BODY IS EMIT \
44774 ." RC5toLCD is running. Type STOP to quit"
44775 LIT RECURSE IS WARM \ replace WARM by this START routine
44776 ABORT \ and continue with the next word after WARM...
44777 ; \ ...until interpreter falls in sleep mode within ACCEPT.
44780 CODE STOP \ stops multitasking, must to be used before downloading app
44781 \ restore default action of primary DEFERred word SLEEP, assembly version
44782 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
44783 ADD #4,X \ X = BODY of SLEEP
44784 MOV X,-2(X) \ restore the default background
44787 \ restore default action of primary DEFERred word WARM, FORTH version
44788 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
44790 COLD \ because we want to reset CPU and interrupt vectors
44795 ; downloading RC5toLCD.4th is done
44796 RST_HERE ; this app is protected against <reset>
44804 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
44806 [DEFINED] ASM [IF] \ security test
44810 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
44812 CODE MAX \ n1 n2 -- n3 signed maximum
44813 CMP @PSP,TOS \ n2-n1
44814 S< ?GOTO FW1 \ n2<n1
44820 CODE MIN \ n1 n2 -- n3 signed minimum
44821 CMP @PSP,TOS \ n2-n1
44822 S< ?GOTO BW1 \ n2<n1
44830 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
44831 : U.R \ u n -- display u unsigned in n width (n >= 2)
44833 R> OVER - 0 MAX SPACES TYPE
44838 \ CODE 20_US \ n -- n * 20 us
44839 \ BEGIN \ 3 cycles loop + 6~
44840 \ \ MOV #5,W \ 3 MCLK = 1 MHz
44841 \ \ MOV #23,W \ 3 MCLK = 4 MHz
44842 \ \ MOV #51,W \ 3 MCLK = 8 MHz
44843 \ MOV #104,W \ 3 MCLK = 16 MHz
44844 \ \ MOV #158,W \ 3 MCLK = 24 MHz
44845 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
44850 \ MOV @PSP+,TOS \ 2
44855 CODE 20_US \ n -- n * 20 us
44856 BEGIN \ here we presume that LCD_TIM_IFG = 1...
44858 BIT #1,&LCD_TIM_CTL \ 3
44859 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
44860 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
44862 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
44868 CODE TOP_LCD \ LCD Sample
44869 \ \ if write : %xxxxWWWW --
44870 \ \ if read : -- %0000RRRR
44871 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
44872 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
44873 0= IF \ write LCD bits pattern
44874 AND.B #LCD_DB,TOS \
44875 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
44876 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
44879 THEN \ read LCD bits pattern
44882 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
44883 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
44884 AND.B #LCD_DB,TOS \
44889 CODE LCD_W \ byte -- write byte to LCD
44891 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
44892 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
44893 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
44894 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
44895 COLON \ high level word starts here
44896 TOP_LCD 2 20_US \ write high nibble first
44901 CODE LCD_WrC \ char -- Write Char
44902 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
44907 CODE LCD_WrF \ func -- Write Fonction
44908 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
44914 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
44919 $02 LCD_WrF 100 20_us
44923 [UNDEFINED] OR [IF]
44925 \ https://forth-standard.org/standard/core/OR
44926 \ C OR x1 x2 -- x3 logical OR
44935 : LCD_Entry_set $04 OR LCD_WrF ;
44937 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
44939 : LCD_DSP_Shift $10 OR LCD_WrF ;
44941 : LCD_Fn_Set $20 OR LCD_WrF ;
44943 : LCD_CGRAM_Set $40 OR LCD_WrF ;
44945 : LCD_Goto $80 OR LCD_WrF ;
44947 CODE LCD_R \ -- byte read byte from LCD
44948 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
44949 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
44950 COLON \ starts a FORTH word
44951 TOP_LCD 2 20_us \ -- %0000HHHH
44952 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
44953 HI2LO \ switch from FORTH to assembler
44954 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
44955 ADD.B @PSP+,TOS \ -- %HHHHLLLL
44956 MOV @RSP+,IP \ restore IP saved by COLON
44961 CODE LCD_RdS \ -- status Read Status
44962 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
44967 CODE LCD_RdC \ -- char Read Char
44968 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
44974 \ ******************************\
44975 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
44976 \ ******************************\
44977 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
44978 BIT.B #SW2,&SW2_IN \ test switch S2
44979 0= IF \ case of switch S2 pressed
44980 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
44982 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
44985 BIT.B #SW1,&SW1_IN \ test switch S1 input
44986 0= IF \ case of Switch S1 pressed
44987 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
44989 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
44993 BW1 \ from quit on truncated RC5 message
44994 BW2 \ from repeated RC5 command
44995 BW3 \ from end of RC5_INT
44996 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
45001 \ ******************************\
45002 ASM RC5_INT \ wake up on Px.RC5 change interrupt
45003 \ ******************************\
45004 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
45005 \ ******************************\
45006 \ \ in : SR(9)=old Toggle bit memory (ADD on)
45007 \ \ SMclock = 8|16|24 MHz
45008 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
45009 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
45010 \ \ SR(9)=new Toggle bit memory (ADD on)
45011 \ ******************************\
45012 \ RC5_FirstStartBitHalfCycle: \
45013 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
45014 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
45015 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
45016 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
45017 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
45018 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
45019 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
45020 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
45021 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
45022 MOV #1778,X \ RC5_Period * 1us
45023 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
45024 MOV #14,W \ count of loop
45026 \ ******************************\
45027 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
45028 \ ******************************\ |
45029 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
45030 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
45031 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
45032 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
45033 \ RC5_Compute_3/4_Period: \ |
45034 RRUM #1,X \ X=1/2 cycle |
45037 ADD X,Y \ Y=3/4 cycle
45038 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
45040 \ ******************************\
45041 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
45042 \ ******************************\
45043 BIT.B #RC5,&IR_IN \ C_flag = IR bit
45044 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
45045 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
45046 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
45047 SUB #1,W \ decrement count loop
45048 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
45049 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
45050 0<> WHILE \ ----> out of loop ----+
45051 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
45053 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
45054 CMP Y,X \ 1 | cycle time out of bound ?
45055 U>= IF \ 2 ^ | yes:
45056 BIC #$30,&RC5_TIM_CTL \ | | stop timer
45057 GOTO BW1 \ | | quit on truncated RC5 message
45059 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
45061 REPEAT \ ----> loop back --+ | with X = new RC5_period value
45062 \ ******************************\ |
45063 \ RC5_SampleEndOf: \ <---------------------+
45064 \ ******************************\
45065 BIC #$30,&RC5_TIM_CTL \ stop timer
45066 \ ******************************\
45067 \ RC5_ComputeNewRC5word \
45068 \ ******************************\
45069 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
45070 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
45071 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
45072 \ ******************************\
45073 \ RC5_ComputeC6bit \
45074 \ ******************************\
45075 BIT #BIT14,T \ test /C6 bit in T
45076 0= IF BIS #BIT6,X \ set C6 bit in X
45077 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
45078 \ ******************************\
45079 \ RC5_CommandByteIsDone \ -- BASE RC5_code
45080 \ ******************************\
45081 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
45082 \ ******************************\
45083 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
45084 XOR @RSP,T \ (new XOR old) Toggle bits
45085 BIT #UF10,T \ repeated RC5_command ?
45086 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
45087 XOR #UF10,0(RSP) \ 5 toggle bit memory
45088 \ ******************************\
45089 \ Display IR_RC5 code \ X = RC5 code
45090 \ ******************************\
45092 MOV &BASE,2(PSP) \ save current base
45093 MOV #$10,&BASE \ set hex base
45094 MOV TOS,0(PSP) \ save TOS
45096 LO2HI \ switch from assembler to FORTH
45097 ['] LCD_CLEAR IS CR \ redirects CR
45098 ['] LCD_WrC IS EMIT \ redirects EMIT
45099 CR ." $" 2 U.R \ print IR_RC5 code
45100 ['] CR >BODY IS CR \ restore CR
45101 ['] EMIT >BODY IS EMIT \ restore EMIT
45102 HI2LO \ switch from FORTH to assembler
45103 MOV TOS,&BASE \ restore current BASE
45105 \ ******************************\
45107 \ ******************************\
45111 \ ------------------------------\
45113 \ ------------------------------\
45114 \ ... \ insert here your background task
45117 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
45118 ADD #4,X \ 1 X = BODY of SLEEP
45121 \ ------------------------------\
45125 \ ------------------------------\
45126 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
45127 \ - - \CNTL Counter lentgh \ 00 = 16 bits
45128 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
45129 \ -- \ID input divider \ 10 = /4
45130 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
45131 \ - \TBCLR TimerB Clear
45134 \ -------------------------------\
45135 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
45136 \ -- \CM Capture Mode
45141 \ --- \OUTMOD \ 011 = set/reset
45147 \ -------------------------------\
45149 \ -------------------------------\
45151 \ ------------------------------\
45152 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
45153 \ ------------------------------\
45154 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
45155 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
45156 \ ------------------------------\
45157 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
45158 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
45159 \ ------------------------------\
45160 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
45161 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
45162 \ ------------------------------\
45163 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
45164 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
45165 \ ------------------------------\
45166 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
45167 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
45168 \ ------------------------------\
45169 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
45170 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
45171 \ ------------------------------\
45172 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
45173 \ ------------------------------\
45174 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
45175 \ ------------------------------\
45176 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
45177 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
45178 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
45179 \ ------------------------------\
45180 BIS.B #LCDVo,&LCDVo_DIR \
45181 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
45182 \ ------------------------------\
45183 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
45184 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
45185 \ ------------------------------\
45186 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
45187 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
45188 \ ******************************\
45190 \ ******************************\
45191 BIS.B #RC5,&IR_IE \ enable RC5_Int
45192 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
45193 MOV #RC5_INT,&IR_Vec \ init interrupt vector
45194 \ ******************************\
45195 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
45196 \ ******************************\
45197 \ %01 0001 0100 \ TAxCTL
45198 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
45199 \ -- \ ID divided by 1
45200 \ -- \ MC MODE = up to TAxCCRn
45201 \ - \ TACLR clear timer count
45204 \ ------------------------------\
45205 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
45206 \ ------------------------------\
45208 \ --- \ TAIDEX pre divisor
45209 \ ------------------------------\
45210 \ %0000 0000 0000 0101 \ TAxCCR0
45211 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
45212 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
45213 \ ------------------------------\
45214 \ %0000 0000 0001 0000 \ TAxCCTL0
45215 \ - \ CAP capture/compare mode = compare
45218 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
45219 \ ------------------------------\
45220 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
45221 \ ------------------------------\
45222 \ define LPM mode for ACCEPT \
45223 \ ------------------------------\
45224 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
45225 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
45226 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
45228 \ ------------------------------\
45229 \ redirects to background task \
45230 \ ------------------------------\
45232 MOV #BACKGROUND,2(X) \
45233 \ ------------------------------\
45235 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
45237 \ ------------------------------\
45239 \ ------------------------------\
45240 $03E8 20_US \ 1- wait 20 ms
45241 $03 TOP_LCD \ 2- send DB5=DB4=1
45242 $CD 20_US \ 3- wait 4,1 ms
45243 $03 TOP_LCD \ 4- send again DB5=DB4=1
45244 $5 20_US \ 5- wait 0,1 ms
45245 $03 TOP_LCD \ 6- send again again DB5=DB4=1
45246 $2 20_US \ wait 40 us = LCD cycle
45247 $02 TOP_LCD \ 7- send DB5=1 DB4=0
45248 $2 20_US \ wait 40 us = LCD cycle
45249 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
45250 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
45251 LCD_Clear \ 10- "LCD_Clear"
45252 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
45253 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
45254 LCD_Clear \ 10- "LCD_Clear"
45255 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
45256 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
45258 ['] CR >BODY IS CR \
45259 ['] EMIT >BODY IS EMIT \
45260 ." RC5toLCD is running. Type STOP to quit"
45261 LIT RECURSE IS WARM \ replace WARM by this START routine
45262 ABORT \ and continue with the next word after WARM...
45263 ; \ ...until interpreter falls in sleep mode within ACCEPT.
45266 CODE STOP \ stops multitasking, must to be used before downloading app
45267 \ restore default action of primary DEFERred word SLEEP, assembly version
45268 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
45269 ADD #4,X \ X = BODY of SLEEP
45270 MOV X,-2(X) \ restore the default background
45273 \ restore default action of primary DEFERred word WARM, FORTH version
45274 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
45276 COLD \ because we want to reset CPU and interrupt vectors
45281 ; downloading RC5toLCD.4th is done
45282 RST_HERE ; this app is protected against <reset>
45290 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
45292 [DEFINED] ASM [IF] \ security test
45296 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
45298 CODE MAX \ n1 n2 -- n3 signed maximum
45299 CMP @PSP,TOS \ n2-n1
45300 S< ?GOTO FW1 \ n2<n1
45306 CODE MIN \ n1 n2 -- n3 signed minimum
45307 CMP @PSP,TOS \ n2-n1
45308 S< ?GOTO BW1 \ n2<n1
45316 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
45317 : U.R \ u n -- display u unsigned in n width (n >= 2)
45319 R> OVER - 0 MAX SPACES TYPE
45324 \ CODE 20_US \ n -- n * 20 us
45325 \ BEGIN \ 3 cycles loop + 6~
45326 \ \ MOV #5,W \ 3 MCLK = 1 MHz
45327 \ \ MOV #23,W \ 3 MCLK = 4 MHz
45328 \ \ MOV #51,W \ 3 MCLK = 8 MHz
45329 \ MOV #104,W \ 3 MCLK = 16 MHz
45330 \ \ MOV #158,W \ 3 MCLK = 24 MHz
45331 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
45336 \ MOV @PSP+,TOS \ 2
45341 CODE 20_US \ n -- n * 20 us
45342 BEGIN \ here we presume that LCD_TIM_IFG = 1...
45344 BIT #1,&LCD_TIM_CTL \ 3
45345 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
45346 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
45348 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
45354 CODE TOP_LCD \ LCD Sample
45355 \ \ if write : %xxxxWWWW --
45356 \ \ if read : -- %0000RRRR
45357 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
45358 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
45359 0= IF \ write LCD bits pattern
45360 AND.B #LCD_DB,TOS \
45361 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
45362 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
45365 THEN \ read LCD bits pattern
45368 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
45369 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
45370 AND.B #LCD_DB,TOS \
45375 CODE LCD_W \ byte -- write byte to LCD
45377 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
45378 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
45379 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
45380 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
45381 COLON \ high level word starts here
45382 TOP_LCD 2 20_US \ write high nibble first
45387 CODE LCD_WrC \ char -- Write Char
45388 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
45393 CODE LCD_WrF \ func -- Write Fonction
45394 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
45400 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
45405 $02 LCD_WrF 100 20_us
45409 [UNDEFINED] OR [IF]
45411 \ https://forth-standard.org/standard/core/OR
45412 \ C OR x1 x2 -- x3 logical OR
45421 : LCD_Entry_set $04 OR LCD_WrF ;
45423 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
45425 : LCD_DSP_Shift $10 OR LCD_WrF ;
45427 : LCD_Fn_Set $20 OR LCD_WrF ;
45429 : LCD_CGRAM_Set $40 OR LCD_WrF ;
45431 : LCD_Goto $80 OR LCD_WrF ;
45433 CODE LCD_R \ -- byte read byte from LCD
45434 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
45435 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
45436 COLON \ starts a FORTH word
45437 TOP_LCD 2 20_us \ -- %0000HHHH
45438 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
45439 HI2LO \ switch from FORTH to assembler
45440 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
45441 ADD.B @PSP+,TOS \ -- %HHHHLLLL
45442 MOV @RSP+,IP \ restore IP saved by COLON
45447 CODE LCD_RdS \ -- status Read Status
45448 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
45453 CODE LCD_RdC \ -- char Read Char
45454 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
45460 \ ******************************\
45461 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
45462 \ ******************************\
45463 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
45464 BIT.B #SW2,&SW2_IN \ test switch S2
45465 0= IF \ case of switch S2 pressed
45466 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
45468 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
45471 BIT.B #SW1,&SW1_IN \ test switch S1 input
45472 0= IF \ case of Switch S1 pressed
45473 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
45475 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
45479 BW1 \ from quit on truncated RC5 message
45480 BW2 \ from repeated RC5 command
45481 BW3 \ from end of RC5_INT
45482 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
45487 \ ******************************\
45488 ASM RC5_INT \ wake up on Px.RC5 change interrupt
45489 \ ******************************\
45490 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
45491 \ ******************************\
45492 \ \ in : SR(9)=old Toggle bit memory (ADD on)
45493 \ \ SMclock = 8|16|24 MHz
45494 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
45495 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
45496 \ \ SR(9)=new Toggle bit memory (ADD on)
45497 \ ******************************\
45498 \ RC5_FirstStartBitHalfCycle: \
45499 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
45500 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
45501 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
45502 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
45503 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
45504 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
45505 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
45506 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
45507 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
45508 MOV #1778,X \ RC5_Period * 1us
45509 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
45510 MOV #14,W \ count of loop
45512 \ ******************************\
45513 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
45514 \ ******************************\ |
45515 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
45516 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
45517 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
45518 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
45519 \ RC5_Compute_3/4_Period: \ |
45520 RRUM #1,X \ X=1/2 cycle |
45523 ADD X,Y \ Y=3/4 cycle
45524 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
45526 \ ******************************\
45527 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
45528 \ ******************************\
45529 BIT.B #RC5,&IR_IN \ C_flag = IR bit
45530 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
45531 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
45532 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
45533 SUB #1,W \ decrement count loop
45534 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
45535 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
45536 0<> WHILE \ ----> out of loop ----+
45537 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
45539 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
45540 CMP Y,X \ 1 | cycle time out of bound ?
45541 U>= IF \ 2 ^ | yes:
45542 BIC #$30,&RC5_TIM_CTL \ | | stop timer
45543 GOTO BW1 \ | | quit on truncated RC5 message
45545 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
45547 REPEAT \ ----> loop back --+ | with X = new RC5_period value
45548 \ ******************************\ |
45549 \ RC5_SampleEndOf: \ <---------------------+
45550 \ ******************************\
45551 BIC #$30,&RC5_TIM_CTL \ stop timer
45552 \ ******************************\
45553 \ RC5_ComputeNewRC5word \
45554 \ ******************************\
45555 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
45556 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
45557 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
45558 \ ******************************\
45559 \ RC5_ComputeC6bit \
45560 \ ******************************\
45561 BIT #BIT14,T \ test /C6 bit in T
45562 0= IF BIS #BIT6,X \ set C6 bit in X
45563 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
45564 \ ******************************\
45565 \ RC5_CommandByteIsDone \ -- BASE RC5_code
45566 \ ******************************\
45567 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
45568 \ ******************************\
45569 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
45570 XOR @RSP,T \ (new XOR old) Toggle bits
45571 BIT #UF10,T \ repeated RC5_command ?
45572 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
45573 XOR #UF10,0(RSP) \ 5 toggle bit memory
45574 \ ******************************\
45575 \ Display IR_RC5 code \ X = RC5 code
45576 \ ******************************\
45578 MOV &BASE,2(PSP) \ save current base
45579 MOV #$10,&BASE \ set hex base
45580 MOV TOS,0(PSP) \ save TOS
45582 LO2HI \ switch from assembler to FORTH
45583 ['] LCD_CLEAR IS CR \ redirects CR
45584 ['] LCD_WrC IS EMIT \ redirects EMIT
45585 CR ." $" 2 U.R \ print IR_RC5 code
45586 ['] CR >BODY IS CR \ restore CR
45587 ['] EMIT >BODY IS EMIT \ restore EMIT
45588 HI2LO \ switch from FORTH to assembler
45589 MOV TOS,&BASE \ restore current BASE
45591 \ ******************************\
45593 \ ******************************\
45597 \ ------------------------------\
45599 \ ------------------------------\
45600 \ ... \ insert here your background task
45603 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
45604 ADD #4,X \ 1 X = BODY of SLEEP
45607 \ ------------------------------\
45611 \ ------------------------------\
45612 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
45613 \ - - \CNTL Counter lentgh \ 00 = 16 bits
45614 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
45615 \ -- \ID input divider \ 10 = /4
45616 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
45617 \ - \TBCLR TimerB Clear
45620 \ -------------------------------\
45621 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
45622 \ -- \CM Capture Mode
45627 \ --- \OUTMOD \ 011 = set/reset
45633 \ -------------------------------\
45635 \ -------------------------------\
45637 \ ------------------------------\
45638 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
45639 \ ------------------------------\
45640 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
45641 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
45642 \ ------------------------------\
45643 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
45644 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
45645 \ ------------------------------\
45646 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
45647 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
45648 \ ------------------------------\
45649 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
45650 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
45651 \ ------------------------------\
45652 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
45653 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
45654 \ ------------------------------\
45655 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
45656 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
45657 \ ------------------------------\
45658 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
45659 \ ------------------------------\
45660 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
45661 \ ------------------------------\
45662 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
45663 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
45664 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
45665 \ ------------------------------\
45666 BIS.B #LCDVo,&LCDVo_DIR \
45667 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
45668 \ ------------------------------\
45669 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
45670 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
45671 \ ------------------------------\
45672 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
45673 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
45674 \ ******************************\
45676 \ ******************************\
45677 BIS.B #RC5,&IR_IE \ enable RC5_Int
45678 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
45679 MOV #RC5_INT,&IR_Vec \ init interrupt vector
45680 \ ******************************\
45681 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
45682 \ ******************************\
45683 \ %01 0001 0100 \ TAxCTL
45684 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
45685 \ -- \ ID divided by 1
45686 \ -- \ MC MODE = up to TAxCCRn
45687 \ - \ TACLR clear timer count
45690 \ ------------------------------\
45691 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
45692 \ ------------------------------\
45694 \ --- \ TAIDEX pre divisor
45695 \ ------------------------------\
45696 \ %0000 0000 0000 0101 \ TAxCCR0
45697 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
45698 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
45699 \ ------------------------------\
45700 \ %0000 0000 0001 0000 \ TAxCCTL0
45701 \ - \ CAP capture/compare mode = compare
45704 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
45705 \ ------------------------------\
45706 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
45707 \ ------------------------------\
45708 \ define LPM mode for ACCEPT \
45709 \ ------------------------------\
45710 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
45711 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
45712 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
45714 \ ------------------------------\
45715 \ redirects to background task \
45716 \ ------------------------------\
45718 MOV #BACKGROUND,2(X) \
45719 \ ------------------------------\
45721 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
45723 \ ------------------------------\
45725 \ ------------------------------\
45726 $03E8 20_US \ 1- wait 20 ms
45727 $03 TOP_LCD \ 2- send DB5=DB4=1
45728 $CD 20_US \ 3- wait 4,1 ms
45729 $03 TOP_LCD \ 4- send again DB5=DB4=1
45730 $5 20_US \ 5- wait 0,1 ms
45731 $03 TOP_LCD \ 6- send again again DB5=DB4=1
45732 $2 20_US \ wait 40 us = LCD cycle
45733 $02 TOP_LCD \ 7- send DB5=1 DB4=0
45734 $2 20_US \ wait 40 us = LCD cycle
45735 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
45736 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
45737 LCD_Clear \ 10- "LCD_Clear"
45738 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
45739 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
45740 LCD_Clear \ 10- "LCD_Clear"
45741 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
45742 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
45744 ['] CR >BODY IS CR \
45745 ['] EMIT >BODY IS EMIT \
45746 ." RC5toLCD is running. Type STOP to quit"
45747 LIT RECURSE IS WARM \ replace WARM by this START routine
45748 ABORT \ and continue with the next word after WARM...
45749 ; \ ...until interpreter falls in sleep mode within ACCEPT.
45752 CODE STOP \ stops multitasking, must to be used before downloading app
45753 \ restore default action of primary DEFERred word SLEEP, assembly version
45754 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
45755 ADD #4,X \ X = BODY of SLEEP
45756 MOV X,-2(X) \ restore the default background
45759 \ restore default action of primary DEFERred word WARM, FORTH version
45760 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
45762 COLD \ because we want to reset CPU and interrupt vectors
45767 ; downloading RC5toLCD.4th is done
45768 RST_HERE ; this app is protected against <reset>
45776 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
45778 [DEFINED] ASM [IF] \ security test
45782 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
45784 CODE MAX \ n1 n2 -- n3 signed maximum
45785 CMP @PSP,TOS \ n2-n1
45786 S< ?GOTO FW1 \ n2<n1
45792 CODE MIN \ n1 n2 -- n3 signed minimum
45793 CMP @PSP,TOS \ n2-n1
45794 S< ?GOTO BW1 \ n2<n1
45802 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
45803 : U.R \ u n -- display u unsigned in n width (n >= 2)
45805 R> OVER - 0 MAX SPACES TYPE
45810 \ CODE 20_US \ n -- n * 20 us
45811 \ BEGIN \ 3 cycles loop + 6~
45812 \ \ MOV #5,W \ 3 MCLK = 1 MHz
45813 \ \ MOV #23,W \ 3 MCLK = 4 MHz
45814 \ \ MOV #51,W \ 3 MCLK = 8 MHz
45815 \ MOV #104,W \ 3 MCLK = 16 MHz
45816 \ \ MOV #158,W \ 3 MCLK = 24 MHz
45817 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
45822 \ MOV @PSP+,TOS \ 2
45827 CODE 20_US \ n -- n * 20 us
45828 BEGIN \ here we presume that LCD_TIM_IFG = 1...
45830 BIT #1,&LCD_TIM_CTL \ 3
45831 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
45832 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
45834 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
45840 CODE TOP_LCD \ LCD Sample
45841 \ \ if write : %xxxxWWWW --
45842 \ \ if read : -- %0000RRRR
45843 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
45844 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
45845 0= IF \ write LCD bits pattern
45846 AND.B #LCD_DB,TOS \
45847 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
45848 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
45851 THEN \ read LCD bits pattern
45854 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
45855 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
45856 AND.B #LCD_DB,TOS \
45861 CODE LCD_W \ byte -- write byte to LCD
45863 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
45864 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
45865 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
45866 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
45867 COLON \ high level word starts here
45868 TOP_LCD 2 20_US \ write high nibble first
45873 CODE LCD_WrC \ char -- Write Char
45874 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
45879 CODE LCD_WrF \ func -- Write Fonction
45880 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
45886 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
45891 $02 LCD_WrF 100 20_us
45895 [UNDEFINED] OR [IF]
45897 \ https://forth-standard.org/standard/core/OR
45898 \ C OR x1 x2 -- x3 logical OR
45907 : LCD_Entry_set $04 OR LCD_WrF ;
45909 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
45911 : LCD_DSP_Shift $10 OR LCD_WrF ;
45913 : LCD_Fn_Set $20 OR LCD_WrF ;
45915 : LCD_CGRAM_Set $40 OR LCD_WrF ;
45917 : LCD_Goto $80 OR LCD_WrF ;
45919 CODE LCD_R \ -- byte read byte from LCD
45920 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
45921 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
45922 COLON \ starts a FORTH word
45923 TOP_LCD 2 20_us \ -- %0000HHHH
45924 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
45925 HI2LO \ switch from FORTH to assembler
45926 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
45927 ADD.B @PSP+,TOS \ -- %HHHHLLLL
45928 MOV @RSP+,IP \ restore IP saved by COLON
45933 CODE LCD_RdS \ -- status Read Status
45934 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
45939 CODE LCD_RdC \ -- char Read Char
45940 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
45946 \ ******************************\
45947 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
45948 \ ******************************\
45949 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
45950 BIT.B #SW2,&SW2_IN \ test switch S2
45951 0= IF \ case of switch S2 pressed
45952 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
45954 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
45957 BIT.B #SW1,&SW1_IN \ test switch S1 input
45958 0= IF \ case of Switch S1 pressed
45959 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
45961 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
45965 BW1 \ from quit on truncated RC5 message
45966 BW2 \ from repeated RC5 command
45967 BW3 \ from end of RC5_INT
45968 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
45973 \ ******************************\
45974 ASM RC5_INT \ wake up on Px.RC5 change interrupt
45975 \ ******************************\
45976 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
45977 \ ******************************\
45978 \ \ in : SR(9)=old Toggle bit memory (ADD on)
45979 \ \ SMclock = 8|16|24 MHz
45980 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
45981 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
45982 \ \ SR(9)=new Toggle bit memory (ADD on)
45983 \ ******************************\
45984 \ RC5_FirstStartBitHalfCycle: \
45985 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
45986 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
45987 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
45988 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
45989 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
45990 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
45991 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
45992 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
45993 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
45994 MOV #1778,X \ RC5_Period * 1us
45995 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
45996 MOV #14,W \ count of loop
45998 \ ******************************\
45999 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
46000 \ ******************************\ |
46001 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
46002 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
46003 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
46004 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
46005 \ RC5_Compute_3/4_Period: \ |
46006 RRUM #1,X \ X=1/2 cycle |
46009 ADD X,Y \ Y=3/4 cycle
46010 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
46012 \ ******************************\
46013 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
46014 \ ******************************\
46015 BIT.B #RC5,&IR_IN \ C_flag = IR bit
46016 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
46017 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
46018 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
46019 SUB #1,W \ decrement count loop
46020 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
46021 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
46022 0<> WHILE \ ----> out of loop ----+
46023 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
46025 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
46026 CMP Y,X \ 1 | cycle time out of bound ?
46027 U>= IF \ 2 ^ | yes:
46028 BIC #$30,&RC5_TIM_CTL \ | | stop timer
46029 GOTO BW1 \ | | quit on truncated RC5 message
46031 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
46033 REPEAT \ ----> loop back --+ | with X = new RC5_period value
46034 \ ******************************\ |
46035 \ RC5_SampleEndOf: \ <---------------------+
46036 \ ******************************\
46037 BIC #$30,&RC5_TIM_CTL \ stop timer
46038 \ ******************************\
46039 \ RC5_ComputeNewRC5word \
46040 \ ******************************\
46041 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
46042 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
46043 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
46044 \ ******************************\
46045 \ RC5_ComputeC6bit \
46046 \ ******************************\
46047 BIT #BIT14,T \ test /C6 bit in T
46048 0= IF BIS #BIT6,X \ set C6 bit in X
46049 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
46050 \ ******************************\
46051 \ RC5_CommandByteIsDone \ -- BASE RC5_code
46052 \ ******************************\
46053 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
46054 \ ******************************\
46055 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
46056 XOR @RSP,T \ (new XOR old) Toggle bits
46057 BIT #UF10,T \ repeated RC5_command ?
46058 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
46059 XOR #UF10,0(RSP) \ 5 toggle bit memory
46060 \ ******************************\
46061 \ Display IR_RC5 code \ X = RC5 code
46062 \ ******************************\
46064 MOV &BASE,2(PSP) \ save current base
46065 MOV #$10,&BASE \ set hex base
46066 MOV TOS,0(PSP) \ save TOS
46068 LO2HI \ switch from assembler to FORTH
46069 ['] LCD_CLEAR IS CR \ redirects CR
46070 ['] LCD_WrC IS EMIT \ redirects EMIT
46071 CR ." $" 2 U.R \ print IR_RC5 code
46072 ['] CR >BODY IS CR \ restore CR
46073 ['] EMIT >BODY IS EMIT \ restore EMIT
46074 HI2LO \ switch from FORTH to assembler
46075 MOV TOS,&BASE \ restore current BASE
46077 \ ******************************\
46079 \ ******************************\
46083 \ ------------------------------\
46085 \ ------------------------------\
46086 \ ... \ insert here your background task
46089 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
46090 ADD #4,X \ 1 X = BODY of SLEEP
46093 \ ------------------------------\
46097 \ ------------------------------\
46098 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
46099 \ - - \CNTL Counter lentgh \ 00 = 16 bits
46100 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
46101 \ -- \ID input divider \ 10 = /4
46102 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
46103 \ - \TBCLR TimerB Clear
46106 \ -------------------------------\
46107 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
46108 \ -- \CM Capture Mode
46113 \ --- \OUTMOD \ 011 = set/reset
46119 \ -------------------------------\
46121 \ -------------------------------\
46123 \ ------------------------------\
46124 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
46125 \ ------------------------------\
46126 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
46127 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
46128 \ ------------------------------\
46129 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
46130 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
46131 \ ------------------------------\
46132 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
46133 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
46134 \ ------------------------------\
46135 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
46136 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
46137 \ ------------------------------\
46138 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
46139 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
46140 \ ------------------------------\
46141 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
46142 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
46143 \ ------------------------------\
46144 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
46145 \ ------------------------------\
46146 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
46147 \ ------------------------------\
46148 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
46149 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
46150 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
46151 \ ------------------------------\
46152 BIS.B #LCDVo,&LCDVo_DIR \
46153 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
46154 \ ------------------------------\
46155 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
46156 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
46157 \ ------------------------------\
46158 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
46159 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
46160 \ ******************************\
46162 \ ******************************\
46163 BIS.B #RC5,&IR_IE \ enable RC5_Int
46164 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
46165 MOV #RC5_INT,&IR_Vec \ init interrupt vector
46166 \ ******************************\
46167 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
46168 \ ******************************\
46169 \ %01 0001 0100 \ TAxCTL
46170 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
46171 \ -- \ ID divided by 1
46172 \ -- \ MC MODE = up to TAxCCRn
46173 \ - \ TACLR clear timer count
46176 \ ------------------------------\
46177 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
46178 \ ------------------------------\
46180 \ --- \ TAIDEX pre divisor
46181 \ ------------------------------\
46182 \ %0000 0000 0000 0101 \ TAxCCR0
46183 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
46184 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
46185 \ ------------------------------\
46186 \ %0000 0000 0001 0000 \ TAxCCTL0
46187 \ - \ CAP capture/compare mode = compare
46190 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
46191 \ ------------------------------\
46192 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
46193 \ ------------------------------\
46194 \ define LPM mode for ACCEPT \
46195 \ ------------------------------\
46196 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
46197 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
46198 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
46200 \ ------------------------------\
46201 \ redirects to background task \
46202 \ ------------------------------\
46204 MOV #BACKGROUND,2(X) \
46205 \ ------------------------------\
46207 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
46209 \ ------------------------------\
46211 \ ------------------------------\
46212 $03E8 20_US \ 1- wait 20 ms
46213 $03 TOP_LCD \ 2- send DB5=DB4=1
46214 $CD 20_US \ 3- wait 4,1 ms
46215 $03 TOP_LCD \ 4- send again DB5=DB4=1
46216 $5 20_US \ 5- wait 0,1 ms
46217 $03 TOP_LCD \ 6- send again again DB5=DB4=1
46218 $2 20_US \ wait 40 us = LCD cycle
46219 $02 TOP_LCD \ 7- send DB5=1 DB4=0
46220 $2 20_US \ wait 40 us = LCD cycle
46221 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
46222 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
46223 LCD_Clear \ 10- "LCD_Clear"
46224 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
46225 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
46226 LCD_Clear \ 10- "LCD_Clear"
46227 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
46228 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
46230 ['] CR >BODY IS CR \
46231 ['] EMIT >BODY IS EMIT \
46232 ." RC5toLCD is running. Type STOP to quit"
46233 LIT RECURSE IS WARM \ replace WARM by this START routine
46234 ABORT \ and continue with the next word after WARM...
46235 ; \ ...until interpreter falls in sleep mode within ACCEPT.
46238 CODE STOP \ stops multitasking, must to be used before downloading app
46239 \ restore default action of primary DEFERred word SLEEP, assembly version
46240 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
46241 ADD #4,X \ X = BODY of SLEEP
46242 MOV X,-2(X) \ restore the default background
46245 \ restore default action of primary DEFERred word WARM, FORTH version
46246 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
46248 COLD \ because we want to reset CPU and interrupt vectors
46253 ; downloading RC5toLCD.4th is done
46254 RST_HERE ; this app is protected against <reset>
46262 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
46264 [DEFINED] ASM [IF] \ security test
46268 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
46270 CODE MAX \ n1 n2 -- n3 signed maximum
46271 CMP @PSP,TOS \ n2-n1
46272 S< ?GOTO FW1 \ n2<n1
46278 CODE MIN \ n1 n2 -- n3 signed minimum
46279 CMP @PSP,TOS \ n2-n1
46280 S< ?GOTO BW1 \ n2<n1
46288 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
46289 : U.R \ u n -- display u unsigned in n width (n >= 2)
46291 R> OVER - 0 MAX SPACES TYPE
46296 \ CODE 20_US \ n -- n * 20 us
46297 \ BEGIN \ 3 cycles loop + 6~
46298 \ \ MOV #5,W \ 3 MCLK = 1 MHz
46299 \ \ MOV #23,W \ 3 MCLK = 4 MHz
46300 \ \ MOV #51,W \ 3 MCLK = 8 MHz
46301 \ MOV #104,W \ 3 MCLK = 16 MHz
46302 \ \ MOV #158,W \ 3 MCLK = 24 MHz
46303 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
46308 \ MOV @PSP+,TOS \ 2
46313 CODE 20_US \ n -- n * 20 us
46314 BEGIN \ here we presume that LCD_TIM_IFG = 1...
46316 BIT #1,&LCD_TIM_CTL \ 3
46317 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
46318 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
46320 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
46326 CODE TOP_LCD \ LCD Sample
46327 \ \ if write : %xxxxWWWW --
46328 \ \ if read : -- %0000RRRR
46329 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
46330 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
46331 0= IF \ write LCD bits pattern
46332 AND.B #LCD_DB,TOS \
46333 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
46334 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
46337 THEN \ read LCD bits pattern
46340 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
46341 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
46342 AND.B #LCD_DB,TOS \
46347 CODE LCD_W \ byte -- write byte to LCD
46349 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
46350 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
46351 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
46352 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
46353 COLON \ high level word starts here
46354 TOP_LCD 2 20_US \ write high nibble first
46359 CODE LCD_WrC \ char -- Write Char
46360 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
46365 CODE LCD_WrF \ func -- Write Fonction
46366 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
46372 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
46377 $02 LCD_WrF 100 20_us
46381 [UNDEFINED] OR [IF]
46383 \ https://forth-standard.org/standard/core/OR
46384 \ C OR x1 x2 -- x3 logical OR
46393 : LCD_Entry_set $04 OR LCD_WrF ;
46395 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
46397 : LCD_DSP_Shift $10 OR LCD_WrF ;
46399 : LCD_Fn_Set $20 OR LCD_WrF ;
46401 : LCD_CGRAM_Set $40 OR LCD_WrF ;
46403 : LCD_Goto $80 OR LCD_WrF ;
46405 CODE LCD_R \ -- byte read byte from LCD
46406 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
46407 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
46408 COLON \ starts a FORTH word
46409 TOP_LCD 2 20_us \ -- %0000HHHH
46410 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
46411 HI2LO \ switch from FORTH to assembler
46412 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
46413 ADD.B @PSP+,TOS \ -- %HHHHLLLL
46414 MOV @RSP+,IP \ restore IP saved by COLON
46419 CODE LCD_RdS \ -- status Read Status
46420 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
46425 CODE LCD_RdC \ -- char Read Char
46426 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
46432 \ ******************************\
46433 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
46434 \ ******************************\
46435 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
46436 BIT.B #SW2,&SW2_IN \ test switch S2
46437 0= IF \ case of switch S2 pressed
46438 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
46440 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
46443 BIT.B #SW1,&SW1_IN \ test switch S1 input
46444 0= IF \ case of Switch S1 pressed
46445 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
46447 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
46451 BW1 \ from quit on truncated RC5 message
46452 BW2 \ from repeated RC5 command
46453 BW3 \ from end of RC5_INT
46454 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
46459 \ ******************************\
46460 ASM RC5_INT \ wake up on Px.RC5 change interrupt
46461 \ ******************************\
46462 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
46463 \ ******************************\
46464 \ \ in : SR(9)=old Toggle bit memory (ADD on)
46465 \ \ SMclock = 8|16|24 MHz
46466 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
46467 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
46468 \ \ SR(9)=new Toggle bit memory (ADD on)
46469 \ ******************************\
46470 \ RC5_FirstStartBitHalfCycle: \
46471 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
46472 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
46473 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
46474 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
46475 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
46476 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
46477 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
46478 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
46479 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
46480 MOV #1778,X \ RC5_Period * 1us
46481 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
46482 MOV #14,W \ count of loop
46484 \ ******************************\
46485 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
46486 \ ******************************\ |
46487 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
46488 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
46489 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
46490 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
46491 \ RC5_Compute_3/4_Period: \ |
46492 RRUM #1,X \ X=1/2 cycle |
46495 ADD X,Y \ Y=3/4 cycle
46496 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
46498 \ ******************************\
46499 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
46500 \ ******************************\
46501 BIT.B #RC5,&IR_IN \ C_flag = IR bit
46502 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
46503 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
46504 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
46505 SUB #1,W \ decrement count loop
46506 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
46507 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
46508 0<> WHILE \ ----> out of loop ----+
46509 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
46511 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
46512 CMP Y,X \ 1 | cycle time out of bound ?
46513 U>= IF \ 2 ^ | yes:
46514 BIC #$30,&RC5_TIM_CTL \ | | stop timer
46515 GOTO BW1 \ | | quit on truncated RC5 message
46517 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
46519 REPEAT \ ----> loop back --+ | with X = new RC5_period value
46520 \ ******************************\ |
46521 \ RC5_SampleEndOf: \ <---------------------+
46522 \ ******************************\
46523 BIC #$30,&RC5_TIM_CTL \ stop timer
46524 \ ******************************\
46525 \ RC5_ComputeNewRC5word \
46526 \ ******************************\
46527 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
46528 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
46529 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
46530 \ ******************************\
46531 \ RC5_ComputeC6bit \
46532 \ ******************************\
46533 BIT #BIT14,T \ test /C6 bit in T
46534 0= IF BIS #BIT6,X \ set C6 bit in X
46535 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
46536 \ ******************************\
46537 \ RC5_CommandByteIsDone \ -- BASE RC5_code
46538 \ ******************************\
46539 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
46540 \ ******************************\
46541 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
46542 XOR @RSP,T \ (new XOR old) Toggle bits
46543 BIT #UF10,T \ repeated RC5_command ?
46544 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
46545 XOR #UF10,0(RSP) \ 5 toggle bit memory
46546 \ ******************************\
46547 \ Display IR_RC5 code \ X = RC5 code
46548 \ ******************************\
46550 MOV &BASE,2(PSP) \ save current base
46551 MOV #$10,&BASE \ set hex base
46552 MOV TOS,0(PSP) \ save TOS
46554 LO2HI \ switch from assembler to FORTH
46555 ['] LCD_CLEAR IS CR \ redirects CR
46556 ['] LCD_WrC IS EMIT \ redirects EMIT
46557 CR ." $" 2 U.R \ print IR_RC5 code
46558 ['] CR >BODY IS CR \ restore CR
46559 ['] EMIT >BODY IS EMIT \ restore EMIT
46560 HI2LO \ switch from FORTH to assembler
46561 MOV TOS,&BASE \ restore current BASE
46563 \ ******************************\
46565 \ ******************************\
46569 \ ------------------------------\
46571 \ ------------------------------\
46572 \ ... \ insert here your background task
46575 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
46576 ADD #4,X \ 1 X = BODY of SLEEP
46579 \ ------------------------------\
46583 \ ------------------------------\
46584 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
46585 \ - - \CNTL Counter lentgh \ 00 = 16 bits
46586 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
46587 \ -- \ID input divider \ 10 = /4
46588 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
46589 \ - \TBCLR TimerB Clear
46592 \ -------------------------------\
46593 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
46594 \ -- \CM Capture Mode
46599 \ --- \OUTMOD \ 011 = set/reset
46605 \ -------------------------------\
46607 \ -------------------------------\
46609 \ ------------------------------\
46610 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
46611 \ ------------------------------\
46612 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
46613 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
46614 \ ------------------------------\
46615 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
46616 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
46617 \ ------------------------------\
46618 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
46619 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
46620 \ ------------------------------\
46621 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
46622 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
46623 \ ------------------------------\
46624 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
46625 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
46626 \ ------------------------------\
46627 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
46628 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
46629 \ ------------------------------\
46630 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
46631 \ ------------------------------\
46632 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
46633 \ ------------------------------\
46634 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
46635 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
46636 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
46637 \ ------------------------------\
46638 BIS.B #LCDVo,&LCDVo_DIR \
46639 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
46640 \ ------------------------------\
46641 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
46642 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
46643 \ ------------------------------\
46644 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
46645 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
46646 \ ******************************\
46648 \ ******************************\
46649 BIS.B #RC5,&IR_IE \ enable RC5_Int
46650 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
46651 MOV #RC5_INT,&IR_Vec \ init interrupt vector
46652 \ ******************************\
46653 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
46654 \ ******************************\
46655 \ %01 0001 0100 \ TAxCTL
46656 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
46657 \ -- \ ID divided by 1
46658 \ -- \ MC MODE = up to TAxCCRn
46659 \ - \ TACLR clear timer count
46662 \ ------------------------------\
46663 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
46664 \ ------------------------------\
46666 \ --- \ TAIDEX pre divisor
46667 \ ------------------------------\
46668 \ %0000 0000 0000 0101 \ TAxCCR0
46669 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
46670 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
46671 \ ------------------------------\
46672 \ %0000 0000 0001 0000 \ TAxCCTL0
46673 \ - \ CAP capture/compare mode = compare
46676 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
46677 \ ------------------------------\
46678 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
46679 \ ------------------------------\
46680 \ define LPM mode for ACCEPT \
46681 \ ------------------------------\
46682 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
46683 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
46684 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
46686 \ ------------------------------\
46687 \ redirects to background task \
46688 \ ------------------------------\
46690 MOV #BACKGROUND,2(X) \
46691 \ ------------------------------\
46693 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
46695 \ ------------------------------\
46697 \ ------------------------------\
46698 $03E8 20_US \ 1- wait 20 ms
46699 $03 TOP_LCD \ 2- send DB5=DB4=1
46700 $CD 20_US \ 3- wait 4,1 ms
46701 $03 TOP_LCD \ 4- send again DB5=DB4=1
46702 $5 20_US \ 5- wait 0,1 ms
46703 $03 TOP_LCD \ 6- send again again DB5=DB4=1
46704 $2 20_US \ wait 40 us = LCD cycle
46705 $02 TOP_LCD \ 7- send DB5=1 DB4=0
46706 $2 20_US \ wait 40 us = LCD cycle
46707 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
46708 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
46709 LCD_Clear \ 10- "LCD_Clear"
46710 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
46711 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
46712 LCD_Clear \ 10- "LCD_Clear"
46713 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
46714 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
46716 ['] CR >BODY IS CR \
46717 ['] EMIT >BODY IS EMIT \
46718 ." RC5toLCD is running. Type STOP to quit"
46719 LIT RECURSE IS WARM \ replace WARM by this START routine
46720 ABORT \ and continue with the next word after WARM...
46721 ; \ ...until interpreter falls in sleep mode within ACCEPT.
46724 CODE STOP \ stops multitasking, must to be used before downloading app
46725 \ restore default action of primary DEFERred word SLEEP, assembly version
46726 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
46727 ADD #4,X \ X = BODY of SLEEP
46728 MOV X,-2(X) \ restore the default background
46731 \ restore default action of primary DEFERred word WARM, FORTH version
46732 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
46734 COLD \ because we want to reset CPU and interrupt vectors
46739 ; downloading RC5toLCD.4th is done
46740 RST_HERE ; this app is protected against <reset>
46748 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
46750 [DEFINED] ASM [IF] \ security test
46754 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
46756 CODE MAX \ n1 n2 -- n3 signed maximum
46757 CMP @PSP,TOS \ n2-n1
46758 S< ?GOTO FW1 \ n2<n1
46764 CODE MIN \ n1 n2 -- n3 signed minimum
46765 CMP @PSP,TOS \ n2-n1
46766 S< ?GOTO BW1 \ n2<n1
46774 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
46775 : U.R \ u n -- display u unsigned in n width (n >= 2)
46777 R> OVER - 0 MAX SPACES TYPE
46782 \ CODE 20_US \ n -- n * 20 us
46783 \ BEGIN \ 3 cycles loop + 6~
46784 \ \ MOV #5,W \ 3 MCLK = 1 MHz
46785 \ \ MOV #23,W \ 3 MCLK = 4 MHz
46786 \ \ MOV #51,W \ 3 MCLK = 8 MHz
46787 \ MOV #104,W \ 3 MCLK = 16 MHz
46788 \ \ MOV #158,W \ 3 MCLK = 24 MHz
46789 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
46794 \ MOV @PSP+,TOS \ 2
46799 CODE 20_US \ n -- n * 20 us
46800 BEGIN \ here we presume that LCD_TIM_IFG = 1...
46802 BIT #1,&LCD_TIM_CTL \ 3
46803 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
46804 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
46806 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
46812 CODE TOP_LCD \ LCD Sample
46813 \ \ if write : %xxxxWWWW --
46814 \ \ if read : -- %0000RRRR
46815 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
46816 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
46817 0= IF \ write LCD bits pattern
46818 AND.B #LCD_DB,TOS \
46819 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
46820 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
46823 THEN \ read LCD bits pattern
46826 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
46827 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
46828 AND.B #LCD_DB,TOS \
46833 CODE LCD_W \ byte -- write byte to LCD
46835 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
46836 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
46837 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
46838 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
46839 COLON \ high level word starts here
46840 TOP_LCD 2 20_US \ write high nibble first
46845 CODE LCD_WrC \ char -- Write Char
46846 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
46851 CODE LCD_WrF \ func -- Write Fonction
46852 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
46858 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
46863 $02 LCD_WrF 100 20_us
46867 [UNDEFINED] OR [IF]
46869 \ https://forth-standard.org/standard/core/OR
46870 \ C OR x1 x2 -- x3 logical OR
46879 : LCD_Entry_set $04 OR LCD_WrF ;
46881 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
46883 : LCD_DSP_Shift $10 OR LCD_WrF ;
46885 : LCD_Fn_Set $20 OR LCD_WrF ;
46887 : LCD_CGRAM_Set $40 OR LCD_WrF ;
46889 : LCD_Goto $80 OR LCD_WrF ;
46891 CODE LCD_R \ -- byte read byte from LCD
46892 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
46893 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
46894 COLON \ starts a FORTH word
46895 TOP_LCD 2 20_us \ -- %0000HHHH
46896 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
46897 HI2LO \ switch from FORTH to assembler
46898 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
46899 ADD.B @PSP+,TOS \ -- %HHHHLLLL
46900 MOV @RSP+,IP \ restore IP saved by COLON
46905 CODE LCD_RdS \ -- status Read Status
46906 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
46911 CODE LCD_RdC \ -- char Read Char
46912 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
46918 \ ******************************\
46919 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
46920 \ ******************************\
46921 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
46922 BIT.B #SW2,&SW2_IN \ test switch S2
46923 0= IF \ case of switch S2 pressed
46924 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
46926 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
46929 BIT.B #SW1,&SW1_IN \ test switch S1 input
46930 0= IF \ case of Switch S1 pressed
46931 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
46933 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
46937 BW1 \ from quit on truncated RC5 message
46938 BW2 \ from repeated RC5 command
46939 BW3 \ from end of RC5_INT
46940 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
46945 \ ******************************\
46946 ASM RC5_INT \ wake up on Px.RC5 change interrupt
46947 \ ******************************\
46948 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
46949 \ ******************************\
46950 \ \ in : SR(9)=old Toggle bit memory (ADD on)
46951 \ \ SMclock = 8|16|24 MHz
46952 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
46953 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
46954 \ \ SR(9)=new Toggle bit memory (ADD on)
46955 \ ******************************\
46956 \ RC5_FirstStartBitHalfCycle: \
46957 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
46958 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
46959 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
46960 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
46961 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
46962 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
46963 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
46964 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
46965 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
46966 MOV #1778,X \ RC5_Period * 1us
46967 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
46968 MOV #14,W \ count of loop
46970 \ ******************************\
46971 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
46972 \ ******************************\ |
46973 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
46974 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
46975 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
46976 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
46977 \ RC5_Compute_3/4_Period: \ |
46978 RRUM #1,X \ X=1/2 cycle |
46981 ADD X,Y \ Y=3/4 cycle
46982 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
46984 \ ******************************\
46985 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
46986 \ ******************************\
46987 BIT.B #RC5,&IR_IN \ C_flag = IR bit
46988 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
46989 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
46990 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
46991 SUB #1,W \ decrement count loop
46992 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
46993 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
46994 0<> WHILE \ ----> out of loop ----+
46995 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
46997 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
46998 CMP Y,X \ 1 | cycle time out of bound ?
46999 U>= IF \ 2 ^ | yes:
47000 BIC #$30,&RC5_TIM_CTL \ | | stop timer
47001 GOTO BW1 \ | | quit on truncated RC5 message
47003 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
47005 REPEAT \ ----> loop back --+ | with X = new RC5_period value
47006 \ ******************************\ |
47007 \ RC5_SampleEndOf: \ <---------------------+
47008 \ ******************************\
47009 BIC #$30,&RC5_TIM_CTL \ stop timer
47010 \ ******************************\
47011 \ RC5_ComputeNewRC5word \
47012 \ ******************************\
47013 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
47014 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
47015 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
47016 \ ******************************\
47017 \ RC5_ComputeC6bit \
47018 \ ******************************\
47019 BIT #BIT14,T \ test /C6 bit in T
47020 0= IF BIS #BIT6,X \ set C6 bit in X
47021 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
47022 \ ******************************\
47023 \ RC5_CommandByteIsDone \ -- BASE RC5_code
47024 \ ******************************\
47025 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
47026 \ ******************************\
47027 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
47028 XOR @RSP,T \ (new XOR old) Toggle bits
47029 BIT #UF10,T \ repeated RC5_command ?
47030 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
47031 XOR #UF10,0(RSP) \ 5 toggle bit memory
47032 \ ******************************\
47033 \ Display IR_RC5 code \ X = RC5 code
47034 \ ******************************\
47036 MOV &BASE,2(PSP) \ save current base
47037 MOV #$10,&BASE \ set hex base
47038 MOV TOS,0(PSP) \ save TOS
47040 LO2HI \ switch from assembler to FORTH
47041 ['] LCD_CLEAR IS CR \ redirects CR
47042 ['] LCD_WrC IS EMIT \ redirects EMIT
47043 CR ." $" 2 U.R \ print IR_RC5 code
47044 ['] CR >BODY IS CR \ restore CR
47045 ['] EMIT >BODY IS EMIT \ restore EMIT
47046 HI2LO \ switch from FORTH to assembler
47047 MOV TOS,&BASE \ restore current BASE
47049 \ ******************************\
47051 \ ******************************\
47055 \ ------------------------------\
47057 \ ------------------------------\
47058 \ ... \ insert here your background task
47061 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
47062 ADD #4,X \ 1 X = BODY of SLEEP
47065 \ ------------------------------\
47069 \ ------------------------------\
47070 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
47071 \ - - \CNTL Counter lentgh \ 00 = 16 bits
47072 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
47073 \ -- \ID input divider \ 10 = /4
47074 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
47075 \ - \TBCLR TimerB Clear
47078 \ -------------------------------\
47079 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
47080 \ -- \CM Capture Mode
47085 \ --- \OUTMOD \ 011 = set/reset
47091 \ -------------------------------\
47093 \ -------------------------------\
47095 \ ------------------------------\
47096 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
47097 \ ------------------------------\
47098 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
47099 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
47100 \ ------------------------------\
47101 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
47102 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
47103 \ ------------------------------\
47104 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
47105 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
47106 \ ------------------------------\
47107 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
47108 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
47109 \ ------------------------------\
47110 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
47111 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
47112 \ ------------------------------\
47113 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
47114 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
47115 \ ------------------------------\
47116 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
47117 \ ------------------------------\
47118 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
47119 \ ------------------------------\
47120 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
47121 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
47122 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
47123 \ ------------------------------\
47124 BIS.B #LCDVo,&LCDVo_DIR \
47125 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
47126 \ ------------------------------\
47127 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
47128 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
47129 \ ------------------------------\
47130 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
47131 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
47132 \ ******************************\
47134 \ ******************************\
47135 BIS.B #RC5,&IR_IE \ enable RC5_Int
47136 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
47137 MOV #RC5_INT,&IR_Vec \ init interrupt vector
47138 \ ******************************\
47139 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
47140 \ ******************************\
47141 \ %01 0001 0100 \ TAxCTL
47142 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
47143 \ -- \ ID divided by 1
47144 \ -- \ MC MODE = up to TAxCCRn
47145 \ - \ TACLR clear timer count
47148 \ ------------------------------\
47149 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
47150 \ ------------------------------\
47152 \ --- \ TAIDEX pre divisor
47153 \ ------------------------------\
47154 \ %0000 0000 0000 0101 \ TAxCCR0
47155 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
47156 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
47157 \ ------------------------------\
47158 \ %0000 0000 0001 0000 \ TAxCCTL0
47159 \ - \ CAP capture/compare mode = compare
47162 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
47163 \ ------------------------------\
47164 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
47165 \ ------------------------------\
47166 \ define LPM mode for ACCEPT \
47167 \ ------------------------------\
47168 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
47169 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
47170 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
47172 \ ------------------------------\
47173 \ redirects to background task \
47174 \ ------------------------------\
47176 MOV #BACKGROUND,2(X) \
47177 \ ------------------------------\
47179 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
47181 \ ------------------------------\
47183 \ ------------------------------\
47184 $03E8 20_US \ 1- wait 20 ms
47185 $03 TOP_LCD \ 2- send DB5=DB4=1
47186 $CD 20_US \ 3- wait 4,1 ms
47187 $03 TOP_LCD \ 4- send again DB5=DB4=1
47188 $5 20_US \ 5- wait 0,1 ms
47189 $03 TOP_LCD \ 6- send again again DB5=DB4=1
47190 $2 20_US \ wait 40 us = LCD cycle
47191 $02 TOP_LCD \ 7- send DB5=1 DB4=0
47192 $2 20_US \ wait 40 us = LCD cycle
47193 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
47194 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
47195 LCD_Clear \ 10- "LCD_Clear"
47196 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
47197 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
47198 LCD_Clear \ 10- "LCD_Clear"
47199 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
47200 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
47202 ['] CR >BODY IS CR \
47203 ['] EMIT >BODY IS EMIT \
47204 ." RC5toLCD is running. Type STOP to quit"
47205 LIT RECURSE IS WARM \ replace WARM by this START routine
47206 ABORT \ and continue with the next word after WARM...
47207 ; \ ...until interpreter falls in sleep mode within ACCEPT.
47210 CODE STOP \ stops multitasking, must to be used before downloading app
47211 \ restore default action of primary DEFERred word SLEEP, assembly version
47212 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
47213 ADD #4,X \ X = BODY of SLEEP
47214 MOV X,-2(X) \ restore the default background
47217 \ restore default action of primary DEFERred word WARM, FORTH version
47218 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
47220 COLD \ because we want to reset CPU and interrupt vectors
47225 ; downloading RC5toLCD.4th is done
47226 RST_HERE ; this app is protected against <reset>
47234 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
47236 [DEFINED] ASM [IF] \ security test
47240 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
47242 CODE MAX \ n1 n2 -- n3 signed maximum
47243 CMP @PSP,TOS \ n2-n1
47244 S< ?GOTO FW1 \ n2<n1
47250 CODE MIN \ n1 n2 -- n3 signed minimum
47251 CMP @PSP,TOS \ n2-n1
47252 S< ?GOTO BW1 \ n2<n1
47260 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
47261 : U.R \ u n -- display u unsigned in n width (n >= 2)
47263 R> OVER - 0 MAX SPACES TYPE
47268 \ CODE 20_US \ n -- n * 20 us
47269 \ BEGIN \ 3 cycles loop + 6~
47270 \ \ MOV #5,W \ 3 MCLK = 1 MHz
47271 \ \ MOV #23,W \ 3 MCLK = 4 MHz
47272 \ \ MOV #51,W \ 3 MCLK = 8 MHz
47273 \ MOV #104,W \ 3 MCLK = 16 MHz
47274 \ \ MOV #158,W \ 3 MCLK = 24 MHz
47275 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
47280 \ MOV @PSP+,TOS \ 2
47285 CODE 20_US \ n -- n * 20 us
47286 BEGIN \ here we presume that LCD_TIM_IFG = 1...
47288 BIT #1,&LCD_TIM_CTL \ 3
47289 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
47290 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
47292 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
47298 CODE TOP_LCD \ LCD Sample
47299 \ \ if write : %xxxxWWWW --
47300 \ \ if read : -- %0000RRRR
47301 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
47302 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
47303 0= IF \ write LCD bits pattern
47304 AND.B #LCD_DB,TOS \
47305 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
47306 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
47309 THEN \ read LCD bits pattern
47312 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
47313 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
47314 AND.B #LCD_DB,TOS \
47319 CODE LCD_W \ byte -- write byte to LCD
47321 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
47322 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
47323 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
47324 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
47325 COLON \ high level word starts here
47326 TOP_LCD 2 20_US \ write high nibble first
47331 CODE LCD_WrC \ char -- Write Char
47332 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
47337 CODE LCD_WrF \ func -- Write Fonction
47338 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
47344 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
47349 $02 LCD_WrF 100 20_us
47353 [UNDEFINED] OR [IF]
47355 \ https://forth-standard.org/standard/core/OR
47356 \ C OR x1 x2 -- x3 logical OR
47365 : LCD_Entry_set $04 OR LCD_WrF ;
47367 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
47369 : LCD_DSP_Shift $10 OR LCD_WrF ;
47371 : LCD_Fn_Set $20 OR LCD_WrF ;
47373 : LCD_CGRAM_Set $40 OR LCD_WrF ;
47375 : LCD_Goto $80 OR LCD_WrF ;
47377 CODE LCD_R \ -- byte read byte from LCD
47378 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
47379 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
47380 COLON \ starts a FORTH word
47381 TOP_LCD 2 20_us \ -- %0000HHHH
47382 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
47383 HI2LO \ switch from FORTH to assembler
47384 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
47385 ADD.B @PSP+,TOS \ -- %HHHHLLLL
47386 MOV @RSP+,IP \ restore IP saved by COLON
47391 CODE LCD_RdS \ -- status Read Status
47392 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
47397 CODE LCD_RdC \ -- char Read Char
47398 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
47404 \ ******************************\
47405 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
47406 \ ******************************\
47407 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
47408 BIT.B #SW2,&SW2_IN \ test switch S2
47409 0= IF \ case of switch S2 pressed
47410 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
47412 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
47415 BIT.B #SW1,&SW1_IN \ test switch S1 input
47416 0= IF \ case of Switch S1 pressed
47417 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
47419 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
47423 BW1 \ from quit on truncated RC5 message
47424 BW2 \ from repeated RC5 command
47425 BW3 \ from end of RC5_INT
47426 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
47431 \ ******************************\
47432 ASM RC5_INT \ wake up on Px.RC5 change interrupt
47433 \ ******************************\
47434 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
47435 \ ******************************\
47436 \ \ in : SR(9)=old Toggle bit memory (ADD on)
47437 \ \ SMclock = 8|16|24 MHz
47438 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
47439 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
47440 \ \ SR(9)=new Toggle bit memory (ADD on)
47441 \ ******************************\
47442 \ RC5_FirstStartBitHalfCycle: \
47443 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
47444 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
47445 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
47446 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
47447 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
47448 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
47449 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
47450 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
47451 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
47452 MOV #1778,X \ RC5_Period * 1us
47453 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
47454 MOV #14,W \ count of loop
47456 \ ******************************\
47457 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
47458 \ ******************************\ |
47459 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
47460 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
47461 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
47462 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
47463 \ RC5_Compute_3/4_Period: \ |
47464 RRUM #1,X \ X=1/2 cycle |
47467 ADD X,Y \ Y=3/4 cycle
47468 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
47470 \ ******************************\
47471 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
47472 \ ******************************\
47473 BIT.B #RC5,&IR_IN \ C_flag = IR bit
47474 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
47475 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
47476 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
47477 SUB #1,W \ decrement count loop
47478 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
47479 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
47480 0<> WHILE \ ----> out of loop ----+
47481 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
47483 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
47484 CMP Y,X \ 1 | cycle time out of bound ?
47485 U>= IF \ 2 ^ | yes:
47486 BIC #$30,&RC5_TIM_CTL \ | | stop timer
47487 GOTO BW1 \ | | quit on truncated RC5 message
47489 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
47491 REPEAT \ ----> loop back --+ | with X = new RC5_period value
47492 \ ******************************\ |
47493 \ RC5_SampleEndOf: \ <---------------------+
47494 \ ******************************\
47495 BIC #$30,&RC5_TIM_CTL \ stop timer
47496 \ ******************************\
47497 \ RC5_ComputeNewRC5word \
47498 \ ******************************\
47499 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
47500 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
47501 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
47502 \ ******************************\
47503 \ RC5_ComputeC6bit \
47504 \ ******************************\
47505 BIT #BIT14,T \ test /C6 bit in T
47506 0= IF BIS #BIT6,X \ set C6 bit in X
47507 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
47508 \ ******************************\
47509 \ RC5_CommandByteIsDone \ -- BASE RC5_code
47510 \ ******************************\
47511 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
47512 \ ******************************\
47513 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
47514 XOR @RSP,T \ (new XOR old) Toggle bits
47515 BIT #UF10,T \ repeated RC5_command ?
47516 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
47517 XOR #UF10,0(RSP) \ 5 toggle bit memory
47518 \ ******************************\
47519 \ Display IR_RC5 code \ X = RC5 code
47520 \ ******************************\
47522 MOV &BASE,2(PSP) \ save current base
47523 MOV #$10,&BASE \ set hex base
47524 MOV TOS,0(PSP) \ save TOS
47526 LO2HI \ switch from assembler to FORTH
47527 ['] LCD_CLEAR IS CR \ redirects CR
47528 ['] LCD_WrC IS EMIT \ redirects EMIT
47529 CR ." $" 2 U.R \ print IR_RC5 code
47530 ['] CR >BODY IS CR \ restore CR
47531 ['] EMIT >BODY IS EMIT \ restore EMIT
47532 HI2LO \ switch from FORTH to assembler
47533 MOV TOS,&BASE \ restore current BASE
47535 \ ******************************\
47537 \ ******************************\
47541 \ ------------------------------\
47543 \ ------------------------------\
47544 \ ... \ insert here your background task
47547 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
47548 ADD #4,X \ 1 X = BODY of SLEEP
47551 \ ------------------------------\
47555 \ ------------------------------\
47556 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
47557 \ - - \CNTL Counter lentgh \ 00 = 16 bits
47558 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
47559 \ -- \ID input divider \ 10 = /4
47560 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
47561 \ - \TBCLR TimerB Clear
47564 \ -------------------------------\
47565 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
47566 \ -- \CM Capture Mode
47571 \ --- \OUTMOD \ 011 = set/reset
47577 \ -------------------------------\
47579 \ -------------------------------\
47581 \ ------------------------------\
47582 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
47583 \ ------------------------------\
47584 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
47585 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
47586 \ ------------------------------\
47587 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
47588 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
47589 \ ------------------------------\
47590 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
47591 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
47592 \ ------------------------------\
47593 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
47594 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
47595 \ ------------------------------\
47596 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
47597 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
47598 \ ------------------------------\
47599 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
47600 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
47601 \ ------------------------------\
47602 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
47603 \ ------------------------------\
47604 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
47605 \ ------------------------------\
47606 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
47607 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
47608 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
47609 \ ------------------------------\
47610 BIS.B #LCDVo,&LCDVo_DIR \
47611 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
47612 \ ------------------------------\
47613 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
47614 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
47615 \ ------------------------------\
47616 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
47617 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
47618 \ ******************************\
47620 \ ******************************\
47621 BIS.B #RC5,&IR_IE \ enable RC5_Int
47622 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
47623 MOV #RC5_INT,&IR_Vec \ init interrupt vector
47624 \ ******************************\
47625 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
47626 \ ******************************\
47627 \ %01 0001 0100 \ TAxCTL
47628 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
47629 \ -- \ ID divided by 1
47630 \ -- \ MC MODE = up to TAxCCRn
47631 \ - \ TACLR clear timer count
47634 \ ------------------------------\
47635 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
47636 \ ------------------------------\
47638 \ --- \ TAIDEX pre divisor
47639 \ ------------------------------\
47640 \ %0000 0000 0000 0101 \ TAxCCR0
47641 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
47642 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
47643 \ ------------------------------\
47644 \ %0000 0000 0001 0000 \ TAxCCTL0
47645 \ - \ CAP capture/compare mode = compare
47648 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
47649 \ ------------------------------\
47650 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
47651 \ ------------------------------\
47652 \ define LPM mode for ACCEPT \
47653 \ ------------------------------\
47654 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
47655 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
47656 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
47658 \ ------------------------------\
47659 \ redirects to background task \
47660 \ ------------------------------\
47662 MOV #BACKGROUND,2(X) \
47663 \ ------------------------------\
47665 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
47667 \ ------------------------------\
47669 \ ------------------------------\
47670 $03E8 20_US \ 1- wait 20 ms
47671 $03 TOP_LCD \ 2- send DB5=DB4=1
47672 $CD 20_US \ 3- wait 4,1 ms
47673 $03 TOP_LCD \ 4- send again DB5=DB4=1
47674 $5 20_US \ 5- wait 0,1 ms
47675 $03 TOP_LCD \ 6- send again again DB5=DB4=1
47676 $2 20_US \ wait 40 us = LCD cycle
47677 $02 TOP_LCD \ 7- send DB5=1 DB4=0
47678 $2 20_US \ wait 40 us = LCD cycle
47679 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
47680 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
47681 LCD_Clear \ 10- "LCD_Clear"
47682 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
47683 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
47684 LCD_Clear \ 10- "LCD_Clear"
47685 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
47686 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
47688 ['] CR >BODY IS CR \
47689 ['] EMIT >BODY IS EMIT \
47690 ." RC5toLCD is running. Type STOP to quit"
47691 LIT RECURSE IS WARM \ replace WARM by this START routine
47692 ABORT \ and continue with the next word after WARM...
47693 ; \ ...until interpreter falls in sleep mode within ACCEPT.
47696 CODE STOP \ stops multitasking, must to be used before downloading app
47697 \ restore default action of primary DEFERred word SLEEP, assembly version
47698 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
47699 ADD #4,X \ X = BODY of SLEEP
47700 MOV X,-2(X) \ restore the default background
47703 \ restore default action of primary DEFERred word WARM, FORTH version
47704 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
47706 COLD \ because we want to reset CPU and interrupt vectors
47711 ; downloading RC5toLCD.4th is done
47712 RST_HERE ; this app is protected against <reset>
47720 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
47722 [DEFINED] ASM [IF] \ security test
47726 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
47728 CODE MAX \ n1 n2 -- n3 signed maximum
47729 CMP @PSP,TOS \ n2-n1
47730 S< ?GOTO FW1 \ n2<n1
47736 CODE MIN \ n1 n2 -- n3 signed minimum
47737 CMP @PSP,TOS \ n2-n1
47738 S< ?GOTO BW1 \ n2<n1
47746 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
47747 : U.R \ u n -- display u unsigned in n width (n >= 2)
47749 R> OVER - 0 MAX SPACES TYPE
47754 \ CODE 20_US \ n -- n * 20 us
47755 \ BEGIN \ 3 cycles loop + 6~
47756 \ \ MOV #5,W \ 3 MCLK = 1 MHz
47757 \ \ MOV #23,W \ 3 MCLK = 4 MHz
47758 \ \ MOV #51,W \ 3 MCLK = 8 MHz
47759 \ MOV #104,W \ 3 MCLK = 16 MHz
47760 \ \ MOV #158,W \ 3 MCLK = 24 MHz
47761 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
47766 \ MOV @PSP+,TOS \ 2
47771 CODE 20_US \ n -- n * 20 us
47772 BEGIN \ here we presume that LCD_TIM_IFG = 1...
47774 BIT #1,&LCD_TIM_CTL \ 3
47775 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
47776 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
47778 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
47784 CODE TOP_LCD \ LCD Sample
47785 \ \ if write : %xxxxWWWW --
47786 \ \ if read : -- %0000RRRR
47787 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
47788 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
47789 0= IF \ write LCD bits pattern
47790 AND.B #LCD_DB,TOS \
47791 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
47792 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
47795 THEN \ read LCD bits pattern
47798 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
47799 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
47800 AND.B #LCD_DB,TOS \
47805 CODE LCD_W \ byte -- write byte to LCD
47807 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
47808 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
47809 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
47810 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
47811 COLON \ high level word starts here
47812 TOP_LCD 2 20_US \ write high nibble first
47817 CODE LCD_WrC \ char -- Write Char
47818 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
47823 CODE LCD_WrF \ func -- Write Fonction
47824 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
47830 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
47835 $02 LCD_WrF 100 20_us
47839 [UNDEFINED] OR [IF]
47841 \ https://forth-standard.org/standard/core/OR
47842 \ C OR x1 x2 -- x3 logical OR
47851 : LCD_Entry_set $04 OR LCD_WrF ;
47853 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
47855 : LCD_DSP_Shift $10 OR LCD_WrF ;
47857 : LCD_Fn_Set $20 OR LCD_WrF ;
47859 : LCD_CGRAM_Set $40 OR LCD_WrF ;
47861 : LCD_Goto $80 OR LCD_WrF ;
47863 CODE LCD_R \ -- byte read byte from LCD
47864 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
47865 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
47866 COLON \ starts a FORTH word
47867 TOP_LCD 2 20_us \ -- %0000HHHH
47868 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
47869 HI2LO \ switch from FORTH to assembler
47870 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
47871 ADD.B @PSP+,TOS \ -- %HHHHLLLL
47872 MOV @RSP+,IP \ restore IP saved by COLON
47877 CODE LCD_RdS \ -- status Read Status
47878 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
47883 CODE LCD_RdC \ -- char Read Char
47884 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
47890 \ ******************************\
47891 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
47892 \ ******************************\
47893 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
47894 BIT.B #SW2,&SW2_IN \ test switch S2
47895 0= IF \ case of switch S2 pressed
47896 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
47898 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
47901 BIT.B #SW1,&SW1_IN \ test switch S1 input
47902 0= IF \ case of Switch S1 pressed
47903 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
47905 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
47909 BW1 \ from quit on truncated RC5 message
47910 BW2 \ from repeated RC5 command
47911 BW3 \ from end of RC5_INT
47912 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
47917 \ ******************************\
47918 ASM RC5_INT \ wake up on Px.RC5 change interrupt
47919 \ ******************************\
47920 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
47921 \ ******************************\
47922 \ \ in : SR(9)=old Toggle bit memory (ADD on)
47923 \ \ SMclock = 8|16|24 MHz
47924 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
47925 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
47926 \ \ SR(9)=new Toggle bit memory (ADD on)
47927 \ ******************************\
47928 \ RC5_FirstStartBitHalfCycle: \
47929 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
47930 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
47931 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
47932 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
47933 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
47934 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
47935 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
47936 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
47937 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
47938 MOV #1778,X \ RC5_Period * 1us
47939 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
47940 MOV #14,W \ count of loop
47942 \ ******************************\
47943 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
47944 \ ******************************\ |
47945 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
47946 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
47947 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
47948 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
47949 \ RC5_Compute_3/4_Period: \ |
47950 RRUM #1,X \ X=1/2 cycle |
47953 ADD X,Y \ Y=3/4 cycle
47954 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
47956 \ ******************************\
47957 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
47958 \ ******************************\
47959 BIT.B #RC5,&IR_IN \ C_flag = IR bit
47960 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
47961 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
47962 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
47963 SUB #1,W \ decrement count loop
47964 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
47965 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
47966 0<> WHILE \ ----> out of loop ----+
47967 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
47969 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
47970 CMP Y,X \ 1 | cycle time out of bound ?
47971 U>= IF \ 2 ^ | yes:
47972 BIC #$30,&RC5_TIM_CTL \ | | stop timer
47973 GOTO BW1 \ | | quit on truncated RC5 message
47975 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
47977 REPEAT \ ----> loop back --+ | with X = new RC5_period value
47978 \ ******************************\ |
47979 \ RC5_SampleEndOf: \ <---------------------+
47980 \ ******************************\
47981 BIC #$30,&RC5_TIM_CTL \ stop timer
47982 \ ******************************\
47983 \ RC5_ComputeNewRC5word \
47984 \ ******************************\
47985 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
47986 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
47987 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
47988 \ ******************************\
47989 \ RC5_ComputeC6bit \
47990 \ ******************************\
47991 BIT #BIT14,T \ test /C6 bit in T
47992 0= IF BIS #BIT6,X \ set C6 bit in X
47993 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
47994 \ ******************************\
47995 \ RC5_CommandByteIsDone \ -- BASE RC5_code
47996 \ ******************************\
47997 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
47998 \ ******************************\
47999 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
48000 XOR @RSP,T \ (new XOR old) Toggle bits
48001 BIT #UF10,T \ repeated RC5_command ?
48002 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
48003 XOR #UF10,0(RSP) \ 5 toggle bit memory
48004 \ ******************************\
48005 \ Display IR_RC5 code \ X = RC5 code
48006 \ ******************************\
48008 MOV &BASE,2(PSP) \ save current base
48009 MOV #$10,&BASE \ set hex base
48010 MOV TOS,0(PSP) \ save TOS
48012 LO2HI \ switch from assembler to FORTH
48013 ['] LCD_CLEAR IS CR \ redirects CR
48014 ['] LCD_WrC IS EMIT \ redirects EMIT
48015 CR ." $" 2 U.R \ print IR_RC5 code
48016 ['] CR >BODY IS CR \ restore CR
48017 ['] EMIT >BODY IS EMIT \ restore EMIT
48018 HI2LO \ switch from FORTH to assembler
48019 MOV TOS,&BASE \ restore current BASE
48021 \ ******************************\
48023 \ ******************************\
48027 \ ------------------------------\
48029 \ ------------------------------\
48030 \ ... \ insert here your background task
48033 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
48034 ADD #4,X \ 1 X = BODY of SLEEP
48037 \ ------------------------------\
48041 \ ------------------------------\
48042 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
48043 \ - - \CNTL Counter lentgh \ 00 = 16 bits
48044 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
48045 \ -- \ID input divider \ 10 = /4
48046 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
48047 \ - \TBCLR TimerB Clear
48050 \ -------------------------------\
48051 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
48052 \ -- \CM Capture Mode
48057 \ --- \OUTMOD \ 011 = set/reset
48063 \ -------------------------------\
48065 \ -------------------------------\
48067 \ ------------------------------\
48068 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
48069 \ ------------------------------\
48070 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
48071 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
48072 \ ------------------------------\
48073 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
48074 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
48075 \ ------------------------------\
48076 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
48077 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
48078 \ ------------------------------\
48079 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
48080 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
48081 \ ------------------------------\
48082 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
48083 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
48084 \ ------------------------------\
48085 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
48086 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
48087 \ ------------------------------\
48088 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
48089 \ ------------------------------\
48090 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
48091 \ ------------------------------\
48092 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
48093 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
48094 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
48095 \ ------------------------------\
48096 BIS.B #LCDVo,&LCDVo_DIR \
48097 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
48098 \ ------------------------------\
48099 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
48100 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
48101 \ ------------------------------\
48102 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
48103 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
48104 \ ******************************\
48106 \ ******************************\
48107 BIS.B #RC5,&IR_IE \ enable RC5_Int
48108 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
48109 MOV #RC5_INT,&IR_Vec \ init interrupt vector
48110 \ ******************************\
48111 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
48112 \ ******************************\
48113 \ %01 0001 0100 \ TAxCTL
48114 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
48115 \ -- \ ID divided by 1
48116 \ -- \ MC MODE = up to TAxCCRn
48117 \ - \ TACLR clear timer count
48120 \ ------------------------------\
48121 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
48122 \ ------------------------------\
48124 \ --- \ TAIDEX pre divisor
48125 \ ------------------------------\
48126 \ %0000 0000 0000 0101 \ TAxCCR0
48127 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
48128 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
48129 \ ------------------------------\
48130 \ %0000 0000 0001 0000 \ TAxCCTL0
48131 \ - \ CAP capture/compare mode = compare
48134 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
48135 \ ------------------------------\
48136 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
48137 \ ------------------------------\
48138 \ define LPM mode for ACCEPT \
48139 \ ------------------------------\
48140 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
48141 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
48142 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
48144 \ ------------------------------\
48145 \ redirects to background task \
48146 \ ------------------------------\
48148 MOV #BACKGROUND,2(X) \
48149 \ ------------------------------\
48151 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
48153 \ ------------------------------\
48155 \ ------------------------------\
48156 $03E8 20_US \ 1- wait 20 ms
48157 $03 TOP_LCD \ 2- send DB5=DB4=1
48158 $CD 20_US \ 3- wait 4,1 ms
48159 $03 TOP_LCD \ 4- send again DB5=DB4=1
48160 $5 20_US \ 5- wait 0,1 ms
48161 $03 TOP_LCD \ 6- send again again DB5=DB4=1
48162 $2 20_US \ wait 40 us = LCD cycle
48163 $02 TOP_LCD \ 7- send DB5=1 DB4=0
48164 $2 20_US \ wait 40 us = LCD cycle
48165 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
48166 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
48167 LCD_Clear \ 10- "LCD_Clear"
48168 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
48169 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
48170 LCD_Clear \ 10- "LCD_Clear"
48171 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
48172 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
48174 ['] CR >BODY IS CR \
48175 ['] EMIT >BODY IS EMIT \
48176 ." RC5toLCD is running. Type STOP to quit"
48177 LIT RECURSE IS WARM \ replace WARM by this START routine
48178 ABORT \ and continue with the next word after WARM...
48179 ; \ ...until interpreter falls in sleep mode within ACCEPT.
48182 CODE STOP \ stops multitasking, must to be used before downloading app
48183 \ restore default action of primary DEFERred word SLEEP, assembly version
48184 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
48185 ADD #4,X \ X = BODY of SLEEP
48186 MOV X,-2(X) \ restore the default background
48189 \ restore default action of primary DEFERred word WARM, FORTH version
48190 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
48192 COLD \ because we want to reset CPU and interrupt vectors
48197 ; downloading RC5toLCD.4th is done
48198 RST_HERE ; this app is protected against <reset>
48206 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
48208 [DEFINED] ASM [IF] \ security test
48212 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
48214 CODE MAX \ n1 n2 -- n3 signed maximum
48215 CMP @PSP,TOS \ n2-n1
48216 S< ?GOTO FW1 \ n2<n1
48222 CODE MIN \ n1 n2 -- n3 signed minimum
48223 CMP @PSP,TOS \ n2-n1
48224 S< ?GOTO BW1 \ n2<n1
48232 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
48233 : U.R \ u n -- display u unsigned in n width (n >= 2)
48235 R> OVER - 0 MAX SPACES TYPE
48240 \ CODE 20_US \ n -- n * 20 us
48241 \ BEGIN \ 3 cycles loop + 6~
48242 \ \ MOV #5,W \ 3 MCLK = 1 MHz
48243 \ \ MOV #23,W \ 3 MCLK = 4 MHz
48244 \ \ MOV #51,W \ 3 MCLK = 8 MHz
48245 \ MOV #104,W \ 3 MCLK = 16 MHz
48246 \ \ MOV #158,W \ 3 MCLK = 24 MHz
48247 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
48252 \ MOV @PSP+,TOS \ 2
48257 CODE 20_US \ n -- n * 20 us
48258 BEGIN \ here we presume that LCD_TIM_IFG = 1...
48260 BIT #1,&LCD_TIM_CTL \ 3
48261 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
48262 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
48264 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
48270 CODE TOP_LCD \ LCD Sample
48271 \ \ if write : %xxxxWWWW --
48272 \ \ if read : -- %0000RRRR
48273 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
48274 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
48275 0= IF \ write LCD bits pattern
48276 AND.B #LCD_DB,TOS \
48277 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
48278 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
48281 THEN \ read LCD bits pattern
48284 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
48285 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
48286 AND.B #LCD_DB,TOS \
48291 CODE LCD_W \ byte -- write byte to LCD
48293 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
48294 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
48295 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
48296 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
48297 COLON \ high level word starts here
48298 TOP_LCD 2 20_US \ write high nibble first
48303 CODE LCD_WrC \ char -- Write Char
48304 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
48309 CODE LCD_WrF \ func -- Write Fonction
48310 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
48316 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
48321 $02 LCD_WrF 100 20_us
48325 [UNDEFINED] OR [IF]
48327 \ https://forth-standard.org/standard/core/OR
48328 \ C OR x1 x2 -- x3 logical OR
48337 : LCD_Entry_set $04 OR LCD_WrF ;
48339 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
48341 : LCD_DSP_Shift $10 OR LCD_WrF ;
48343 : LCD_Fn_Set $20 OR LCD_WrF ;
48345 : LCD_CGRAM_Set $40 OR LCD_WrF ;
48347 : LCD_Goto $80 OR LCD_WrF ;
48349 CODE LCD_R \ -- byte read byte from LCD
48350 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
48351 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
48352 COLON \ starts a FORTH word
48353 TOP_LCD 2 20_us \ -- %0000HHHH
48354 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
48355 HI2LO \ switch from FORTH to assembler
48356 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
48357 ADD.B @PSP+,TOS \ -- %HHHHLLLL
48358 MOV @RSP+,IP \ restore IP saved by COLON
48363 CODE LCD_RdS \ -- status Read Status
48364 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
48369 CODE LCD_RdC \ -- char Read Char
48370 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
48376 \ ******************************\
48377 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
48378 \ ******************************\
48379 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
48380 BIT.B #SW2,&SW2_IN \ test switch S2
48381 0= IF \ case of switch S2 pressed
48382 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
48384 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
48387 BIT.B #SW1,&SW1_IN \ test switch S1 input
48388 0= IF \ case of Switch S1 pressed
48389 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
48391 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
48395 BW1 \ from quit on truncated RC5 message
48396 BW2 \ from repeated RC5 command
48397 BW3 \ from end of RC5_INT
48398 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
48403 \ ******************************\
48404 ASM RC5_INT \ wake up on Px.RC5 change interrupt
48405 \ ******************************\
48406 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
48407 \ ******************************\
48408 \ \ in : SR(9)=old Toggle bit memory (ADD on)
48409 \ \ SMclock = 8|16|24 MHz
48410 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
48411 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
48412 \ \ SR(9)=new Toggle bit memory (ADD on)
48413 \ ******************************\
48414 \ RC5_FirstStartBitHalfCycle: \
48415 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
48416 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
48417 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
48418 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
48419 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
48420 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
48421 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
48422 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
48423 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
48424 MOV #1778,X \ RC5_Period * 1us
48425 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
48426 MOV #14,W \ count of loop
48428 \ ******************************\
48429 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
48430 \ ******************************\ |
48431 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
48432 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
48433 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
48434 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
48435 \ RC5_Compute_3/4_Period: \ |
48436 RRUM #1,X \ X=1/2 cycle |
48439 ADD X,Y \ Y=3/4 cycle
48440 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
48442 \ ******************************\
48443 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
48444 \ ******************************\
48445 BIT.B #RC5,&IR_IN \ C_flag = IR bit
48446 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
48447 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
48448 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
48449 SUB #1,W \ decrement count loop
48450 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
48451 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
48452 0<> WHILE \ ----> out of loop ----+
48453 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
48455 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
48456 CMP Y,X \ 1 | cycle time out of bound ?
48457 U>= IF \ 2 ^ | yes:
48458 BIC #$30,&RC5_TIM_CTL \ | | stop timer
48459 GOTO BW1 \ | | quit on truncated RC5 message
48461 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
48463 REPEAT \ ----> loop back --+ | with X = new RC5_period value
48464 \ ******************************\ |
48465 \ RC5_SampleEndOf: \ <---------------------+
48466 \ ******************************\
48467 BIC #$30,&RC5_TIM_CTL \ stop timer
48468 \ ******************************\
48469 \ RC5_ComputeNewRC5word \
48470 \ ******************************\
48471 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
48472 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
48473 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
48474 \ ******************************\
48475 \ RC5_ComputeC6bit \
48476 \ ******************************\
48477 BIT #BIT14,T \ test /C6 bit in T
48478 0= IF BIS #BIT6,X \ set C6 bit in X
48479 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
48480 \ ******************************\
48481 \ RC5_CommandByteIsDone \ -- BASE RC5_code
48482 \ ******************************\
48483 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
48484 \ ******************************\
48485 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
48486 XOR @RSP,T \ (new XOR old) Toggle bits
48487 BIT #UF10,T \ repeated RC5_command ?
48488 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
48489 XOR #UF10,0(RSP) \ 5 toggle bit memory
48490 \ ******************************\
48491 \ Display IR_RC5 code \ X = RC5 code
48492 \ ******************************\
48494 MOV &BASE,2(PSP) \ save current base
48495 MOV #$10,&BASE \ set hex base
48496 MOV TOS,0(PSP) \ save TOS
48498 LO2HI \ switch from assembler to FORTH
48499 ['] LCD_CLEAR IS CR \ redirects CR
48500 ['] LCD_WrC IS EMIT \ redirects EMIT
48501 CR ." $" 2 U.R \ print IR_RC5 code
48502 ['] CR >BODY IS CR \ restore CR
48503 ['] EMIT >BODY IS EMIT \ restore EMIT
48504 HI2LO \ switch from FORTH to assembler
48505 MOV TOS,&BASE \ restore current BASE
48507 \ ******************************\
48509 \ ******************************\
48513 \ ------------------------------\
48515 \ ------------------------------\
48516 \ ... \ insert here your background task
48519 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
48520 ADD #4,X \ 1 X = BODY of SLEEP
48523 \ ------------------------------\
48527 \ ------------------------------\
48528 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
48529 \ - - \CNTL Counter lentgh \ 00 = 16 bits
48530 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
48531 \ -- \ID input divider \ 10 = /4
48532 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
48533 \ - \TBCLR TimerB Clear
48536 \ -------------------------------\
48537 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
48538 \ -- \CM Capture Mode
48543 \ --- \OUTMOD \ 011 = set/reset
48549 \ -------------------------------\
48551 \ -------------------------------\
48553 \ ------------------------------\
48554 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
48555 \ ------------------------------\
48556 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
48557 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
48558 \ ------------------------------\
48559 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
48560 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
48561 \ ------------------------------\
48562 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
48563 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
48564 \ ------------------------------\
48565 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
48566 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
48567 \ ------------------------------\
48568 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
48569 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
48570 \ ------------------------------\
48571 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
48572 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
48573 \ ------------------------------\
48574 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
48575 \ ------------------------------\
48576 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
48577 \ ------------------------------\
48578 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
48579 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
48580 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
48581 \ ------------------------------\
48582 BIS.B #LCDVo,&LCDVo_DIR \
48583 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
48584 \ ------------------------------\
48585 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
48586 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
48587 \ ------------------------------\
48588 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
48589 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
48590 \ ******************************\
48592 \ ******************************\
48593 BIS.B #RC5,&IR_IE \ enable RC5_Int
48594 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
48595 MOV #RC5_INT,&IR_Vec \ init interrupt vector
48596 \ ******************************\
48597 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
48598 \ ******************************\
48599 \ %01 0001 0100 \ TAxCTL
48600 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
48601 \ -- \ ID divided by 1
48602 \ -- \ MC MODE = up to TAxCCRn
48603 \ - \ TACLR clear timer count
48606 \ ------------------------------\
48607 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
48608 \ ------------------------------\
48610 \ --- \ TAIDEX pre divisor
48611 \ ------------------------------\
48612 \ %0000 0000 0000 0101 \ TAxCCR0
48613 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
48614 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
48615 \ ------------------------------\
48616 \ %0000 0000 0001 0000 \ TAxCCTL0
48617 \ - \ CAP capture/compare mode = compare
48620 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
48621 \ ------------------------------\
48622 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
48623 \ ------------------------------\
48624 \ define LPM mode for ACCEPT \
48625 \ ------------------------------\
48626 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
48627 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
48628 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
48630 \ ------------------------------\
48631 \ redirects to background task \
48632 \ ------------------------------\
48634 MOV #BACKGROUND,2(X) \
48635 \ ------------------------------\
48637 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
48639 \ ------------------------------\
48641 \ ------------------------------\
48642 $03E8 20_US \ 1- wait 20 ms
48643 $03 TOP_LCD \ 2- send DB5=DB4=1
48644 $CD 20_US \ 3- wait 4,1 ms
48645 $03 TOP_LCD \ 4- send again DB5=DB4=1
48646 $5 20_US \ 5- wait 0,1 ms
48647 $03 TOP_LCD \ 6- send again again DB5=DB4=1
48648 $2 20_US \ wait 40 us = LCD cycle
48649 $02 TOP_LCD \ 7- send DB5=1 DB4=0
48650 $2 20_US \ wait 40 us = LCD cycle
48651 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
48652 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
48653 LCD_Clear \ 10- "LCD_Clear"
48654 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
48655 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
48656 LCD_Clear \ 10- "LCD_Clear"
48657 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
48658 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
48660 ['] CR >BODY IS CR \
48661 ['] EMIT >BODY IS EMIT \
48662 ." RC5toLCD is running. Type STOP to quit"
48663 LIT RECURSE IS WARM \ replace WARM by this START routine
48664 ABORT \ and continue with the next word after WARM...
48665 ; \ ...until interpreter falls in sleep mode within ACCEPT.
48668 CODE STOP \ stops multitasking, must to be used before downloading app
48669 \ restore default action of primary DEFERred word SLEEP, assembly version
48670 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
48671 ADD #4,X \ X = BODY of SLEEP
48672 MOV X,-2(X) \ restore the default background
48675 \ restore default action of primary DEFERred word WARM, FORTH version
48676 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
48678 COLD \ because we want to reset CPU and interrupt vectors
48683 ; downloading RC5toLCD.4th is done
48684 RST_HERE ; this app is protected against <reset>
48692 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
48694 [DEFINED] ASM [IF] \ security test
48698 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
48700 CODE MAX \ n1 n2 -- n3 signed maximum
48701 CMP @PSP,TOS \ n2-n1
48702 S< ?GOTO FW1 \ n2<n1
48708 CODE MIN \ n1 n2 -- n3 signed minimum
48709 CMP @PSP,TOS \ n2-n1
48710 S< ?GOTO BW1 \ n2<n1
48718 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
48719 : U.R \ u n -- display u unsigned in n width (n >= 2)
48721 R> OVER - 0 MAX SPACES TYPE
48726 \ CODE 20_US \ n -- n * 20 us
48727 \ BEGIN \ 3 cycles loop + 6~
48728 \ \ MOV #5,W \ 3 MCLK = 1 MHz
48729 \ \ MOV #23,W \ 3 MCLK = 4 MHz
48730 \ \ MOV #51,W \ 3 MCLK = 8 MHz
48731 \ MOV #104,W \ 3 MCLK = 16 MHz
48732 \ \ MOV #158,W \ 3 MCLK = 24 MHz
48733 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
48738 \ MOV @PSP+,TOS \ 2
48743 CODE 20_US \ n -- n * 20 us
48744 BEGIN \ here we presume that LCD_TIM_IFG = 1...
48746 BIT #1,&LCD_TIM_CTL \ 3
48747 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
48748 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
48750 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
48756 CODE TOP_LCD \ LCD Sample
48757 \ \ if write : %xxxxWWWW --
48758 \ \ if read : -- %0000RRRR
48759 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
48760 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
48761 0= IF \ write LCD bits pattern
48762 AND.B #LCD_DB,TOS \
48763 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
48764 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
48767 THEN \ read LCD bits pattern
48770 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
48771 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
48772 AND.B #LCD_DB,TOS \
48777 CODE LCD_W \ byte -- write byte to LCD
48779 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
48780 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
48781 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
48782 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
48783 COLON \ high level word starts here
48784 TOP_LCD 2 20_US \ write high nibble first
48789 CODE LCD_WrC \ char -- Write Char
48790 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
48795 CODE LCD_WrF \ func -- Write Fonction
48796 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
48802 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
48807 $02 LCD_WrF 100 20_us
48811 [UNDEFINED] OR [IF]
48813 \ https://forth-standard.org/standard/core/OR
48814 \ C OR x1 x2 -- x3 logical OR
48823 : LCD_Entry_set $04 OR LCD_WrF ;
48825 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
48827 : LCD_DSP_Shift $10 OR LCD_WrF ;
48829 : LCD_Fn_Set $20 OR LCD_WrF ;
48831 : LCD_CGRAM_Set $40 OR LCD_WrF ;
48833 : LCD_Goto $80 OR LCD_WrF ;
48835 CODE LCD_R \ -- byte read byte from LCD
48836 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
48837 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
48838 COLON \ starts a FORTH word
48839 TOP_LCD 2 20_us \ -- %0000HHHH
48840 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
48841 HI2LO \ switch from FORTH to assembler
48842 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
48843 ADD.B @PSP+,TOS \ -- %HHHHLLLL
48844 MOV @RSP+,IP \ restore IP saved by COLON
48849 CODE LCD_RdS \ -- status Read Status
48850 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
48855 CODE LCD_RdC \ -- char Read Char
48856 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
48862 \ ******************************\
48863 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
48864 \ ******************************\
48865 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
48866 BIT.B #SW2,&SW2_IN \ test switch S2
48867 0= IF \ case of switch S2 pressed
48868 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
48870 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
48873 BIT.B #SW1,&SW1_IN \ test switch S1 input
48874 0= IF \ case of Switch S1 pressed
48875 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
48877 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
48881 BW1 \ from quit on truncated RC5 message
48882 BW2 \ from repeated RC5 command
48883 BW3 \ from end of RC5_INT
48884 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
48889 \ ******************************\
48890 ASM RC5_INT \ wake up on Px.RC5 change interrupt
48891 \ ******************************\
48892 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
48893 \ ******************************\
48894 \ \ in : SR(9)=old Toggle bit memory (ADD on)
48895 \ \ SMclock = 8|16|24 MHz
48896 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
48897 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
48898 \ \ SR(9)=new Toggle bit memory (ADD on)
48899 \ ******************************\
48900 \ RC5_FirstStartBitHalfCycle: \
48901 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
48902 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
48903 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
48904 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
48905 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
48906 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
48907 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
48908 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
48909 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
48910 MOV #1778,X \ RC5_Period * 1us
48911 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
48912 MOV #14,W \ count of loop
48914 \ ******************************\
48915 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
48916 \ ******************************\ |
48917 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
48918 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
48919 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
48920 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
48921 \ RC5_Compute_3/4_Period: \ |
48922 RRUM #1,X \ X=1/2 cycle |
48925 ADD X,Y \ Y=3/4 cycle
48926 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
48928 \ ******************************\
48929 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
48930 \ ******************************\
48931 BIT.B #RC5,&IR_IN \ C_flag = IR bit
48932 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
48933 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
48934 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
48935 SUB #1,W \ decrement count loop
48936 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
48937 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
48938 0<> WHILE \ ----> out of loop ----+
48939 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
48941 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
48942 CMP Y,X \ 1 | cycle time out of bound ?
48943 U>= IF \ 2 ^ | yes:
48944 BIC #$30,&RC5_TIM_CTL \ | | stop timer
48945 GOTO BW1 \ | | quit on truncated RC5 message
48947 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
48949 REPEAT \ ----> loop back --+ | with X = new RC5_period value
48950 \ ******************************\ |
48951 \ RC5_SampleEndOf: \ <---------------------+
48952 \ ******************************\
48953 BIC #$30,&RC5_TIM_CTL \ stop timer
48954 \ ******************************\
48955 \ RC5_ComputeNewRC5word \
48956 \ ******************************\
48957 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
48958 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
48959 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
48960 \ ******************************\
48961 \ RC5_ComputeC6bit \
48962 \ ******************************\
48963 BIT #BIT14,T \ test /C6 bit in T
48964 0= IF BIS #BIT6,X \ set C6 bit in X
48965 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
48966 \ ******************************\
48967 \ RC5_CommandByteIsDone \ -- BASE RC5_code
48968 \ ******************************\
48969 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
48970 \ ******************************\
48971 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
48972 XOR @RSP,T \ (new XOR old) Toggle bits
48973 BIT #UF10,T \ repeated RC5_command ?
48974 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
48975 XOR #UF10,0(RSP) \ 5 toggle bit memory
48976 \ ******************************\
48977 \ Display IR_RC5 code \ X = RC5 code
48978 \ ******************************\
48980 MOV &BASE,2(PSP) \ save current base
48981 MOV #$10,&BASE \ set hex base
48982 MOV TOS,0(PSP) \ save TOS
48984 LO2HI \ switch from assembler to FORTH
48985 ['] LCD_CLEAR IS CR \ redirects CR
48986 ['] LCD_WrC IS EMIT \ redirects EMIT
48987 CR ." $" 2 U.R \ print IR_RC5 code
48988 ['] CR >BODY IS CR \ restore CR
48989 ['] EMIT >BODY IS EMIT \ restore EMIT
48990 HI2LO \ switch from FORTH to assembler
48991 MOV TOS,&BASE \ restore current BASE
48993 \ ******************************\
48995 \ ******************************\
48999 \ ------------------------------\
49001 \ ------------------------------\
49002 \ ... \ insert here your background task
49005 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
49006 ADD #4,X \ 1 X = BODY of SLEEP
49009 \ ------------------------------\
49013 \ ------------------------------\
49014 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
49015 \ - - \CNTL Counter lentgh \ 00 = 16 bits
49016 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
49017 \ -- \ID input divider \ 10 = /4
49018 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
49019 \ - \TBCLR TimerB Clear
49022 \ -------------------------------\
49023 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
49024 \ -- \CM Capture Mode
49029 \ --- \OUTMOD \ 011 = set/reset
49035 \ -------------------------------\
49037 \ -------------------------------\
49039 \ ------------------------------\
49040 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
49041 \ ------------------------------\
49042 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
49043 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
49044 \ ------------------------------\
49045 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
49046 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
49047 \ ------------------------------\
49048 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
49049 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
49050 \ ------------------------------\
49051 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
49052 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
49053 \ ------------------------------\
49054 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
49055 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
49056 \ ------------------------------\
49057 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
49058 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
49059 \ ------------------------------\
49060 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
49061 \ ------------------------------\
49062 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
49063 \ ------------------------------\
49064 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
49065 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
49066 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
49067 \ ------------------------------\
49068 BIS.B #LCDVo,&LCDVo_DIR \
49069 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
49070 \ ------------------------------\
49071 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
49072 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
49073 \ ------------------------------\
49074 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
49075 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
49076 \ ******************************\
49078 \ ******************************\
49079 BIS.B #RC5,&IR_IE \ enable RC5_Int
49080 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
49081 MOV #RC5_INT,&IR_Vec \ init interrupt vector
49082 \ ******************************\
49083 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
49084 \ ******************************\
49085 \ %01 0001 0100 \ TAxCTL
49086 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
49087 \ -- \ ID divided by 1
49088 \ -- \ MC MODE = up to TAxCCRn
49089 \ - \ TACLR clear timer count
49092 \ ------------------------------\
49093 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
49094 \ ------------------------------\
49096 \ --- \ TAIDEX pre divisor
49097 \ ------------------------------\
49098 \ %0000 0000 0000 0101 \ TAxCCR0
49099 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
49100 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
49101 \ ------------------------------\
49102 \ %0000 0000 0001 0000 \ TAxCCTL0
49103 \ - \ CAP capture/compare mode = compare
49106 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
49107 \ ------------------------------\
49108 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
49109 \ ------------------------------\
49110 \ define LPM mode for ACCEPT \
49111 \ ------------------------------\
49112 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
49113 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
49114 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
49116 \ ------------------------------\
49117 \ redirects to background task \
49118 \ ------------------------------\
49120 MOV #BACKGROUND,2(X) \
49121 \ ------------------------------\
49123 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
49125 \ ------------------------------\
49127 \ ------------------------------\
49128 $03E8 20_US \ 1- wait 20 ms
49129 $03 TOP_LCD \ 2- send DB5=DB4=1
49130 $CD 20_US \ 3- wait 4,1 ms
49131 $03 TOP_LCD \ 4- send again DB5=DB4=1
49132 $5 20_US \ 5- wait 0,1 ms
49133 $03 TOP_LCD \ 6- send again again DB5=DB4=1
49134 $2 20_US \ wait 40 us = LCD cycle
49135 $02 TOP_LCD \ 7- send DB5=1 DB4=0
49136 $2 20_US \ wait 40 us = LCD cycle
49137 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
49138 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
49139 LCD_Clear \ 10- "LCD_Clear"
49140 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
49141 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
49142 LCD_Clear \ 10- "LCD_Clear"
49143 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
49144 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
49146 ['] CR >BODY IS CR \
49147 ['] EMIT >BODY IS EMIT \
49148 ." RC5toLCD is running. Type STOP to quit"
49149 LIT RECURSE IS WARM \ replace WARM by this START routine
49150 ABORT \ and continue with the next word after WARM...
49151 ; \ ...until interpreter falls in sleep mode within ACCEPT.
49154 CODE STOP \ stops multitasking, must to be used before downloading app
49155 \ restore default action of primary DEFERred word SLEEP, assembly version
49156 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
49157 ADD #4,X \ X = BODY of SLEEP
49158 MOV X,-2(X) \ restore the default background
49161 \ restore default action of primary DEFERred word WARM, FORTH version
49162 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
49164 COLD \ because we want to reset CPU and interrupt vectors
49169 ; downloading RC5toLCD.4th is done
49170 RST_HERE ; this app is protected against <reset>
49178 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
49180 [DEFINED] ASM [IF] \ security test
49184 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
49186 CODE MAX \ n1 n2 -- n3 signed maximum
49187 CMP @PSP,TOS \ n2-n1
49188 S< ?GOTO FW1 \ n2<n1
49194 CODE MIN \ n1 n2 -- n3 signed minimum
49195 CMP @PSP,TOS \ n2-n1
49196 S< ?GOTO BW1 \ n2<n1
49204 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
49205 : U.R \ u n -- display u unsigned in n width (n >= 2)
49207 R> OVER - 0 MAX SPACES TYPE
49212 \ CODE 20_US \ n -- n * 20 us
49213 \ BEGIN \ 3 cycles loop + 6~
49214 \ \ MOV #5,W \ 3 MCLK = 1 MHz
49215 \ \ MOV #23,W \ 3 MCLK = 4 MHz
49216 \ \ MOV #51,W \ 3 MCLK = 8 MHz
49217 \ MOV #104,W \ 3 MCLK = 16 MHz
49218 \ \ MOV #158,W \ 3 MCLK = 24 MHz
49219 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
49224 \ MOV @PSP+,TOS \ 2
49229 CODE 20_US \ n -- n * 20 us
49230 BEGIN \ here we presume that LCD_TIM_IFG = 1...
49232 BIT #1,&LCD_TIM_CTL \ 3
49233 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
49234 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
49236 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
49242 CODE TOP_LCD \ LCD Sample
49243 \ \ if write : %xxxxWWWW --
49244 \ \ if read : -- %0000RRRR
49245 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
49246 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
49247 0= IF \ write LCD bits pattern
49248 AND.B #LCD_DB,TOS \
49249 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
49250 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
49253 THEN \ read LCD bits pattern
49256 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
49257 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
49258 AND.B #LCD_DB,TOS \
49263 CODE LCD_W \ byte -- write byte to LCD
49265 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
49266 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
49267 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
49268 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
49269 COLON \ high level word starts here
49270 TOP_LCD 2 20_US \ write high nibble first
49275 CODE LCD_WrC \ char -- Write Char
49276 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
49281 CODE LCD_WrF \ func -- Write Fonction
49282 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
49288 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
49293 $02 LCD_WrF 100 20_us
49297 [UNDEFINED] OR [IF]
49299 \ https://forth-standard.org/standard/core/OR
49300 \ C OR x1 x2 -- x3 logical OR
49309 : LCD_Entry_set $04 OR LCD_WrF ;
49311 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
49313 : LCD_DSP_Shift $10 OR LCD_WrF ;
49315 : LCD_Fn_Set $20 OR LCD_WrF ;
49317 : LCD_CGRAM_Set $40 OR LCD_WrF ;
49319 : LCD_Goto $80 OR LCD_WrF ;
49321 CODE LCD_R \ -- byte read byte from LCD
49322 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
49323 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
49324 COLON \ starts a FORTH word
49325 TOP_LCD 2 20_us \ -- %0000HHHH
49326 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
49327 HI2LO \ switch from FORTH to assembler
49328 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
49329 ADD.B @PSP+,TOS \ -- %HHHHLLLL
49330 MOV @RSP+,IP \ restore IP saved by COLON
49335 CODE LCD_RdS \ -- status Read Status
49336 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
49341 CODE LCD_RdC \ -- char Read Char
49342 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
49348 \ ******************************\
49349 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
49350 \ ******************************\
49351 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
49352 BIT.B #SW2,&SW2_IN \ test switch S2
49353 0= IF \ case of switch S2 pressed
49354 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
49356 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
49359 BIT.B #SW1,&SW1_IN \ test switch S1 input
49360 0= IF \ case of Switch S1 pressed
49361 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
49363 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
49367 BW1 \ from quit on truncated RC5 message
49368 BW2 \ from repeated RC5 command
49369 BW3 \ from end of RC5_INT
49370 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
49375 \ ******************************\
49376 ASM RC5_INT \ wake up on Px.RC5 change interrupt
49377 \ ******************************\
49378 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
49379 \ ******************************\
49380 \ \ in : SR(9)=old Toggle bit memory (ADD on)
49381 \ \ SMclock = 8|16|24 MHz
49382 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
49383 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
49384 \ \ SR(9)=new Toggle bit memory (ADD on)
49385 \ ******************************\
49386 \ RC5_FirstStartBitHalfCycle: \
49387 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
49388 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
49389 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
49390 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
49391 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
49392 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
49393 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
49394 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
49395 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
49396 MOV #1778,X \ RC5_Period * 1us
49397 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
49398 MOV #14,W \ count of loop
49400 \ ******************************\
49401 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
49402 \ ******************************\ |
49403 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
49404 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
49405 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
49406 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
49407 \ RC5_Compute_3/4_Period: \ |
49408 RRUM #1,X \ X=1/2 cycle |
49411 ADD X,Y \ Y=3/4 cycle
49412 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
49414 \ ******************************\
49415 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
49416 \ ******************************\
49417 BIT.B #RC5,&IR_IN \ C_flag = IR bit
49418 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
49419 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
49420 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
49421 SUB #1,W \ decrement count loop
49422 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
49423 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
49424 0<> WHILE \ ----> out of loop ----+
49425 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
49427 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
49428 CMP Y,X \ 1 | cycle time out of bound ?
49429 U>= IF \ 2 ^ | yes:
49430 BIC #$30,&RC5_TIM_CTL \ | | stop timer
49431 GOTO BW1 \ | | quit on truncated RC5 message
49433 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
49435 REPEAT \ ----> loop back --+ | with X = new RC5_period value
49436 \ ******************************\ |
49437 \ RC5_SampleEndOf: \ <---------------------+
49438 \ ******************************\
49439 BIC #$30,&RC5_TIM_CTL \ stop timer
49440 \ ******************************\
49441 \ RC5_ComputeNewRC5word \
49442 \ ******************************\
49443 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
49444 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
49445 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
49446 \ ******************************\
49447 \ RC5_ComputeC6bit \
49448 \ ******************************\
49449 BIT #BIT14,T \ test /C6 bit in T
49450 0= IF BIS #BIT6,X \ set C6 bit in X
49451 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
49452 \ ******************************\
49453 \ RC5_CommandByteIsDone \ -- BASE RC5_code
49454 \ ******************************\
49455 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
49456 \ ******************************\
49457 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
49458 XOR @RSP,T \ (new XOR old) Toggle bits
49459 BIT #UF10,T \ repeated RC5_command ?
49460 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
49461 XOR #UF10,0(RSP) \ 5 toggle bit memory
49462 \ ******************************\
49463 \ Display IR_RC5 code \ X = RC5 code
49464 \ ******************************\
49466 MOV &BASE,2(PSP) \ save current base
49467 MOV #$10,&BASE \ set hex base
49468 MOV TOS,0(PSP) \ save TOS
49470 LO2HI \ switch from assembler to FORTH
49471 ['] LCD_CLEAR IS CR \ redirects CR
49472 ['] LCD_WrC IS EMIT \ redirects EMIT
49473 CR ." $" 2 U.R \ print IR_RC5 code
49474 ['] CR >BODY IS CR \ restore CR
49475 ['] EMIT >BODY IS EMIT \ restore EMIT
49476 HI2LO \ switch from FORTH to assembler
49477 MOV TOS,&BASE \ restore current BASE
49479 \ ******************************\
49481 \ ******************************\
49485 \ ------------------------------\
49487 \ ------------------------------\
49488 \ ... \ insert here your background task
49491 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
49492 ADD #4,X \ 1 X = BODY of SLEEP
49495 \ ------------------------------\
49499 \ ------------------------------\
49500 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
49501 \ - - \CNTL Counter lentgh \ 00 = 16 bits
49502 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
49503 \ -- \ID input divider \ 10 = /4
49504 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
49505 \ - \TBCLR TimerB Clear
49508 \ -------------------------------\
49509 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
49510 \ -- \CM Capture Mode
49515 \ --- \OUTMOD \ 011 = set/reset
49521 \ -------------------------------\
49523 \ -------------------------------\
49525 \ ------------------------------\
49526 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
49527 \ ------------------------------\
49528 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
49529 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
49530 \ ------------------------------\
49531 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
49532 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
49533 \ ------------------------------\
49534 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
49535 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
49536 \ ------------------------------\
49537 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
49538 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
49539 \ ------------------------------\
49540 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
49541 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
49542 \ ------------------------------\
49543 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
49544 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
49545 \ ------------------------------\
49546 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
49547 \ ------------------------------\
49548 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
49549 \ ------------------------------\
49550 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
49551 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
49552 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
49553 \ ------------------------------\
49554 BIS.B #LCDVo,&LCDVo_DIR \
49555 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
49556 \ ------------------------------\
49557 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
49558 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
49559 \ ------------------------------\
49560 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
49561 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
49562 \ ******************************\
49564 \ ******************************\
49565 BIS.B #RC5,&IR_IE \ enable RC5_Int
49566 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
49567 MOV #RC5_INT,&IR_Vec \ init interrupt vector
49568 \ ******************************\
49569 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
49570 \ ******************************\
49571 \ %01 0001 0100 \ TAxCTL
49572 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
49573 \ -- \ ID divided by 1
49574 \ -- \ MC MODE = up to TAxCCRn
49575 \ - \ TACLR clear timer count
49578 \ ------------------------------\
49579 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
49580 \ ------------------------------\
49582 \ --- \ TAIDEX pre divisor
49583 \ ------------------------------\
49584 \ %0000 0000 0000 0101 \ TAxCCR0
49585 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
49586 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
49587 \ ------------------------------\
49588 \ %0000 0000 0001 0000 \ TAxCCTL0
49589 \ - \ CAP capture/compare mode = compare
49592 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
49593 \ ------------------------------\
49594 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
49595 \ ------------------------------\
49596 \ define LPM mode for ACCEPT \
49597 \ ------------------------------\
49598 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
49599 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
49600 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
49602 \ ------------------------------\
49603 \ redirects to background task \
49604 \ ------------------------------\
49606 MOV #BACKGROUND,2(X) \
49607 \ ------------------------------\
49609 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
49611 \ ------------------------------\
49613 \ ------------------------------\
49614 $03E8 20_US \ 1- wait 20 ms
49615 $03 TOP_LCD \ 2- send DB5=DB4=1
49616 $CD 20_US \ 3- wait 4,1 ms
49617 $03 TOP_LCD \ 4- send again DB5=DB4=1
49618 $5 20_US \ 5- wait 0,1 ms
49619 $03 TOP_LCD \ 6- send again again DB5=DB4=1
49620 $2 20_US \ wait 40 us = LCD cycle
49621 $02 TOP_LCD \ 7- send DB5=1 DB4=0
49622 $2 20_US \ wait 40 us = LCD cycle
49623 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
49624 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
49625 LCD_Clear \ 10- "LCD_Clear"
49626 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
49627 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
49628 LCD_Clear \ 10- "LCD_Clear"
49629 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
49630 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
49632 ['] CR >BODY IS CR \
49633 ['] EMIT >BODY IS EMIT \
49634 ." RC5toLCD is running. Type STOP to quit"
49635 LIT RECURSE IS WARM \ replace WARM by this START routine
49636 ABORT \ and continue with the next word after WARM...
49637 ; \ ...until interpreter falls in sleep mode within ACCEPT.
49640 CODE STOP \ stops multitasking, must to be used before downloading app
49641 \ restore default action of primary DEFERred word SLEEP, assembly version
49642 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
49643 ADD #4,X \ X = BODY of SLEEP
49644 MOV X,-2(X) \ restore the default background
49647 \ restore default action of primary DEFERred word WARM, FORTH version
49648 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
49650 COLD \ because we want to reset CPU and interrupt vectors
49655 ; downloading RC5toLCD.4th is done
49656 RST_HERE ; this app is protected against <reset>
49664 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
49666 [DEFINED] ASM [IF] \ security test
49670 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
49672 CODE MAX \ n1 n2 -- n3 signed maximum
49673 CMP @PSP,TOS \ n2-n1
49674 S< ?GOTO FW1 \ n2<n1
49680 CODE MIN \ n1 n2 -- n3 signed minimum
49681 CMP @PSP,TOS \ n2-n1
49682 S< ?GOTO BW1 \ n2<n1
49690 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
49691 : U.R \ u n -- display u unsigned in n width (n >= 2)
49693 R> OVER - 0 MAX SPACES TYPE
49698 \ CODE 20_US \ n -- n * 20 us
49699 \ BEGIN \ 3 cycles loop + 6~
49700 \ \ MOV #5,W \ 3 MCLK = 1 MHz
49701 \ \ MOV #23,W \ 3 MCLK = 4 MHz
49702 \ \ MOV #51,W \ 3 MCLK = 8 MHz
49703 \ MOV #104,W \ 3 MCLK = 16 MHz
49704 \ \ MOV #158,W \ 3 MCLK = 24 MHz
49705 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
49710 \ MOV @PSP+,TOS \ 2
49715 CODE 20_US \ n -- n * 20 us
49716 BEGIN \ here we presume that LCD_TIM_IFG = 1...
49718 BIT #1,&LCD_TIM_CTL \ 3
49719 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
49720 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
49722 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
49728 CODE TOP_LCD \ LCD Sample
49729 \ \ if write : %xxxxWWWW --
49730 \ \ if read : -- %0000RRRR
49731 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
49732 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
49733 0= IF \ write LCD bits pattern
49734 AND.B #LCD_DB,TOS \
49735 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
49736 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
49739 THEN \ read LCD bits pattern
49742 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
49743 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
49744 AND.B #LCD_DB,TOS \
49749 CODE LCD_W \ byte -- write byte to LCD
49751 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
49752 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
49753 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
49754 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
49755 COLON \ high level word starts here
49756 TOP_LCD 2 20_US \ write high nibble first
49761 CODE LCD_WrC \ char -- Write Char
49762 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
49767 CODE LCD_WrF \ func -- Write Fonction
49768 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
49774 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
49779 $02 LCD_WrF 100 20_us
49783 [UNDEFINED] OR [IF]
49785 \ https://forth-standard.org/standard/core/OR
49786 \ C OR x1 x2 -- x3 logical OR
49795 : LCD_Entry_set $04 OR LCD_WrF ;
49797 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
49799 : LCD_DSP_Shift $10 OR LCD_WrF ;
49801 : LCD_Fn_Set $20 OR LCD_WrF ;
49803 : LCD_CGRAM_Set $40 OR LCD_WrF ;
49805 : LCD_Goto $80 OR LCD_WrF ;
49807 CODE LCD_R \ -- byte read byte from LCD
49808 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
49809 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
49810 COLON \ starts a FORTH word
49811 TOP_LCD 2 20_us \ -- %0000HHHH
49812 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
49813 HI2LO \ switch from FORTH to assembler
49814 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
49815 ADD.B @PSP+,TOS \ -- %HHHHLLLL
49816 MOV @RSP+,IP \ restore IP saved by COLON
49821 CODE LCD_RdS \ -- status Read Status
49822 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
49827 CODE LCD_RdC \ -- char Read Char
49828 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
49834 \ ******************************\
49835 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
49836 \ ******************************\
49837 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
49838 BIT.B #SW2,&SW2_IN \ test switch S2
49839 0= IF \ case of switch S2 pressed
49840 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
49842 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
49845 BIT.B #SW1,&SW1_IN \ test switch S1 input
49846 0= IF \ case of Switch S1 pressed
49847 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
49849 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
49853 BW1 \ from quit on truncated RC5 message
49854 BW2 \ from repeated RC5 command
49855 BW3 \ from end of RC5_INT
49856 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
49861 \ ******************************\
49862 ASM RC5_INT \ wake up on Px.RC5 change interrupt
49863 \ ******************************\
49864 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
49865 \ ******************************\
49866 \ \ in : SR(9)=old Toggle bit memory (ADD on)
49867 \ \ SMclock = 8|16|24 MHz
49868 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
49869 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
49870 \ \ SR(9)=new Toggle bit memory (ADD on)
49871 \ ******************************\
49872 \ RC5_FirstStartBitHalfCycle: \
49873 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
49874 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
49875 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
49876 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
49877 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
49878 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
49879 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
49880 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
49881 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
49882 MOV #1778,X \ RC5_Period * 1us
49883 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
49884 MOV #14,W \ count of loop
49886 \ ******************************\
49887 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
49888 \ ******************************\ |
49889 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
49890 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
49891 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
49892 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
49893 \ RC5_Compute_3/4_Period: \ |
49894 RRUM #1,X \ X=1/2 cycle |
49897 ADD X,Y \ Y=3/4 cycle
49898 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
49900 \ ******************************\
49901 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
49902 \ ******************************\
49903 BIT.B #RC5,&IR_IN \ C_flag = IR bit
49904 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
49905 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
49906 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
49907 SUB #1,W \ decrement count loop
49908 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
49909 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
49910 0<> WHILE \ ----> out of loop ----+
49911 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
49913 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
49914 CMP Y,X \ 1 | cycle time out of bound ?
49915 U>= IF \ 2 ^ | yes:
49916 BIC #$30,&RC5_TIM_CTL \ | | stop timer
49917 GOTO BW1 \ | | quit on truncated RC5 message
49919 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
49921 REPEAT \ ----> loop back --+ | with X = new RC5_period value
49922 \ ******************************\ |
49923 \ RC5_SampleEndOf: \ <---------------------+
49924 \ ******************************\
49925 BIC #$30,&RC5_TIM_CTL \ stop timer
49926 \ ******************************\
49927 \ RC5_ComputeNewRC5word \
49928 \ ******************************\
49929 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
49930 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
49931 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
49932 \ ******************************\
49933 \ RC5_ComputeC6bit \
49934 \ ******************************\
49935 BIT #BIT14,T \ test /C6 bit in T
49936 0= IF BIS #BIT6,X \ set C6 bit in X
49937 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
49938 \ ******************************\
49939 \ RC5_CommandByteIsDone \ -- BASE RC5_code
49940 \ ******************************\
49941 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
49942 \ ******************************\
49943 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
49944 XOR @RSP,T \ (new XOR old) Toggle bits
49945 BIT #UF10,T \ repeated RC5_command ?
49946 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
49947 XOR #UF10,0(RSP) \ 5 toggle bit memory
49948 \ ******************************\
49949 \ Display IR_RC5 code \ X = RC5 code
49950 \ ******************************\
49952 MOV &BASE,2(PSP) \ save current base
49953 MOV #$10,&BASE \ set hex base
49954 MOV TOS,0(PSP) \ save TOS
49956 LO2HI \ switch from assembler to FORTH
49957 ['] LCD_CLEAR IS CR \ redirects CR
49958 ['] LCD_WrC IS EMIT \ redirects EMIT
49959 CR ." $" 2 U.R \ print IR_RC5 code
49960 ['] CR >BODY IS CR \ restore CR
49961 ['] EMIT >BODY IS EMIT \ restore EMIT
49962 HI2LO \ switch from FORTH to assembler
49963 MOV TOS,&BASE \ restore current BASE
49965 \ ******************************\
49967 \ ******************************\
49971 \ ------------------------------\
49973 \ ------------------------------\
49974 \ ... \ insert here your background task
49977 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
49978 ADD #4,X \ 1 X = BODY of SLEEP
49981 \ ------------------------------\
49985 \ ------------------------------\
49986 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
49987 \ - - \CNTL Counter lentgh \ 00 = 16 bits
49988 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
49989 \ -- \ID input divider \ 10 = /4
49990 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
49991 \ - \TBCLR TimerB Clear
49994 \ -------------------------------\
49995 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
49996 \ -- \CM Capture Mode
50001 \ --- \OUTMOD \ 011 = set/reset
50007 \ -------------------------------\
50009 \ -------------------------------\
50011 \ ------------------------------\
50012 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
50013 \ ------------------------------\
50014 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
50015 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
50016 \ ------------------------------\
50017 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
50018 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
50019 \ ------------------------------\
50020 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
50021 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
50022 \ ------------------------------\
50023 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
50024 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
50025 \ ------------------------------\
50026 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
50027 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
50028 \ ------------------------------\
50029 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
50030 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
50031 \ ------------------------------\
50032 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
50033 \ ------------------------------\
50034 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
50035 \ ------------------------------\
50036 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
50037 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
50038 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
50039 \ ------------------------------\
50040 BIS.B #LCDVo,&LCDVo_DIR \
50041 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
50042 \ ------------------------------\
50043 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
50044 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
50045 \ ------------------------------\
50046 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
50047 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
50048 \ ******************************\
50050 \ ******************************\
50051 BIS.B #RC5,&IR_IE \ enable RC5_Int
50052 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
50053 MOV #RC5_INT,&IR_Vec \ init interrupt vector
50054 \ ******************************\
50055 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
50056 \ ******************************\
50057 \ %01 0001 0100 \ TAxCTL
50058 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
50059 \ -- \ ID divided by 1
50060 \ -- \ MC MODE = up to TAxCCRn
50061 \ - \ TACLR clear timer count
50064 \ ------------------------------\
50065 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
50066 \ ------------------------------\
50068 \ --- \ TAIDEX pre divisor
50069 \ ------------------------------\
50070 \ %0000 0000 0000 0101 \ TAxCCR0
50071 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
50072 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
50073 \ ------------------------------\
50074 \ %0000 0000 0001 0000 \ TAxCCTL0
50075 \ - \ CAP capture/compare mode = compare
50078 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
50079 \ ------------------------------\
50080 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
50081 \ ------------------------------\
50082 \ define LPM mode for ACCEPT \
50083 \ ------------------------------\
50084 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
50085 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
50086 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
50088 \ ------------------------------\
50089 \ redirects to background task \
50090 \ ------------------------------\
50092 MOV #BACKGROUND,2(X) \
50093 \ ------------------------------\
50095 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
50097 \ ------------------------------\
50099 \ ------------------------------\
50100 $03E8 20_US \ 1- wait 20 ms
50101 $03 TOP_LCD \ 2- send DB5=DB4=1
50102 $CD 20_US \ 3- wait 4,1 ms
50103 $03 TOP_LCD \ 4- send again DB5=DB4=1
50104 $5 20_US \ 5- wait 0,1 ms
50105 $03 TOP_LCD \ 6- send again again DB5=DB4=1
50106 $2 20_US \ wait 40 us = LCD cycle
50107 $02 TOP_LCD \ 7- send DB5=1 DB4=0
50108 $2 20_US \ wait 40 us = LCD cycle
50109 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
50110 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
50111 LCD_Clear \ 10- "LCD_Clear"
50112 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
50113 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
50114 LCD_Clear \ 10- "LCD_Clear"
50115 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
50116 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
50118 ['] CR >BODY IS CR \
50119 ['] EMIT >BODY IS EMIT \
50120 ." RC5toLCD is running. Type STOP to quit"
50121 LIT RECURSE IS WARM \ replace WARM by this START routine
50122 ABORT \ and continue with the next word after WARM...
50123 ; \ ...until interpreter falls in sleep mode within ACCEPT.
50126 CODE STOP \ stops multitasking, must to be used before downloading app
50127 \ restore default action of primary DEFERred word SLEEP, assembly version
50128 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
50129 ADD #4,X \ X = BODY of SLEEP
50130 MOV X,-2(X) \ restore the default background
50133 \ restore default action of primary DEFERred word WARM, FORTH version
50134 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
50136 COLD \ because we want to reset CPU and interrupt vectors
50141 ; downloading RC5toLCD.4th is done
50142 RST_HERE ; this app is protected against <reset>
50150 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
50152 [DEFINED] ASM [IF] \ security test
50156 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
50158 CODE MAX \ n1 n2 -- n3 signed maximum
50159 CMP @PSP,TOS \ n2-n1
50160 S< ?GOTO FW1 \ n2<n1
50166 CODE MIN \ n1 n2 -- n3 signed minimum
50167 CMP @PSP,TOS \ n2-n1
50168 S< ?GOTO BW1 \ n2<n1
50176 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
50177 : U.R \ u n -- display u unsigned in n width (n >= 2)
50179 R> OVER - 0 MAX SPACES TYPE
50184 \ CODE 20_US \ n -- n * 20 us
50185 \ BEGIN \ 3 cycles loop + 6~
50186 \ \ MOV #5,W \ 3 MCLK = 1 MHz
50187 \ \ MOV #23,W \ 3 MCLK = 4 MHz
50188 \ \ MOV #51,W \ 3 MCLK = 8 MHz
50189 \ MOV #104,W \ 3 MCLK = 16 MHz
50190 \ \ MOV #158,W \ 3 MCLK = 24 MHz
50191 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
50196 \ MOV @PSP+,TOS \ 2
50201 CODE 20_US \ n -- n * 20 us
50202 BEGIN \ here we presume that LCD_TIM_IFG = 1...
50204 BIT #1,&LCD_TIM_CTL \ 3
50205 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
50206 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
50208 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
50214 CODE TOP_LCD \ LCD Sample
50215 \ \ if write : %xxxxWWWW --
50216 \ \ if read : -- %0000RRRR
50217 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
50218 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
50219 0= IF \ write LCD bits pattern
50220 AND.B #LCD_DB,TOS \
50221 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
50222 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
50225 THEN \ read LCD bits pattern
50228 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
50229 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
50230 AND.B #LCD_DB,TOS \
50235 CODE LCD_W \ byte -- write byte to LCD
50237 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
50238 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
50239 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
50240 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
50241 COLON \ high level word starts here
50242 TOP_LCD 2 20_US \ write high nibble first
50247 CODE LCD_WrC \ char -- Write Char
50248 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
50253 CODE LCD_WrF \ func -- Write Fonction
50254 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
50260 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
50265 $02 LCD_WrF 100 20_us
50269 [UNDEFINED] OR [IF]
50271 \ https://forth-standard.org/standard/core/OR
50272 \ C OR x1 x2 -- x3 logical OR
50281 : LCD_Entry_set $04 OR LCD_WrF ;
50283 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
50285 : LCD_DSP_Shift $10 OR LCD_WrF ;
50287 : LCD_Fn_Set $20 OR LCD_WrF ;
50289 : LCD_CGRAM_Set $40 OR LCD_WrF ;
50291 : LCD_Goto $80 OR LCD_WrF ;
50293 CODE LCD_R \ -- byte read byte from LCD
50294 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
50295 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
50296 COLON \ starts a FORTH word
50297 TOP_LCD 2 20_us \ -- %0000HHHH
50298 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
50299 HI2LO \ switch from FORTH to assembler
50300 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
50301 ADD.B @PSP+,TOS \ -- %HHHHLLLL
50302 MOV @RSP+,IP \ restore IP saved by COLON
50307 CODE LCD_RdS \ -- status Read Status
50308 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
50313 CODE LCD_RdC \ -- char Read Char
50314 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
50320 \ ******************************\
50321 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
50322 \ ******************************\
50323 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
50324 BIT.B #SW2,&SW2_IN \ test switch S2
50325 0= IF \ case of switch S2 pressed
50326 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
50328 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
50331 BIT.B #SW1,&SW1_IN \ test switch S1 input
50332 0= IF \ case of Switch S1 pressed
50333 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
50335 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
50339 BW1 \ from quit on truncated RC5 message
50340 BW2 \ from repeated RC5 command
50341 BW3 \ from end of RC5_INT
50342 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
50347 \ ******************************\
50348 ASM RC5_INT \ wake up on Px.RC5 change interrupt
50349 \ ******************************\
50350 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
50351 \ ******************************\
50352 \ \ in : SR(9)=old Toggle bit memory (ADD on)
50353 \ \ SMclock = 8|16|24 MHz
50354 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
50355 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
50356 \ \ SR(9)=new Toggle bit memory (ADD on)
50357 \ ******************************\
50358 \ RC5_FirstStartBitHalfCycle: \
50359 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
50360 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
50361 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
50362 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
50363 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
50364 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
50365 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
50366 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
50367 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
50368 MOV #1778,X \ RC5_Period * 1us
50369 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
50370 MOV #14,W \ count of loop
50372 \ ******************************\
50373 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
50374 \ ******************************\ |
50375 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
50376 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
50377 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
50378 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
50379 \ RC5_Compute_3/4_Period: \ |
50380 RRUM #1,X \ X=1/2 cycle |
50383 ADD X,Y \ Y=3/4 cycle
50384 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
50386 \ ******************************\
50387 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
50388 \ ******************************\
50389 BIT.B #RC5,&IR_IN \ C_flag = IR bit
50390 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
50391 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
50392 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
50393 SUB #1,W \ decrement count loop
50394 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
50395 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
50396 0<> WHILE \ ----> out of loop ----+
50397 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
50399 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
50400 CMP Y,X \ 1 | cycle time out of bound ?
50401 U>= IF \ 2 ^ | yes:
50402 BIC #$30,&RC5_TIM_CTL \ | | stop timer
50403 GOTO BW1 \ | | quit on truncated RC5 message
50405 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
50407 REPEAT \ ----> loop back --+ | with X = new RC5_period value
50408 \ ******************************\ |
50409 \ RC5_SampleEndOf: \ <---------------------+
50410 \ ******************************\
50411 BIC #$30,&RC5_TIM_CTL \ stop timer
50412 \ ******************************\
50413 \ RC5_ComputeNewRC5word \
50414 \ ******************************\
50415 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
50416 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
50417 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
50418 \ ******************************\
50419 \ RC5_ComputeC6bit \
50420 \ ******************************\
50421 BIT #BIT14,T \ test /C6 bit in T
50422 0= IF BIS #BIT6,X \ set C6 bit in X
50423 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
50424 \ ******************************\
50425 \ RC5_CommandByteIsDone \ -- BASE RC5_code
50426 \ ******************************\
50427 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
50428 \ ******************************\
50429 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
50430 XOR @RSP,T \ (new XOR old) Toggle bits
50431 BIT #UF10,T \ repeated RC5_command ?
50432 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
50433 XOR #UF10,0(RSP) \ 5 toggle bit memory
50434 \ ******************************\
50435 \ Display IR_RC5 code \ X = RC5 code
50436 \ ******************************\
50438 MOV &BASE,2(PSP) \ save current base
50439 MOV #$10,&BASE \ set hex base
50440 MOV TOS,0(PSP) \ save TOS
50442 LO2HI \ switch from assembler to FORTH
50443 ['] LCD_CLEAR IS CR \ redirects CR
50444 ['] LCD_WrC IS EMIT \ redirects EMIT
50445 CR ." $" 2 U.R \ print IR_RC5 code
50446 ['] CR >BODY IS CR \ restore CR
50447 ['] EMIT >BODY IS EMIT \ restore EMIT
50448 HI2LO \ switch from FORTH to assembler
50449 MOV TOS,&BASE \ restore current BASE
50451 \ ******************************\
50453 \ ******************************\
50457 \ ------------------------------\
50459 \ ------------------------------\
50460 \ ... \ insert here your background task
50463 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
50464 ADD #4,X \ 1 X = BODY of SLEEP
50467 \ ------------------------------\
50471 \ ------------------------------\
50472 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
50473 \ - - \CNTL Counter lentgh \ 00 = 16 bits
50474 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
50475 \ -- \ID input divider \ 10 = /4
50476 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
50477 \ - \TBCLR TimerB Clear
50480 \ -------------------------------\
50481 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
50482 \ -- \CM Capture Mode
50487 \ --- \OUTMOD \ 011 = set/reset
50493 \ -------------------------------\
50495 \ -------------------------------\
50497 \ ------------------------------\
50498 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
50499 \ ------------------------------\
50500 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
50501 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
50502 \ ------------------------------\
50503 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
50504 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
50505 \ ------------------------------\
50506 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
50507 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
50508 \ ------------------------------\
50509 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
50510 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
50511 \ ------------------------------\
50512 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
50513 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
50514 \ ------------------------------\
50515 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
50516 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
50517 \ ------------------------------\
50518 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
50519 \ ------------------------------\
50520 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
50521 \ ------------------------------\
50522 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
50523 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
50524 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
50525 \ ------------------------------\
50526 BIS.B #LCDVo,&LCDVo_DIR \
50527 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
50528 \ ------------------------------\
50529 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
50530 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
50531 \ ------------------------------\
50532 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
50533 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
50534 \ ******************************\
50536 \ ******************************\
50537 BIS.B #RC5,&IR_IE \ enable RC5_Int
50538 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
50539 MOV #RC5_INT,&IR_Vec \ init interrupt vector
50540 \ ******************************\
50541 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
50542 \ ******************************\
50543 \ %01 0001 0100 \ TAxCTL
50544 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
50545 \ -- \ ID divided by 1
50546 \ -- \ MC MODE = up to TAxCCRn
50547 \ - \ TACLR clear timer count
50550 \ ------------------------------\
50551 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
50552 \ ------------------------------\
50554 \ --- \ TAIDEX pre divisor
50555 \ ------------------------------\
50556 \ %0000 0000 0000 0101 \ TAxCCR0
50557 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
50558 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
50559 \ ------------------------------\
50560 \ %0000 0000 0001 0000 \ TAxCCTL0
50561 \ - \ CAP capture/compare mode = compare
50564 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
50565 \ ------------------------------\
50566 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
50567 \ ------------------------------\
50568 \ define LPM mode for ACCEPT \
50569 \ ------------------------------\
50570 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
50571 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
50572 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
50574 \ ------------------------------\
50575 \ redirects to background task \
50576 \ ------------------------------\
50578 MOV #BACKGROUND,2(X) \
50579 \ ------------------------------\
50581 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
50583 \ ------------------------------\
50585 \ ------------------------------\
50586 $03E8 20_US \ 1- wait 20 ms
50587 $03 TOP_LCD \ 2- send DB5=DB4=1
50588 $CD 20_US \ 3- wait 4,1 ms
50589 $03 TOP_LCD \ 4- send again DB5=DB4=1
50590 $5 20_US \ 5- wait 0,1 ms
50591 $03 TOP_LCD \ 6- send again again DB5=DB4=1
50592 $2 20_US \ wait 40 us = LCD cycle
50593 $02 TOP_LCD \ 7- send DB5=1 DB4=0
50594 $2 20_US \ wait 40 us = LCD cycle
50595 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
50596 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
50597 LCD_Clear \ 10- "LCD_Clear"
50598 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
50599 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
50600 LCD_Clear \ 10- "LCD_Clear"
50601 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
50602 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
50604 ['] CR >BODY IS CR \
50605 ['] EMIT >BODY IS EMIT \
50606 ." RC5toLCD is running. Type STOP to quit"
50607 LIT RECURSE IS WARM \ replace WARM by this START routine
50608 ABORT \ and continue with the next word after WARM...
50609 ; \ ...until interpreter falls in sleep mode within ACCEPT.
50612 CODE STOP \ stops multitasking, must to be used before downloading app
50613 \ restore default action of primary DEFERred word SLEEP, assembly version
50614 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
50615 ADD #4,X \ X = BODY of SLEEP
50616 MOV X,-2(X) \ restore the default background
50619 \ restore default action of primary DEFERred word WARM, FORTH version
50620 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
50622 COLD \ because we want to reset CPU and interrupt vectors
50627 ; downloading RC5toLCD.4th is done
50628 RST_HERE ; this app is protected against <reset>
50636 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
50638 [DEFINED] ASM [IF] \ security test
50642 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
50644 CODE MAX \ n1 n2 -- n3 signed maximum
50645 CMP @PSP,TOS \ n2-n1
50646 S< ?GOTO FW1 \ n2<n1
50652 CODE MIN \ n1 n2 -- n3 signed minimum
50653 CMP @PSP,TOS \ n2-n1
50654 S< ?GOTO BW1 \ n2<n1
50662 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
50663 : U.R \ u n -- display u unsigned in n width (n >= 2)
50665 R> OVER - 0 MAX SPACES TYPE
50670 \ CODE 20_US \ n -- n * 20 us
50671 \ BEGIN \ 3 cycles loop + 6~
50672 \ \ MOV #5,W \ 3 MCLK = 1 MHz
50673 \ \ MOV #23,W \ 3 MCLK = 4 MHz
50674 \ \ MOV #51,W \ 3 MCLK = 8 MHz
50675 \ MOV #104,W \ 3 MCLK = 16 MHz
50676 \ \ MOV #158,W \ 3 MCLK = 24 MHz
50677 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
50682 \ MOV @PSP+,TOS \ 2
50687 CODE 20_US \ n -- n * 20 us
50688 BEGIN \ here we presume that LCD_TIM_IFG = 1...
50690 BIT #1,&LCD_TIM_CTL \ 3
50691 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
50692 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
50694 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
50700 CODE TOP_LCD \ LCD Sample
50701 \ \ if write : %xxxxWWWW --
50702 \ \ if read : -- %0000RRRR
50703 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
50704 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
50705 0= IF \ write LCD bits pattern
50706 AND.B #LCD_DB,TOS \
50707 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
50708 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
50711 THEN \ read LCD bits pattern
50714 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
50715 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
50716 AND.B #LCD_DB,TOS \
50721 CODE LCD_W \ byte -- write byte to LCD
50723 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
50724 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
50725 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
50726 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
50727 COLON \ high level word starts here
50728 TOP_LCD 2 20_US \ write high nibble first
50733 CODE LCD_WrC \ char -- Write Char
50734 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
50739 CODE LCD_WrF \ func -- Write Fonction
50740 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
50746 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
50751 $02 LCD_WrF 100 20_us
50755 [UNDEFINED] OR [IF]
50757 \ https://forth-standard.org/standard/core/OR
50758 \ C OR x1 x2 -- x3 logical OR
50767 : LCD_Entry_set $04 OR LCD_WrF ;
50769 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
50771 : LCD_DSP_Shift $10 OR LCD_WrF ;
50773 : LCD_Fn_Set $20 OR LCD_WrF ;
50775 : LCD_CGRAM_Set $40 OR LCD_WrF ;
50777 : LCD_Goto $80 OR LCD_WrF ;
50779 CODE LCD_R \ -- byte read byte from LCD
50780 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
50781 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
50782 COLON \ starts a FORTH word
50783 TOP_LCD 2 20_us \ -- %0000HHHH
50784 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
50785 HI2LO \ switch from FORTH to assembler
50786 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
50787 ADD.B @PSP+,TOS \ -- %HHHHLLLL
50788 MOV @RSP+,IP \ restore IP saved by COLON
50793 CODE LCD_RdS \ -- status Read Status
50794 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
50799 CODE LCD_RdC \ -- char Read Char
50800 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
50806 \ ******************************\
50807 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
50808 \ ******************************\
50809 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
50810 BIT.B #SW2,&SW2_IN \ test switch S2
50811 0= IF \ case of switch S2 pressed
50812 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
50814 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
50817 BIT.B #SW1,&SW1_IN \ test switch S1 input
50818 0= IF \ case of Switch S1 pressed
50819 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
50821 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
50825 BW1 \ from quit on truncated RC5 message
50826 BW2 \ from repeated RC5 command
50827 BW3 \ from end of RC5_INT
50828 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
50833 \ ******************************\
50834 ASM RC5_INT \ wake up on Px.RC5 change interrupt
50835 \ ******************************\
50836 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
50837 \ ******************************\
50838 \ \ in : SR(9)=old Toggle bit memory (ADD on)
50839 \ \ SMclock = 8|16|24 MHz
50840 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
50841 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
50842 \ \ SR(9)=new Toggle bit memory (ADD on)
50843 \ ******************************\
50844 \ RC5_FirstStartBitHalfCycle: \
50845 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
50846 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
50847 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
50848 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
50849 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
50850 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
50851 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
50852 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
50853 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
50854 MOV #1778,X \ RC5_Period * 1us
50855 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
50856 MOV #14,W \ count of loop
50858 \ ******************************\
50859 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
50860 \ ******************************\ |
50861 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
50862 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
50863 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
50864 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
50865 \ RC5_Compute_3/4_Period: \ |
50866 RRUM #1,X \ X=1/2 cycle |
50869 ADD X,Y \ Y=3/4 cycle
50870 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
50872 \ ******************************\
50873 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
50874 \ ******************************\
50875 BIT.B #RC5,&IR_IN \ C_flag = IR bit
50876 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
50877 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
50878 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
50879 SUB #1,W \ decrement count loop
50880 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
50881 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
50882 0<> WHILE \ ----> out of loop ----+
50883 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
50885 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
50886 CMP Y,X \ 1 | cycle time out of bound ?
50887 U>= IF \ 2 ^ | yes:
50888 BIC #$30,&RC5_TIM_CTL \ | | stop timer
50889 GOTO BW1 \ | | quit on truncated RC5 message
50891 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
50893 REPEAT \ ----> loop back --+ | with X = new RC5_period value
50894 \ ******************************\ |
50895 \ RC5_SampleEndOf: \ <---------------------+
50896 \ ******************************\
50897 BIC #$30,&RC5_TIM_CTL \ stop timer
50898 \ ******************************\
50899 \ RC5_ComputeNewRC5word \
50900 \ ******************************\
50901 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
50902 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
50903 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
50904 \ ******************************\
50905 \ RC5_ComputeC6bit \
50906 \ ******************************\
50907 BIT #BIT14,T \ test /C6 bit in T
50908 0= IF BIS #BIT6,X \ set C6 bit in X
50909 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
50910 \ ******************************\
50911 \ RC5_CommandByteIsDone \ -- BASE RC5_code
50912 \ ******************************\
50913 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
50914 \ ******************************\
50915 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
50916 XOR @RSP,T \ (new XOR old) Toggle bits
50917 BIT #UF10,T \ repeated RC5_command ?
50918 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
50919 XOR #UF10,0(RSP) \ 5 toggle bit memory
50920 \ ******************************\
50921 \ Display IR_RC5 code \ X = RC5 code
50922 \ ******************************\
50924 MOV &BASE,2(PSP) \ save current base
50925 MOV #$10,&BASE \ set hex base
50926 MOV TOS,0(PSP) \ save TOS
50928 LO2HI \ switch from assembler to FORTH
50929 ['] LCD_CLEAR IS CR \ redirects CR
50930 ['] LCD_WrC IS EMIT \ redirects EMIT
50931 CR ." $" 2 U.R \ print IR_RC5 code
50932 ['] CR >BODY IS CR \ restore CR
50933 ['] EMIT >BODY IS EMIT \ restore EMIT
50934 HI2LO \ switch from FORTH to assembler
50935 MOV TOS,&BASE \ restore current BASE
50937 \ ******************************\
50939 \ ******************************\
50943 \ ------------------------------\
50945 \ ------------------------------\
50946 \ ... \ insert here your background task
50949 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
50950 ADD #4,X \ 1 X = BODY of SLEEP
50953 \ ------------------------------\
50957 \ ------------------------------\
50958 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
50959 \ - - \CNTL Counter lentgh \ 00 = 16 bits
50960 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
50961 \ -- \ID input divider \ 10 = /4
50962 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
50963 \ - \TBCLR TimerB Clear
50966 \ -------------------------------\
50967 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
50968 \ -- \CM Capture Mode
50973 \ --- \OUTMOD \ 011 = set/reset
50979 \ -------------------------------\
50981 \ -------------------------------\
50983 \ ------------------------------\
50984 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
50985 \ ------------------------------\
50986 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
50987 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
50988 \ ------------------------------\
50989 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
50990 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
50991 \ ------------------------------\
50992 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
50993 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
50994 \ ------------------------------\
50995 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
50996 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
50997 \ ------------------------------\
50998 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
50999 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
51000 \ ------------------------------\
51001 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
51002 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
51003 \ ------------------------------\
51004 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
51005 \ ------------------------------\
51006 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
51007 \ ------------------------------\
51008 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
51009 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
51010 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
51011 \ ------------------------------\
51012 BIS.B #LCDVo,&LCDVo_DIR \
51013 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
51014 \ ------------------------------\
51015 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
51016 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
51017 \ ------------------------------\
51018 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
51019 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
51020 \ ******************************\
51022 \ ******************************\
51023 BIS.B #RC5,&IR_IE \ enable RC5_Int
51024 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
51025 MOV #RC5_INT,&IR_Vec \ init interrupt vector
51026 \ ******************************\
51027 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
51028 \ ******************************\
51029 \ %01 0001 0100 \ TAxCTL
51030 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
51031 \ -- \ ID divided by 1
51032 \ -- \ MC MODE = up to TAxCCRn
51033 \ - \ TACLR clear timer count
51036 \ ------------------------------\
51037 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
51038 \ ------------------------------\
51040 \ --- \ TAIDEX pre divisor
51041 \ ------------------------------\
51042 \ %0000 0000 0000 0101 \ TAxCCR0
51043 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
51044 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
51045 \ ------------------------------\
51046 \ %0000 0000 0001 0000 \ TAxCCTL0
51047 \ - \ CAP capture/compare mode = compare
51050 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
51051 \ ------------------------------\
51052 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
51053 \ ------------------------------\
51054 \ define LPM mode for ACCEPT \
51055 \ ------------------------------\
51056 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
51057 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
51058 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
51060 \ ------------------------------\
51061 \ redirects to background task \
51062 \ ------------------------------\
51064 MOV #BACKGROUND,2(X) \
51065 \ ------------------------------\
51067 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
51069 \ ------------------------------\
51071 \ ------------------------------\
51072 $03E8 20_US \ 1- wait 20 ms
51073 $03 TOP_LCD \ 2- send DB5=DB4=1
51074 $CD 20_US \ 3- wait 4,1 ms
51075 $03 TOP_LCD \ 4- send again DB5=DB4=1
51076 $5 20_US \ 5- wait 0,1 ms
51077 $03 TOP_LCD \ 6- send again again DB5=DB4=1
51078 $2 20_US \ wait 40 us = LCD cycle
51079 $02 TOP_LCD \ 7- send DB5=1 DB4=0
51080 $2 20_US \ wait 40 us = LCD cycle
51081 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
51082 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
51083 LCD_Clear \ 10- "LCD_Clear"
51084 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
51085 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
51086 LCD_Clear \ 10- "LCD_Clear"
51087 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
51088 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
51090 ['] CR >BODY IS CR \
51091 ['] EMIT >BODY IS EMIT \
51092 ." RC5toLCD is running. Type STOP to quit"
51093 LIT RECURSE IS WARM \ replace WARM by this START routine
51094 ABORT \ and continue with the next word after WARM...
51095 ; \ ...until interpreter falls in sleep mode within ACCEPT.
51098 CODE STOP \ stops multitasking, must to be used before downloading app
51099 \ restore default action of primary DEFERred word SLEEP, assembly version
51100 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
51101 ADD #4,X \ X = BODY of SLEEP
51102 MOV X,-2(X) \ restore the default background
51105 \ restore default action of primary DEFERred word WARM, FORTH version
51106 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
51108 COLD \ because we want to reset CPU and interrupt vectors
51113 ; downloading RC5toLCD.4th is done
51114 RST_HERE ; this app is protected against <reset>
51122 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
51124 [DEFINED] ASM [IF] \ security test
51128 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
51130 CODE MAX \ n1 n2 -- n3 signed maximum
51131 CMP @PSP,TOS \ n2-n1
51132 S< ?GOTO FW1 \ n2<n1
51138 CODE MIN \ n1 n2 -- n3 signed minimum
51139 CMP @PSP,TOS \ n2-n1
51140 S< ?GOTO BW1 \ n2<n1
51148 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
51149 : U.R \ u n -- display u unsigned in n width (n >= 2)
51151 R> OVER - 0 MAX SPACES TYPE
51156 \ CODE 20_US \ n -- n * 20 us
51157 \ BEGIN \ 3 cycles loop + 6~
51158 \ \ MOV #5,W \ 3 MCLK = 1 MHz
51159 \ \ MOV #23,W \ 3 MCLK = 4 MHz
51160 \ \ MOV #51,W \ 3 MCLK = 8 MHz
51161 \ MOV #104,W \ 3 MCLK = 16 MHz
51162 \ \ MOV #158,W \ 3 MCLK = 24 MHz
51163 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
51168 \ MOV @PSP+,TOS \ 2
51173 CODE 20_US \ n -- n * 20 us
51174 BEGIN \ here we presume that LCD_TIM_IFG = 1...
51176 BIT #1,&LCD_TIM_CTL \ 3
51177 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
51178 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
51180 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
51186 CODE TOP_LCD \ LCD Sample
51187 \ \ if write : %xxxxWWWW --
51188 \ \ if read : -- %0000RRRR
51189 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
51190 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
51191 0= IF \ write LCD bits pattern
51192 AND.B #LCD_DB,TOS \
51193 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
51194 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
51197 THEN \ read LCD bits pattern
51200 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
51201 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
51202 AND.B #LCD_DB,TOS \
51207 CODE LCD_W \ byte -- write byte to LCD
51209 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
51210 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
51211 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
51212 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
51213 COLON \ high level word starts here
51214 TOP_LCD 2 20_US \ write high nibble first
51219 CODE LCD_WrC \ char -- Write Char
51220 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
51225 CODE LCD_WrF \ func -- Write Fonction
51226 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
51232 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
51237 $02 LCD_WrF 100 20_us
51241 [UNDEFINED] OR [IF]
51243 \ https://forth-standard.org/standard/core/OR
51244 \ C OR x1 x2 -- x3 logical OR
51253 : LCD_Entry_set $04 OR LCD_WrF ;
51255 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
51257 : LCD_DSP_Shift $10 OR LCD_WrF ;
51259 : LCD_Fn_Set $20 OR LCD_WrF ;
51261 : LCD_CGRAM_Set $40 OR LCD_WrF ;
51263 : LCD_Goto $80 OR LCD_WrF ;
51265 CODE LCD_R \ -- byte read byte from LCD
51266 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
51267 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
51268 COLON \ starts a FORTH word
51269 TOP_LCD 2 20_us \ -- %0000HHHH
51270 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
51271 HI2LO \ switch from FORTH to assembler
51272 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
51273 ADD.B @PSP+,TOS \ -- %HHHHLLLL
51274 MOV @RSP+,IP \ restore IP saved by COLON
51279 CODE LCD_RdS \ -- status Read Status
51280 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
51285 CODE LCD_RdC \ -- char Read Char
51286 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
51292 \ ******************************\
51293 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
51294 \ ******************************\
51295 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
51296 BIT.B #SW2,&SW2_IN \ test switch S2
51297 0= IF \ case of switch S2 pressed
51298 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
51300 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
51303 BIT.B #SW1,&SW1_IN \ test switch S1 input
51304 0= IF \ case of Switch S1 pressed
51305 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
51307 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
51311 BW1 \ from quit on truncated RC5 message
51312 BW2 \ from repeated RC5 command
51313 BW3 \ from end of RC5_INT
51314 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
51319 \ ******************************\
51320 ASM RC5_INT \ wake up on Px.RC5 change interrupt
51321 \ ******************************\
51322 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
51323 \ ******************************\
51324 \ \ in : SR(9)=old Toggle bit memory (ADD on)
51325 \ \ SMclock = 8|16|24 MHz
51326 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
51327 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
51328 \ \ SR(9)=new Toggle bit memory (ADD on)
51329 \ ******************************\
51330 \ RC5_FirstStartBitHalfCycle: \
51331 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
51332 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
51333 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
51334 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
51335 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
51336 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
51337 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
51338 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
51339 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
51340 MOV #1778,X \ RC5_Period * 1us
51341 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
51342 MOV #14,W \ count of loop
51344 \ ******************************\
51345 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
51346 \ ******************************\ |
51347 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
51348 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
51349 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
51350 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
51351 \ RC5_Compute_3/4_Period: \ |
51352 RRUM #1,X \ X=1/2 cycle |
51355 ADD X,Y \ Y=3/4 cycle
51356 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
51358 \ ******************************\
51359 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
51360 \ ******************************\
51361 BIT.B #RC5,&IR_IN \ C_flag = IR bit
51362 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
51363 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
51364 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
51365 SUB #1,W \ decrement count loop
51366 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
51367 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
51368 0<> WHILE \ ----> out of loop ----+
51369 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
51371 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
51372 CMP Y,X \ 1 | cycle time out of bound ?
51373 U>= IF \ 2 ^ | yes:
51374 BIC #$30,&RC5_TIM_CTL \ | | stop timer
51375 GOTO BW1 \ | | quit on truncated RC5 message
51377 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
51379 REPEAT \ ----> loop back --+ | with X = new RC5_period value
51380 \ ******************************\ |
51381 \ RC5_SampleEndOf: \ <---------------------+
51382 \ ******************************\
51383 BIC #$30,&RC5_TIM_CTL \ stop timer
51384 \ ******************************\
51385 \ RC5_ComputeNewRC5word \
51386 \ ******************************\
51387 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
51388 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
51389 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
51390 \ ******************************\
51391 \ RC5_ComputeC6bit \
51392 \ ******************************\
51393 BIT #BIT14,T \ test /C6 bit in T
51394 0= IF BIS #BIT6,X \ set C6 bit in X
51395 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
51396 \ ******************************\
51397 \ RC5_CommandByteIsDone \ -- BASE RC5_code
51398 \ ******************************\
51399 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
51400 \ ******************************\
51401 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
51402 XOR @RSP,T \ (new XOR old) Toggle bits
51403 BIT #UF10,T \ repeated RC5_command ?
51404 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
51405 XOR #UF10,0(RSP) \ 5 toggle bit memory
51406 \ ******************************\
51407 \ Display IR_RC5 code \ X = RC5 code
51408 \ ******************************\
51410 MOV &BASE,2(PSP) \ save current base
51411 MOV #$10,&BASE \ set hex base
51412 MOV TOS,0(PSP) \ save TOS
51414 LO2HI \ switch from assembler to FORTH
51415 ['] LCD_CLEAR IS CR \ redirects CR
51416 ['] LCD_WrC IS EMIT \ redirects EMIT
51417 CR ." $" 2 U.R \ print IR_RC5 code
51418 ['] CR >BODY IS CR \ restore CR
51419 ['] EMIT >BODY IS EMIT \ restore EMIT
51420 HI2LO \ switch from FORTH to assembler
51421 MOV TOS,&BASE \ restore current BASE
51423 \ ******************************\
51425 \ ******************************\
51429 \ ------------------------------\
51431 \ ------------------------------\
51432 \ ... \ insert here your background task
51435 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
51436 ADD #4,X \ 1 X = BODY of SLEEP
51439 \ ------------------------------\
51443 \ ------------------------------\
51444 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
51445 \ - - \CNTL Counter lentgh \ 00 = 16 bits
51446 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
51447 \ -- \ID input divider \ 10 = /4
51448 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
51449 \ - \TBCLR TimerB Clear
51452 \ -------------------------------\
51453 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
51454 \ -- \CM Capture Mode
51459 \ --- \OUTMOD \ 011 = set/reset
51465 \ -------------------------------\
51467 \ -------------------------------\
51469 \ ------------------------------\
51470 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
51471 \ ------------------------------\
51472 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
51473 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
51474 \ ------------------------------\
51475 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
51476 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
51477 \ ------------------------------\
51478 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
51479 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
51480 \ ------------------------------\
51481 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
51482 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
51483 \ ------------------------------\
51484 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
51485 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
51486 \ ------------------------------\
51487 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
51488 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
51489 \ ------------------------------\
51490 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
51491 \ ------------------------------\
51492 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
51493 \ ------------------------------\
51494 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
51495 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
51496 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
51497 \ ------------------------------\
51498 BIS.B #LCDVo,&LCDVo_DIR \
51499 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
51500 \ ------------------------------\
51501 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
51502 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
51503 \ ------------------------------\
51504 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
51505 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
51506 \ ******************************\
51508 \ ******************************\
51509 BIS.B #RC5,&IR_IE \ enable RC5_Int
51510 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
51511 MOV #RC5_INT,&IR_Vec \ init interrupt vector
51512 \ ******************************\
51513 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
51514 \ ******************************\
51515 \ %01 0001 0100 \ TAxCTL
51516 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
51517 \ -- \ ID divided by 1
51518 \ -- \ MC MODE = up to TAxCCRn
51519 \ - \ TACLR clear timer count
51522 \ ------------------------------\
51523 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
51524 \ ------------------------------\
51526 \ --- \ TAIDEX pre divisor
51527 \ ------------------------------\
51528 \ %0000 0000 0000 0101 \ TAxCCR0
51529 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
51530 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
51531 \ ------------------------------\
51532 \ %0000 0000 0001 0000 \ TAxCCTL0
51533 \ - \ CAP capture/compare mode = compare
51536 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
51537 \ ------------------------------\
51538 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
51539 \ ------------------------------\
51540 \ define LPM mode for ACCEPT \
51541 \ ------------------------------\
51542 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
51543 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
51544 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
51546 \ ------------------------------\
51547 \ redirects to background task \
51548 \ ------------------------------\
51550 MOV #BACKGROUND,2(X) \
51551 \ ------------------------------\
51553 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
51555 \ ------------------------------\
51557 \ ------------------------------\
51558 $03E8 20_US \ 1- wait 20 ms
51559 $03 TOP_LCD \ 2- send DB5=DB4=1
51560 $CD 20_US \ 3- wait 4,1 ms
51561 $03 TOP_LCD \ 4- send again DB5=DB4=1
51562 $5 20_US \ 5- wait 0,1 ms
51563 $03 TOP_LCD \ 6- send again again DB5=DB4=1
51564 $2 20_US \ wait 40 us = LCD cycle
51565 $02 TOP_LCD \ 7- send DB5=1 DB4=0
51566 $2 20_US \ wait 40 us = LCD cycle
51567 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
51568 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
51569 LCD_Clear \ 10- "LCD_Clear"
51570 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
51571 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
51572 LCD_Clear \ 10- "LCD_Clear"
51573 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
51574 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
51576 ['] CR >BODY IS CR \
51577 ['] EMIT >BODY IS EMIT \
51578 ." RC5toLCD is running. Type STOP to quit"
51579 LIT RECURSE IS WARM \ replace WARM by this START routine
51580 ABORT \ and continue with the next word after WARM...
51581 ; \ ...until interpreter falls in sleep mode within ACCEPT.
51584 CODE STOP \ stops multitasking, must to be used before downloading app
51585 \ restore default action of primary DEFERred word SLEEP, assembly version
51586 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
51587 ADD #4,X \ X = BODY of SLEEP
51588 MOV X,-2(X) \ restore the default background
51591 \ restore default action of primary DEFERred word WARM, FORTH version
51592 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
51594 COLD \ because we want to reset CPU and interrupt vectors
51599 ; downloading RC5toLCD.4th is done
51600 RST_HERE ; this app is protected against <reset>
51608 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
51610 [DEFINED] ASM [IF] \ security test
51614 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
51616 CODE MAX \ n1 n2 -- n3 signed maximum
51617 CMP @PSP,TOS \ n2-n1
51618 S< ?GOTO FW1 \ n2<n1
51624 CODE MIN \ n1 n2 -- n3 signed minimum
51625 CMP @PSP,TOS \ n2-n1
51626 S< ?GOTO BW1 \ n2<n1
51634 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
51635 : U.R \ u n -- display u unsigned in n width (n >= 2)
51637 R> OVER - 0 MAX SPACES TYPE
51642 \ CODE 20_US \ n -- n * 20 us
51643 \ BEGIN \ 3 cycles loop + 6~
51644 \ \ MOV #5,W \ 3 MCLK = 1 MHz
51645 \ \ MOV #23,W \ 3 MCLK = 4 MHz
51646 \ \ MOV #51,W \ 3 MCLK = 8 MHz
51647 \ MOV #104,W \ 3 MCLK = 16 MHz
51648 \ \ MOV #158,W \ 3 MCLK = 24 MHz
51649 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
51654 \ MOV @PSP+,TOS \ 2
51659 CODE 20_US \ n -- n * 20 us
51660 BEGIN \ here we presume that LCD_TIM_IFG = 1...
51662 BIT #1,&LCD_TIM_CTL \ 3
51663 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
51664 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
51666 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
51672 CODE TOP_LCD \ LCD Sample
51673 \ \ if write : %xxxxWWWW --
51674 \ \ if read : -- %0000RRRR
51675 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
51676 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
51677 0= IF \ write LCD bits pattern
51678 AND.B #LCD_DB,TOS \
51679 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
51680 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
51683 THEN \ read LCD bits pattern
51686 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
51687 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
51688 AND.B #LCD_DB,TOS \
51693 CODE LCD_W \ byte -- write byte to LCD
51695 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
51696 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
51697 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
51698 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
51699 COLON \ high level word starts here
51700 TOP_LCD 2 20_US \ write high nibble first
51705 CODE LCD_WrC \ char -- Write Char
51706 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
51711 CODE LCD_WrF \ func -- Write Fonction
51712 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
51718 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
51723 $02 LCD_WrF 100 20_us
51727 [UNDEFINED] OR [IF]
51729 \ https://forth-standard.org/standard/core/OR
51730 \ C OR x1 x2 -- x3 logical OR
51739 : LCD_Entry_set $04 OR LCD_WrF ;
51741 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
51743 : LCD_DSP_Shift $10 OR LCD_WrF ;
51745 : LCD_Fn_Set $20 OR LCD_WrF ;
51747 : LCD_CGRAM_Set $40 OR LCD_WrF ;
51749 : LCD_Goto $80 OR LCD_WrF ;
51751 CODE LCD_R \ -- byte read byte from LCD
51752 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
51753 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
51754 COLON \ starts a FORTH word
51755 TOP_LCD 2 20_us \ -- %0000HHHH
51756 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
51757 HI2LO \ switch from FORTH to assembler
51758 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
51759 ADD.B @PSP+,TOS \ -- %HHHHLLLL
51760 MOV @RSP+,IP \ restore IP saved by COLON
51765 CODE LCD_RdS \ -- status Read Status
51766 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
51771 CODE LCD_RdC \ -- char Read Char
51772 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
51778 \ ******************************\
51779 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
51780 \ ******************************\
51781 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
51782 BIT.B #SW2,&SW2_IN \ test switch S2
51783 0= IF \ case of switch S2 pressed
51784 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
51786 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
51789 BIT.B #SW1,&SW1_IN \ test switch S1 input
51790 0= IF \ case of Switch S1 pressed
51791 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
51793 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
51797 BW1 \ from quit on truncated RC5 message
51798 BW2 \ from repeated RC5 command
51799 BW3 \ from end of RC5_INT
51800 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
51805 \ ******************************\
51806 ASM RC5_INT \ wake up on Px.RC5 change interrupt
51807 \ ******************************\
51808 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
51809 \ ******************************\
51810 \ \ in : SR(9)=old Toggle bit memory (ADD on)
51811 \ \ SMclock = 8|16|24 MHz
51812 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
51813 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
51814 \ \ SR(9)=new Toggle bit memory (ADD on)
51815 \ ******************************\
51816 \ RC5_FirstStartBitHalfCycle: \
51817 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
51818 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
51819 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
51820 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
51821 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
51822 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
51823 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
51824 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
51825 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
51826 MOV #1778,X \ RC5_Period * 1us
51827 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
51828 MOV #14,W \ count of loop
51830 \ ******************************\
51831 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
51832 \ ******************************\ |
51833 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
51834 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
51835 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
51836 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
51837 \ RC5_Compute_3/4_Period: \ |
51838 RRUM #1,X \ X=1/2 cycle |
51841 ADD X,Y \ Y=3/4 cycle
51842 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
51844 \ ******************************\
51845 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
51846 \ ******************************\
51847 BIT.B #RC5,&IR_IN \ C_flag = IR bit
51848 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
51849 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
51850 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
51851 SUB #1,W \ decrement count loop
51852 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
51853 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
51854 0<> WHILE \ ----> out of loop ----+
51855 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
51857 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
51858 CMP Y,X \ 1 | cycle time out of bound ?
51859 U>= IF \ 2 ^ | yes:
51860 BIC #$30,&RC5_TIM_CTL \ | | stop timer
51861 GOTO BW1 \ | | quit on truncated RC5 message
51863 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
51865 REPEAT \ ----> loop back --+ | with X = new RC5_period value
51866 \ ******************************\ |
51867 \ RC5_SampleEndOf: \ <---------------------+
51868 \ ******************************\
51869 BIC #$30,&RC5_TIM_CTL \ stop timer
51870 \ ******************************\
51871 \ RC5_ComputeNewRC5word \
51872 \ ******************************\
51873 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
51874 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
51875 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
51876 \ ******************************\
51877 \ RC5_ComputeC6bit \
51878 \ ******************************\
51879 BIT #BIT14,T \ test /C6 bit in T
51880 0= IF BIS #BIT6,X \ set C6 bit in X
51881 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
51882 \ ******************************\
51883 \ RC5_CommandByteIsDone \ -- BASE RC5_code
51884 \ ******************************\
51885 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
51886 \ ******************************\
51887 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
51888 XOR @RSP,T \ (new XOR old) Toggle bits
51889 BIT #UF10,T \ repeated RC5_command ?
51890 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
51891 XOR #UF10,0(RSP) \ 5 toggle bit memory
51892 \ ******************************\
51893 \ Display IR_RC5 code \ X = RC5 code
51894 \ ******************************\
51896 MOV &BASE,2(PSP) \ save current base
51897 MOV #$10,&BASE \ set hex base
51898 MOV TOS,0(PSP) \ save TOS
51900 LO2HI \ switch from assembler to FORTH
51901 ['] LCD_CLEAR IS CR \ redirects CR
51902 ['] LCD_WrC IS EMIT \ redirects EMIT
51903 CR ." $" 2 U.R \ print IR_RC5 code
51904 ['] CR >BODY IS CR \ restore CR
51905 ['] EMIT >BODY IS EMIT \ restore EMIT
51906 HI2LO \ switch from FORTH to assembler
51907 MOV TOS,&BASE \ restore current BASE
51909 \ ******************************\
51911 \ ******************************\
51915 \ ------------------------------\
51917 \ ------------------------------\
51918 \ ... \ insert here your background task
51921 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
51922 ADD #4,X \ 1 X = BODY of SLEEP
51925 \ ------------------------------\
51929 \ ------------------------------\
51930 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
51931 \ - - \CNTL Counter lentgh \ 00 = 16 bits
51932 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
51933 \ -- \ID input divider \ 10 = /4
51934 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
51935 \ - \TBCLR TimerB Clear
51938 \ -------------------------------\
51939 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
51940 \ -- \CM Capture Mode
51945 \ --- \OUTMOD \ 011 = set/reset
51951 \ -------------------------------\
51953 \ -------------------------------\
51955 \ ------------------------------\
51956 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
51957 \ ------------------------------\
51958 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
51959 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
51960 \ ------------------------------\
51961 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
51962 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
51963 \ ------------------------------\
51964 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
51965 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
51966 \ ------------------------------\
51967 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
51968 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
51969 \ ------------------------------\
51970 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
51971 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
51972 \ ------------------------------\
51973 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
51974 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
51975 \ ------------------------------\
51976 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
51977 \ ------------------------------\
51978 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
51979 \ ------------------------------\
51980 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
51981 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
51982 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
51983 \ ------------------------------\
51984 BIS.B #LCDVo,&LCDVo_DIR \
51985 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
51986 \ ------------------------------\
51987 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
51988 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
51989 \ ------------------------------\
51990 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
51991 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
51992 \ ******************************\
51994 \ ******************************\
51995 BIS.B #RC5,&IR_IE \ enable RC5_Int
51996 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
51997 MOV #RC5_INT,&IR_Vec \ init interrupt vector
51998 \ ******************************\
51999 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
52000 \ ******************************\
52001 \ %01 0001 0100 \ TAxCTL
52002 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
52003 \ -- \ ID divided by 1
52004 \ -- \ MC MODE = up to TAxCCRn
52005 \ - \ TACLR clear timer count
52008 \ ------------------------------\
52009 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
52010 \ ------------------------------\
52012 \ --- \ TAIDEX pre divisor
52013 \ ------------------------------\
52014 \ %0000 0000 0000 0101 \ TAxCCR0
52015 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
52016 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
52017 \ ------------------------------\
52018 \ %0000 0000 0001 0000 \ TAxCCTL0
52019 \ - \ CAP capture/compare mode = compare
52022 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
52023 \ ------------------------------\
52024 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
52025 \ ------------------------------\
52026 \ define LPM mode for ACCEPT \
52027 \ ------------------------------\
52028 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
52029 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
52030 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
52032 \ ------------------------------\
52033 \ redirects to background task \
52034 \ ------------------------------\
52036 MOV #BACKGROUND,2(X) \
52037 \ ------------------------------\
52039 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
52041 \ ------------------------------\
52043 \ ------------------------------\
52044 $03E8 20_US \ 1- wait 20 ms
52045 $03 TOP_LCD \ 2- send DB5=DB4=1
52046 $CD 20_US \ 3- wait 4,1 ms
52047 $03 TOP_LCD \ 4- send again DB5=DB4=1
52048 $5 20_US \ 5- wait 0,1 ms
52049 $03 TOP_LCD \ 6- send again again DB5=DB4=1
52050 $2 20_US \ wait 40 us = LCD cycle
52051 $02 TOP_LCD \ 7- send DB5=1 DB4=0
52052 $2 20_US \ wait 40 us = LCD cycle
52053 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
52054 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
52055 LCD_Clear \ 10- "LCD_Clear"
52056 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
52057 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
52058 LCD_Clear \ 10- "LCD_Clear"
52059 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
52060 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
52062 ['] CR >BODY IS CR \
52063 ['] EMIT >BODY IS EMIT \
52064 ." RC5toLCD is running. Type STOP to quit"
52065 LIT RECURSE IS WARM \ replace WARM by this START routine
52066 ABORT \ and continue with the next word after WARM...
52067 ; \ ...until interpreter falls in sleep mode within ACCEPT.
52070 CODE STOP \ stops multitasking, must to be used before downloading app
52071 \ restore default action of primary DEFERred word SLEEP, assembly version
52072 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
52073 ADD #4,X \ X = BODY of SLEEP
52074 MOV X,-2(X) \ restore the default background
52077 \ restore default action of primary DEFERred word WARM, FORTH version
52078 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
52080 COLD \ because we want to reset CPU and interrupt vectors
52085 ; downloading RC5toLCD.4th is done
52086 RST_HERE ; this app is protected against <reset>
52094 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
52096 [DEFINED] ASM [IF] \ security test
52100 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
52102 CODE MAX \ n1 n2 -- n3 signed maximum
52103 CMP @PSP,TOS \ n2-n1
52104 S< ?GOTO FW1 \ n2<n1
52110 CODE MIN \ n1 n2 -- n3 signed minimum
52111 CMP @PSP,TOS \ n2-n1
52112 S< ?GOTO BW1 \ n2<n1
52120 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
52121 : U.R \ u n -- display u unsigned in n width (n >= 2)
52123 R> OVER - 0 MAX SPACES TYPE
52128 \ CODE 20_US \ n -- n * 20 us
52129 \ BEGIN \ 3 cycles loop + 6~
52130 \ \ MOV #5,W \ 3 MCLK = 1 MHz
52131 \ \ MOV #23,W \ 3 MCLK = 4 MHz
52132 \ \ MOV #51,W \ 3 MCLK = 8 MHz
52133 \ MOV #104,W \ 3 MCLK = 16 MHz
52134 \ \ MOV #158,W \ 3 MCLK = 24 MHz
52135 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
52140 \ MOV @PSP+,TOS \ 2
52145 CODE 20_US \ n -- n * 20 us
52146 BEGIN \ here we presume that LCD_TIM_IFG = 1...
52148 BIT #1,&LCD_TIM_CTL \ 3
52149 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
52150 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
52152 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
52158 CODE TOP_LCD \ LCD Sample
52159 \ \ if write : %xxxxWWWW --
52160 \ \ if read : -- %0000RRRR
52161 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
52162 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
52163 0= IF \ write LCD bits pattern
52164 AND.B #LCD_DB,TOS \
52165 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
52166 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
52169 THEN \ read LCD bits pattern
52172 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
52173 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
52174 AND.B #LCD_DB,TOS \
52179 CODE LCD_W \ byte -- write byte to LCD
52181 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
52182 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
52183 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
52184 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
52185 COLON \ high level word starts here
52186 TOP_LCD 2 20_US \ write high nibble first
52191 CODE LCD_WrC \ char -- Write Char
52192 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
52197 CODE LCD_WrF \ func -- Write Fonction
52198 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
52204 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
52209 $02 LCD_WrF 100 20_us
52213 [UNDEFINED] OR [IF]
52215 \ https://forth-standard.org/standard/core/OR
52216 \ C OR x1 x2 -- x3 logical OR
52225 : LCD_Entry_set $04 OR LCD_WrF ;
52227 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
52229 : LCD_DSP_Shift $10 OR LCD_WrF ;
52231 : LCD_Fn_Set $20 OR LCD_WrF ;
52233 : LCD_CGRAM_Set $40 OR LCD_WrF ;
52235 : LCD_Goto $80 OR LCD_WrF ;
52237 CODE LCD_R \ -- byte read byte from LCD
52238 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
52239 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
52240 COLON \ starts a FORTH word
52241 TOP_LCD 2 20_us \ -- %0000HHHH
52242 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
52243 HI2LO \ switch from FORTH to assembler
52244 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
52245 ADD.B @PSP+,TOS \ -- %HHHHLLLL
52246 MOV @RSP+,IP \ restore IP saved by COLON
52251 CODE LCD_RdS \ -- status Read Status
52252 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
52257 CODE LCD_RdC \ -- char Read Char
52258 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
52264 \ ******************************\
52265 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
52266 \ ******************************\
52267 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
52268 BIT.B #SW2,&SW2_IN \ test switch S2
52269 0= IF \ case of switch S2 pressed
52270 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
52272 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
52275 BIT.B #SW1,&SW1_IN \ test switch S1 input
52276 0= IF \ case of Switch S1 pressed
52277 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
52279 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
52283 BW1 \ from quit on truncated RC5 message
52284 BW2 \ from repeated RC5 command
52285 BW3 \ from end of RC5_INT
52286 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
52291 \ ******************************\
52292 ASM RC5_INT \ wake up on Px.RC5 change interrupt
52293 \ ******************************\
52294 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
52295 \ ******************************\
52296 \ \ in : SR(9)=old Toggle bit memory (ADD on)
52297 \ \ SMclock = 8|16|24 MHz
52298 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
52299 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
52300 \ \ SR(9)=new Toggle bit memory (ADD on)
52301 \ ******************************\
52302 \ RC5_FirstStartBitHalfCycle: \
52303 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
52304 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
52305 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
52306 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
52307 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
52308 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
52309 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
52310 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
52311 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
52312 MOV #1778,X \ RC5_Period * 1us
52313 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
52314 MOV #14,W \ count of loop
52316 \ ******************************\
52317 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
52318 \ ******************************\ |
52319 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
52320 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
52321 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
52322 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
52323 \ RC5_Compute_3/4_Period: \ |
52324 RRUM #1,X \ X=1/2 cycle |
52327 ADD X,Y \ Y=3/4 cycle
52328 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
52330 \ ******************************\
52331 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
52332 \ ******************************\
52333 BIT.B #RC5,&IR_IN \ C_flag = IR bit
52334 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
52335 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
52336 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
52337 SUB #1,W \ decrement count loop
52338 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
52339 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
52340 0<> WHILE \ ----> out of loop ----+
52341 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
52343 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
52344 CMP Y,X \ 1 | cycle time out of bound ?
52345 U>= IF \ 2 ^ | yes:
52346 BIC #$30,&RC5_TIM_CTL \ | | stop timer
52347 GOTO BW1 \ | | quit on truncated RC5 message
52349 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
52351 REPEAT \ ----> loop back --+ | with X = new RC5_period value
52352 \ ******************************\ |
52353 \ RC5_SampleEndOf: \ <---------------------+
52354 \ ******************************\
52355 BIC #$30,&RC5_TIM_CTL \ stop timer
52356 \ ******************************\
52357 \ RC5_ComputeNewRC5word \
52358 \ ******************************\
52359 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
52360 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
52361 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
52362 \ ******************************\
52363 \ RC5_ComputeC6bit \
52364 \ ******************************\
52365 BIT #BIT14,T \ test /C6 bit in T
52366 0= IF BIS #BIT6,X \ set C6 bit in X
52367 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
52368 \ ******************************\
52369 \ RC5_CommandByteIsDone \ -- BASE RC5_code
52370 \ ******************************\
52371 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
52372 \ ******************************\
52373 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
52374 XOR @RSP,T \ (new XOR old) Toggle bits
52375 BIT #UF10,T \ repeated RC5_command ?
52376 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
52377 XOR #UF10,0(RSP) \ 5 toggle bit memory
52378 \ ******************************\
52379 \ Display IR_RC5 code \ X = RC5 code
52380 \ ******************************\
52382 MOV &BASE,2(PSP) \ save current base
52383 MOV #$10,&BASE \ set hex base
52384 MOV TOS,0(PSP) \ save TOS
52386 LO2HI \ switch from assembler to FORTH
52387 ['] LCD_CLEAR IS CR \ redirects CR
52388 ['] LCD_WrC IS EMIT \ redirects EMIT
52389 CR ." $" 2 U.R \ print IR_RC5 code
52390 ['] CR >BODY IS CR \ restore CR
52391 ['] EMIT >BODY IS EMIT \ restore EMIT
52392 HI2LO \ switch from FORTH to assembler
52393 MOV TOS,&BASE \ restore current BASE
52395 \ ******************************\
52397 \ ******************************\
52401 \ ------------------------------\
52403 \ ------------------------------\
52404 \ ... \ insert here your background task
52407 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
52408 ADD #4,X \ 1 X = BODY of SLEEP
52411 \ ------------------------------\
52415 \ ------------------------------\
52416 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
52417 \ - - \CNTL Counter lentgh \ 00 = 16 bits
52418 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
52419 \ -- \ID input divider \ 10 = /4
52420 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
52421 \ - \TBCLR TimerB Clear
52424 \ -------------------------------\
52425 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
52426 \ -- \CM Capture Mode
52431 \ --- \OUTMOD \ 011 = set/reset
52437 \ -------------------------------\
52439 \ -------------------------------\
52441 \ ------------------------------\
52442 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
52443 \ ------------------------------\
52444 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
52445 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
52446 \ ------------------------------\
52447 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
52448 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
52449 \ ------------------------------\
52450 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
52451 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
52452 \ ------------------------------\
52453 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
52454 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
52455 \ ------------------------------\
52456 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
52457 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
52458 \ ------------------------------\
52459 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
52460 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
52461 \ ------------------------------\
52462 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
52463 \ ------------------------------\
52464 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
52465 \ ------------------------------\
52466 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
52467 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
52468 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
52469 \ ------------------------------\
52470 BIS.B #LCDVo,&LCDVo_DIR \
52471 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
52472 \ ------------------------------\
52473 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
52474 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
52475 \ ------------------------------\
52476 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
52477 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
52478 \ ******************************\
52480 \ ******************************\
52481 BIS.B #RC5,&IR_IE \ enable RC5_Int
52482 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
52483 MOV #RC5_INT,&IR_Vec \ init interrupt vector
52484 \ ******************************\
52485 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
52486 \ ******************************\
52487 \ %01 0001 0100 \ TAxCTL
52488 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
52489 \ -- \ ID divided by 1
52490 \ -- \ MC MODE = up to TAxCCRn
52491 \ - \ TACLR clear timer count
52494 \ ------------------------------\
52495 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
52496 \ ------------------------------\
52498 \ --- \ TAIDEX pre divisor
52499 \ ------------------------------\
52500 \ %0000 0000 0000 0101 \ TAxCCR0
52501 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
52502 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
52503 \ ------------------------------\
52504 \ %0000 0000 0001 0000 \ TAxCCTL0
52505 \ - \ CAP capture/compare mode = compare
52508 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
52509 \ ------------------------------\
52510 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
52511 \ ------------------------------\
52512 \ define LPM mode for ACCEPT \
52513 \ ------------------------------\
52514 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
52515 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
52516 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
52518 \ ------------------------------\
52519 \ redirects to background task \
52520 \ ------------------------------\
52522 MOV #BACKGROUND,2(X) \
52523 \ ------------------------------\
52525 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
52527 \ ------------------------------\
52529 \ ------------------------------\
52530 $03E8 20_US \ 1- wait 20 ms
52531 $03 TOP_LCD \ 2- send DB5=DB4=1
52532 $CD 20_US \ 3- wait 4,1 ms
52533 $03 TOP_LCD \ 4- send again DB5=DB4=1
52534 $5 20_US \ 5- wait 0,1 ms
52535 $03 TOP_LCD \ 6- send again again DB5=DB4=1
52536 $2 20_US \ wait 40 us = LCD cycle
52537 $02 TOP_LCD \ 7- send DB5=1 DB4=0
52538 $2 20_US \ wait 40 us = LCD cycle
52539 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
52540 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
52541 LCD_Clear \ 10- "LCD_Clear"
52542 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
52543 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
52544 LCD_Clear \ 10- "LCD_Clear"
52545 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
52546 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
52548 ['] CR >BODY IS CR \
52549 ['] EMIT >BODY IS EMIT \
52550 ." RC5toLCD is running. Type STOP to quit"
52551 LIT RECURSE IS WARM \ replace WARM by this START routine
52552 ABORT \ and continue with the next word after WARM...
52553 ; \ ...until interpreter falls in sleep mode within ACCEPT.
52556 CODE STOP \ stops multitasking, must to be used before downloading app
52557 \ restore default action of primary DEFERred word SLEEP, assembly version
52558 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
52559 ADD #4,X \ X = BODY of SLEEP
52560 MOV X,-2(X) \ restore the default background
52563 \ restore default action of primary DEFERred word WARM, FORTH version
52564 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
52566 COLD \ because we want to reset CPU and interrupt vectors
52571 ; downloading RC5toLCD.4th is done
52572 RST_HERE ; this app is protected against <reset>
52580 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
52582 [DEFINED] ASM [IF] \ security test
52586 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
52588 CODE MAX \ n1 n2 -- n3 signed maximum
52589 CMP @PSP,TOS \ n2-n1
52590 S< ?GOTO FW1 \ n2<n1
52596 CODE MIN \ n1 n2 -- n3 signed minimum
52597 CMP @PSP,TOS \ n2-n1
52598 S< ?GOTO BW1 \ n2<n1
52606 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
52607 : U.R \ u n -- display u unsigned in n width (n >= 2)
52609 R> OVER - 0 MAX SPACES TYPE
52614 \ CODE 20_US \ n -- n * 20 us
52615 \ BEGIN \ 3 cycles loop + 6~
52616 \ \ MOV #5,W \ 3 MCLK = 1 MHz
52617 \ \ MOV #23,W \ 3 MCLK = 4 MHz
52618 \ \ MOV #51,W \ 3 MCLK = 8 MHz
52619 \ MOV #104,W \ 3 MCLK = 16 MHz
52620 \ \ MOV #158,W \ 3 MCLK = 24 MHz
52621 \ BEGIN \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
52626 \ MOV @PSP+,TOS \ 2
52631 CODE 20_US \ n -- n * 20 us
52632 BEGIN \ here we presume that LCD_TIM_IFG = 1...
52634 BIT #1,&LCD_TIM_CTL \ 3
52635 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
52636 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
52638 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
52644 CODE TOP_LCD \ LCD Sample
52645 \ \ if write : %xxxxWWWW --
52646 \ \ if read : -- %0000RRRR
52647 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
52648 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
52649 0= IF \ write LCD bits pattern
52650 AND.B #LCD_DB,TOS \
52651 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
52652 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
52655 THEN \ read LCD bits pattern
52658 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
52659 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
52660 AND.B #LCD_DB,TOS \
52665 CODE LCD_W \ byte -- write byte to LCD
52667 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
52668 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
52669 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
52670 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
52671 COLON \ high level word starts here
52672 TOP_LCD 2 20_US \ write high nibble first
52677 CODE LCD_WrC \ char -- Write Char
52678 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
52683 CODE LCD_WrF \ func -- Write Fonction
52684 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
52690 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
52695 $02 LCD_WrF 100 20_us
52699 [UNDEFINED] OR [IF]
52701 \ https://forth-standard.org/standard/core/OR
52702 \ C OR x1 x2 -- x3 logical OR
52711 : LCD_Entry_set $04 OR LCD_WrF ;
52713 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
52715 : LCD_DSP_Shift $10 OR LCD_WrF ;
52717 : LCD_Fn_Set $20 OR LCD_WrF ;
52719 : LCD_CGRAM_Set $40 OR LCD_WrF ;
52721 : LCD_Goto $80 OR LCD_WrF ;
52723 CODE LCD_R \ -- byte read byte from LCD
52724 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
52725 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
52726 COLON \ starts a FORTH word
52727 TOP_LCD 2 20_us \ -- %0000HHHH
52728 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
52729 HI2LO \ switch from FORTH to assembler
52730 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
52731 ADD.B @PSP+,TOS \ -- %HHHHLLLL
52732 MOV @RSP+,IP \ restore IP saved by COLON
52737 CODE LCD_RdS \ -- status Read Status
52738 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
52743 CODE LCD_RdC \ -- char Read Char
52744 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
52750 \ ******************************\
52751 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
52752 \ ******************************\
52753 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
52754 BIT.B #SW2,&SW2_IN \ test switch S2
52755 0= IF \ case of switch S2 pressed
52756 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
52758 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
52761 BIT.B #SW1,&SW1_IN \ test switch S1 input
52762 0= IF \ case of Switch S1 pressed
52763 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
52765 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
52769 BW1 \ from quit on truncated RC5 message
52770 BW2 \ from repeated RC5 command
52771 BW3 \ from end of RC5_INT
52772 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
52777 \ ******************************\
52778 ASM RC5_INT \ wake up on Px.RC5 change interrupt
52779 \ ******************************\
52780 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
52781 \ ******************************\
52782 \ \ in : SR(9)=old Toggle bit memory (ADD on)
52783 \ \ SMclock = 8|16|24 MHz
52784 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
52785 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
52786 \ \ SR(9)=new Toggle bit memory (ADD on)
52787 \ ******************************\
52788 \ RC5_FirstStartBitHalfCycle: \
52789 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
52790 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register ( 125kHz| 1MHz | 2MHZ | 4MHZ | 8MHZ ), reset value
52791 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register ( 250kHZ| 2MHz | 4MHZ | 8MHZ | 16MHZ )
52792 \ MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register ( 375kHz| 3MHz | 6MHZ | 12MHZ | 24MHZ )
52793 \ MOV #3,&RC5_TIM_EX0 \ predivide by 4 in RC5_TIM_EX0 register ( 500kHZ| 4MHz | 8MHZ | 16MHZ )
52794 \ MOV #4,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 625kHz| 5MHz | 10MHZ | 20MHZ )
52795 \ MOV #5,&RC5_TIM_EX0 \ predivide by 6 in RC5_TIM_EX0 register ( 750kHz| 6MHz | 12MHZ | 24MHZ )
52796 \ MOV #6,&RC5_TIM_EX0 \ predivide by 7 in RC5_TIM_EX0 register ( 875kHz| 7MHz | 14MHZ | 28MHZ )
52797 \ MOV #7,&RC5_TIM_EX0 \ predivide by 8 in RC5_TIM_EX0 register ( 1MHz | 8MHz | 16MHZ | 32MHZ )
52798 MOV #1778,X \ RC5_Period * 1us
52799 \ MOV #222,X \ RC5_Period * 8us (SMCLK/1 and first column above)
52800 MOV #14,W \ count of loop
52802 \ ******************************\
52803 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
52804 \ ******************************\ |
52805 \ MOV #%1000100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/1 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
52806 \ MOV #%1002100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/2 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
52807 \ MOV #%1010100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/4 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
52808 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
52809 \ RC5_Compute_3/4_Period: \ |
52810 RRUM #1,X \ X=1/2 cycle |
52813 ADD X,Y \ Y=3/4 cycle
52814 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
52816 \ ******************************\
52817 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
52818 \ ******************************\
52819 BIT.B #RC5,&IR_IN \ C_flag = IR bit
52820 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
52821 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
52822 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
52823 SUB #1,W \ decrement count loop
52824 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
52825 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
52826 0<> WHILE \ ----> out of loop ----+
52827 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
52829 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
52830 CMP Y,X \ 1 | cycle time out of bound ?
52831 U>= IF \ 2 ^ | yes:
52832 BIC #$30,&RC5_TIM_CTL \ | | stop timer
52833 GOTO BW1 \ | | quit on truncated RC5 message
52835 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
52837 REPEAT \ ----> loop back --+ | with X = new RC5_period value
52838 \ ******************************\ |
52839 \ RC5_SampleEndOf: \ <---------------------+
52840 \ ******************************\
52841 BIC #$30,&RC5_TIM_CTL \ stop timer
52842 \ ******************************\
52843 \ RC5_ComputeNewRC5word \
52844 \ ******************************\
52845 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
52846 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
52847 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
52848 \ ******************************\
52849 \ RC5_ComputeC6bit \
52850 \ ******************************\
52851 BIT #BIT14,T \ test /C6 bit in T
52852 0= IF BIS #BIT6,X \ set C6 bit in X
52853 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
52854 \ ******************************\
52855 \ RC5_CommandByteIsDone \ -- BASE RC5_code
52856 \ ******************************\
52857 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
52858 \ ******************************\
52859 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
52860 XOR @RSP,T \ (new XOR old) Toggle bits
52861 BIT #UF10,T \ repeated RC5_command ?
52862 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
52863 XOR #UF10,0(RSP) \ 5 toggle bit memory
52864 \ ******************************\
52865 \ Display IR_RC5 code \ X = RC5 code
52866 \ ******************************\
52868 MOV &BASE,2(PSP) \ save current base
52869 MOV #$10,&BASE \ set hex base
52870 MOV TOS,0(PSP) \ save TOS
52872 LO2HI \ switch from assembler to FORTH
52873 ['] LCD_CLEAR IS CR \ redirects CR
52874 ['] LCD_WrC IS EMIT \ redirects EMIT
52875 CR ." $" 2 U.R \ print IR_RC5 code
52876 ['] CR >BODY IS CR \ restore CR
52877 ['] EMIT >BODY IS EMIT \ restore EMIT
52878 HI2LO \ switch from FORTH to assembler
52879 MOV TOS,&BASE \ restore current BASE
52881 \ ******************************\
52883 \ ******************************\
52887 \ ------------------------------\
52889 \ ------------------------------\
52890 \ ... \ insert here your background task
52893 MOV #SLEEP,X \ 2 Must be the last statement of BACKGROUND
52894 ADD #4,X \ 1 X = BODY of SLEEP
52897 \ ------------------------------\
52901 \ ------------------------------\
52902 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
52903 \ - - \CNTL Counter lentgh \ 00 = 16 bits
52904 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
52905 \ -- \ID input divider \ 10 = /4
52906 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
52907 \ - \TBCLR TimerB Clear
52910 \ -------------------------------\
52911 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
52912 \ -- \CM Capture Mode
52917 \ --- \OUTMOD \ 011 = set/reset
52923 \ -------------------------------\
52925 \ -------------------------------\
52927 \ ------------------------------\
52928 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo, works without interrupt
52929 \ ------------------------------\
52930 \ MOV #%1000010100,&LCD_TIM_CTL \ SMCLK/1, up mode, clear timer, no int
52931 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (1 MHZ)
52932 \ ------------------------------\
52933 \ MOV #%1001010100,&LCD_TIM_CTL \ SMCLK/2, up mode, clear timer, no int
52934 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (2 MHZ)
52935 \ ------------------------------\
52936 \ MOV #%1010010100,&LCD_TIM_CTL \ SMCLK/4, up mode, clear timer, no int
52937 \ MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (4 MHZ)
52938 \ ------------------------------\
52939 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
52940 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
52941 \ ------------------------------\
52942 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
52943 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
52944 \ ------------------------------\
52945 \ MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
52946 \ MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
52947 \ ------------------------------\
52948 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
52949 \ ------------------------------\
52950 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
52951 \ ------------------------------\
52952 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
52953 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
52954 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
52955 \ ------------------------------\
52956 BIS.B #LCDVo,&LCDVo_DIR \
52957 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
52958 \ ------------------------------\
52959 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
52960 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
52961 \ ------------------------------\
52962 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
52963 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
52964 \ ******************************\
52966 \ ******************************\
52967 BIS.B #RC5,&IR_IE \ enable RC5_Int
52968 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
52969 MOV #RC5_INT,&IR_Vec \ init interrupt vector
52970 \ ******************************\
52971 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
52972 \ ******************************\
52973 \ %01 0001 0100 \ TAxCTL
52974 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
52975 \ -- \ ID divided by 1
52976 \ -- \ MC MODE = up to TAxCCRn
52977 \ - \ TACLR clear timer count
52980 \ ------------------------------\
52981 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
52982 \ ------------------------------\
52984 \ --- \ TAIDEX pre divisor
52985 \ ------------------------------\
52986 \ %0000 0000 0000 0101 \ TAxCCR0
52987 MOV ##1638,&WDT_TIM_CCR0 \ init WDT for LFXT: 32768/20=1638 ==> 50ms
52988 \ MOV ##400,&WDT_TIM_CCR0 \ init WDT for VLO: 8000/20=400 ==> 50ms
52989 \ ------------------------------\
52990 \ %0000 0000 0001 0000 \ TAxCCTL0
52991 \ - \ CAP capture/compare mode = compare
52994 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
52995 \ ------------------------------\
52996 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
52997 \ ------------------------------\
52998 \ define LPM mode for ACCEPT \
52999 \ ------------------------------\
53000 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
53001 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
53002 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
53004 \ ------------------------------\
53005 \ redirects to background task \
53006 \ ------------------------------\
53008 MOV #BACKGROUND,2(X) \
53009 \ ------------------------------\
53011 LO2HI \ no need to push IP because (WARM) resets the Return Stack !
53013 \ ------------------------------\
53015 \ ------------------------------\
53016 $03E8 20_US \ 1- wait 20 ms
53017 $03 TOP_LCD \ 2- send DB5=DB4=1
53018 $CD 20_US \ 3- wait 4,1 ms
53019 $03 TOP_LCD \ 4- send again DB5=DB4=1
53020 $5 20_US \ 5- wait 0,1 ms
53021 $03 TOP_LCD \ 6- send again again DB5=DB4=1
53022 $2 20_US \ wait 40 us = LCD cycle
53023 $02 TOP_LCD \ 7- send DB5=1 DB4=0
53024 $2 20_US \ wait 40 us = LCD cycle
53025 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
53026 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
53027 LCD_Clear \ 10- "LCD_Clear"
53028 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
53029 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
53030 LCD_Clear \ 10- "LCD_Clear"
53031 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
53032 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
53034 ['] CR >BODY IS CR \
53035 ['] EMIT >BODY IS EMIT \
53036 ." RC5toLCD is running. Type STOP to quit"
53037 LIT RECURSE IS WARM \ replace WARM by this START routine
53038 ABORT \ and continue with the next word after WARM...
53039 ; \ ...until interpreter falls in sleep mode within ACCEPT.
53042 CODE STOP \ stops multitasking, must to be used before downloading app
53043 \ restore default action of primary DEFERred word SLEEP, assembly version
53044 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
53045 ADD #4,X \ X = BODY of SLEEP
53046 MOV X,-2(X) \ restore the default background
53049 \ restore default action of primary DEFERred word WARM, FORTH version
53050 ['] WARM >BODY IS WARM \ remove START app from FORTH init process
53052 COLD \ because we want to reset CPU and interrupt vectors
53057 ; downloading RC5toLCD.4th is done
53058 RST_HERE ; this app is protected against <reset>
53066 ; -----------------------------------
53068 ; -----------------------------------
53070 \ FastForth Compiling options used :
53071 \ DTC=2, FREQUENCY=8/16/24MHz, THREADS=16,
53072 \ 921600 bauds, 3WIRES, 4WIRES,
53073 \ ASSEMBLER, CONDCOMP, LOWERCASE, NONAME, UTILITY.
53076 \ MSP_EXP430FR5739 MSP_EXP430FR5969 MSP_EXP430FR5994 MSP_EXP430FR6989
53078 \ MY_MSP430FR5738_1 MY_MSP430FR5738 MY_MSP430FR5948 MY_MSP430FR5948_1
53080 \ Copyright (C) <2016> <J.M. THOORENS>
53082 \ This program is free software: you can redistribute it and/or modify
53083 \ it under the terms of the GNU General Public License as published by
53084 \ the Free Software Foundation, either version 3 of the License, or
53085 \ (at your option) any later version.
53087 \ This program is distributed in the hope that it will be useful,
53088 \ but WITHOUT ANY WARRANTY\ without even the implied warranty of
53089 \ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53090 \ GNU General Public License for more details.
53092 \ You should have received a copy of the GNU General Public License
53093 \ along with this program. If not, see <http://www.gnu.org/licenses/>.
53096 \ ===========================================================================
53097 \ remember: for good downloading to target, all lines must be ended with CR+LF !
53098 \ ===========================================================================
53102 \ R4 to R7 must be saved before use and restored after
53103 \ scratch registers Y to S are free for use
53104 \ under interrupt, IP is free for use
53105 \ interrupts reset SR register !
53107 \ PUSHM order : PSP,TOS, IP, S, T, W, X, Y, rEXIT,rDOVAR,rDOCON, rDODOES, R3, SR,RSP, PC
53108 \ PUSHM order : R15,R14,R13,R12,R11,R10, R9, R8, R7 , R6 , R5 , R4 , R3, R2, R1, R0
53110 \ example : PUSHM #6,IP pushes IP,S,T,W,X,Y registers to return stack
53112 \ POPM order : PC,RSP, SR, R3, rDODOES,rDOCON,rDOVAR,rEXIT, Y, X, W, T, S, IP,TOS,PSP
53113 \ POPM order : R0, R1, R2, R3, R4 , R5 , R6 , R7 , R8, R9,R10,R11,R12,R13,R14,R15
53115 \ example : POPM #6,IP pop Y,X,W,T,S,IP registers from return stack
53117 \ ASSEMBLER conditionnal usage after IF UNTIL WHILE : S< S>= U< U>= 0= 0<> 0>=
53118 \ ASSEMBLER conditionnal usage before ?JMP ?GOTO : S< S>= U< U>= 0= 0<> 0<
53120 \ FORTH conditionnal : 0= 0< = < > U<
53122 \ display on a LCD 2x20 CHAR the code sent by an IR remote under philips RC5 protocol
53123 \ target : any TI MSP-EXP430FRxxxx launchpad (FRAM)
53124 \ LPM_MODE = LPM0 because use SMCLK for LCDVo
53126 \ DEMO : driver for IR remote compatible with the PHILIPS RC5 protocol
53127 \ plus : driver for 5V LCD 2x20 characters display with 4 bits data interface
53128 \ without usage of an auxiliary 5V to feed the LCD_Vo
53129 \ and without potentiometer to adjust the LCD contrast :
53130 \ to adjust LCD contrast, just press S1 (-) or S2 (+)
53131 \ LCDVo current consumption ~ 500 uA.
53133 \ ===================================================================================
53134 \ notice : adjust WDT_TIM_EX0,LCD_TIM_CTL,LCD_TIM_EX0 and 20_us to the target frequency if <> 8MHz !
53135 \ ===================================================================================
53138 \ layout : I/O are defined in the launchpad.pat file (don't work with ChipStick_FR2433)
53140 \ GND <-------o---0V0----------> 1 LCD_Vss
53141 \ VCC >-------|---3V6-----o----> 2 LCD_Vdd
53148 \ TB0.2 >---||--o--^/\/\/v--o----> 3 LCD_Vo (= 0V6 without modulation)
53149 \ -------------------------> 4 LCD_RW
53150 \ -------------------------> 5 LCD_RW
53151 \ -------------------------> 6 LCD_EN
53152 \ <------------------------> 11 LCD_DB4
53153 \ <------------------------> 12 LCD_DB5
53154 \ <------------------------> 13 LCD_DB5
53155 \ <------------------------> 14 LCD_DB7
53157 \ <----- LCD contrast + <--- Sw1 <--- (finger) :-)
53158 \ <----- LCD contrast - <--- Sw2 <--- (finger) :-)
53160 \ rc5 <--- OUT IR_Receiver (1 TSOP32236)
53162 [DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application
53164 [DEFINED] ASM [IF] \ security test
53168 [UNDEFINED] MAX [IF] \ MAX and MIN are defined in {ANS_COMP}
53170 CODE MAX \ n1 n2 -- n3 signed maximum
53171 CMP @PSP,TOS \ n2-n1
53172 S< ?GOTO FW1 \ n2<n1
53177 CODE MIN \ n1 n2 -- n3 signed minimum
53178 CMP @PSP,TOS \ n2-n1
53179 S< ?GOTO BW1 \ n2<n1
53186 [UNDEFINED] U.R [IF] \ defined in {UTILITY}
53187 : U.R \ u n -- display u unsigned in n width (n >= 2)
53189 R> OVER - 0 MAX SPACES TYPE
53193 CODE 20_US \ n -- n * 20 us
53194 BEGIN \ here we presume that LCD_TIM_IFG = 1...
53196 BIT #1,&LCD_TIM_CTL \ 3
53197 0<> UNTIL \ 2 loop until LCD_TIM_IFG set
53198 BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG
53200 U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0=
53205 CODE TOP_LCD \ LCD Sample
53206 \ \ if write : %xxxxWWWW --
53207 \ \ if read : -- %0000RRRR
53208 BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1
53209 BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test
53210 0= IF \ write LCD bits pattern
53211 AND.B #LCD_DB,TOS \
53212 MOV.B TOS,&LCD_DB_OUT \ send LCD_Data
53213 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
53216 THEN \ read LCD bits pattern
53219 BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data
53220 MOV.B &LCD_DB_IN,TOS \ get LCD_Data
53221 AND.B #LCD_DB,TOS \
53225 CODE LCD_W \ byte -- write byte to LCD
53227 MOV TOS,0(PSP) \ -- %xxxxLLLL %HHHHLLLL
53228 RRUM #4,TOS \ -- %xxxxLLLL %xxxxHHHH
53229 BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0
53230 BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output
53231 COLON \ high level word starts here
53232 TOP_LCD 2 20_US \ write high nibble first
53236 CODE LCD_WrC \ char -- Write Char
53237 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
53241 CODE LCD_WrF \ func -- Write Fonction
53242 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
53247 $01 LCD_WrF 100 20_us \ $01 LCD_WrF 80 20_us ==> bad init !
53251 $02 LCD_WrF 100 20_us
53254 [UNDEFINED] OR [IF]
53256 \ https://forth-standard.org/standard/core/OR
53257 \ C OR x1 x2 -- x3 logical OR
53265 : LCD_Entry_set $04 OR LCD_WrF ;
53267 : LCD_DSP_Ctrl $08 OR LCD_WrF ;
53269 : LCD_DSP_Shift $10 OR LCD_WrF ;
53271 : LCD_Fn_Set $20 OR LCD_WrF ;
53273 : LCD_CGRAM_Set $40 OR LCD_WrF ;
53275 : LCD_Goto $80 OR LCD_WrF ;
53277 CODE LCD_R \ -- byte read byte from LCD
53278 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput
53279 BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1
53280 COLON \ starts a FORTH word
53281 TOP_LCD 2 20_us \ -- %0000HHHH
53282 TOP_LCD 2 20_us \ -- %0000HHHH %0000LLLL
53283 HI2LO \ switch from FORTH to assembler
53284 RLAM #4,0(PSP) \ -- %HHHH0000 %0000LLLL
53285 ADD.B @PSP+,TOS \ -- %HHHHLLLL
53286 MOV @RSP+,IP \ restore IP saved by COLON
53290 CODE LCD_RdS \ -- status Read Status
53291 BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0
53295 CODE LCD_RdC \ -- char Read Char
53296 BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1
53301 \ ******************************\
53302 ASM WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable !
53303 \ ******************************\
53304 \ XOR.B #LED1,&LED1_OUT \ to visualise WDT
53305 BIT.B #SW2,&SW2_IN \ test switch S2
53306 0= IF \ case of switch S2 pressed
53307 CMP #19,&LCD_TIM_CCR2 \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4
53309 ADD #1,&LCD_TIM_CCR2 \ action for switch S2 (P2.5) : 150 mV / increment
53312 BIT.B #SW1,&SW1_IN \ test switch S1 input
53313 0= IF \ case of Switch S1 pressed
53314 CMP #3,&LCD_TIM_CCR2 \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V
53316 SUB #1,&LCD_TIM_CCR2 \ action for switch S1 (P2.6) : -150 mV / decrement
53320 BW1 \ from quit on truncated RC5 message
53321 BW2 \ from repeated RC5 command
53322 BW3 \ from end of RC5_INT
53323 BIC #$78,0(RSP) \ 4 SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP despite pending interrupt
53327 \ ******************************\
53328 ASM RC5_INT \ wake up on Px.RC5 change interrupt
53329 \ ******************************\
53330 \ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use
53331 \ ******************************\
53332 \ \ in : SR(9)=old Toggle bit memory (ADD on)
53333 \ \ SMclock = 8|16|24 MHz
53334 \ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register
53335 \ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0
53336 \ \ SR(9)=new Toggle bit memory (ADD on)
53337 \ ******************************\
53338 \ RC5_FirstStartBitHalfCycle: \
53339 \ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8)
53340 \ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ?
53341 \ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value
53343 FREQ_KHZ @ 16000 = [IF] \ 16 MHz ?
53344 MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register
53346 FREQ_KHZ @ 24000 = [IF] \ 24 MHz ?
53347 MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register
53349 MOV #1778,X \ RC5_Period * 1us
53350 MOV #14,W \ count of loop
53352 \ ******************************\
53353 \ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period
53354 \ ******************************\ |
53355 MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R
53356 \ RC5_Compute_3/4_Period: \ |
53357 RRUM #1,X \ X=1/2 cycle |
53360 ADD X,Y \ Y=3/4 cycle
53361 BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles
53363 \ ******************************\
53364 \ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first
53365 \ ******************************\
53366 BIT.B #RC5,&IR_IN \ C_flag = IR bit
53367 ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag
53368 MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG
53369 BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change
53370 SUB #1,W \ decrement count loop
53371 \ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6
53372 \ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1
53373 0<> WHILE \ ----> out of loop ----+
53374 ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present
53376 MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles
53377 CMP Y,X \ 1 | cycle time out of bound ?
53378 U>= IF \ 2 ^ | yes:
53379 BIC #$30,&RC5_TIM_CTL \ | | stop timer
53380 GOTO BW1 \ | | quit on truncated RC5 message
53382 BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present
53384 REPEAT \ ----> loop back --+ | with X = new RC5_period value
53385 \ ******************************\ |
53386 \ RC5_SampleEndOf: \ <---------------------+
53387 \ ******************************\
53388 BIC #$30,&RC5_TIM_CTL \ stop timer
53389 \ ******************************\
53390 \ RC5_ComputeNewRC5word \
53391 \ ******************************\
53392 RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0
53393 MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0
53394 RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0
53395 \ ******************************\
53396 \ RC5_ComputeC6bit \
53397 \ ******************************\
53398 BIT #BIT14,T \ test /C6 bit in T
53399 0= IF BIS #BIT6,X \ set C6 bit in X
53400 THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0
53401 \ ******************************\
53402 \ RC5_CommandByteIsDone \ -- BASE RC5_code
53403 \ ******************************\
53404 \ Only New_RC5_Command ADD_ON \ use SR(9) bit as toggle bit
53405 \ ******************************\
53406 RRUM #3,T \ new toggle bit = T(13) ==> T(10)
53407 XOR @RSP,T \ (new XOR old) Toggle bits
53408 BIT #UF10,T \ repeated RC5_command ?
53409 0= ?GOTO BW2 \ yes, RETI without UF10 change and without action !
53410 XOR #UF10,0(RSP) \ 5 toggle bit memory
53411 \ ******************************\
53412 \ Display IR_RC5 code \ X = RC5 code
53413 \ ******************************\
53415 MOV &BASE,2(PSP) \ save current base
53416 MOV #$10,&BASE \ set hex base
53417 MOV TOS,0(PSP) \ save TOS
53419 LO2HI \ switch from assembler to FORTH
53420 ['] LCD_CLEAR IS CR \ redirects CR to LCD
53421 ['] LCD_WrC IS EMIT \ redirects EMIT to LCD
53422 CR ." $" 2 U.R \ print IR_RC5 code to LCD
53423 ['] CR >BODY IS CR \ restore CR
53424 ['] EMIT >BODY IS EMIT \ restore EMIT
53425 HI2LO \ switch from FORTH to assembler
53426 MOV TOS,&BASE \ restore current BASE
53428 \ ******************************\
53430 \ ******************************\
53433 \ ------------------------------\
53435 \ ------------------------------\
53436 \ ... \ insert here your background task
53441 \ ******************************\
53442 \ here start all interrupts \
53443 \ ******************************\
53444 \ here return all interrupts \
53445 \ ******************************\
53452 \ ------------------------------\
53453 CODE STOP \ stops multitasking, must to be used before downloading app
53454 \ ------------------------------\
53455 \ restore default action of primary DEFERred word SLEEP (assembly version)
53456 MOV #SLEEP,X \ the ASM word SLEEP is only visible in mode assembler.
53457 ADD #4,X \ X = BODY of SLEEP, X-2 = PFA of SLEEP
53458 MOV X,-2(X) \ restore the default background
53460 \ restore default action of primary DEFERred word WARM (FORTH version)
53461 ['] WARM >BODY IS WARM \ remove START from FORTH init process
53463 ." RC5toLCD is removed." CR \ display message
53464 ." type START to restart" \
53465 COLD \ performs reset
53468 \ ------------------------------\
53469 CODE START \ this routine completes the init of system, i.e. FORTH + this app.
53470 \ ------------------------------\
53471 \ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0
53472 \ - - \CNTL Counter lentgh \ 00 = 16 bits
53473 \ -- \TBSSEL TimerB clock select \ 10 = SMCLK
53474 \ -- \ID input divider \ 10 = /4
53475 \ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0
53476 \ - \TBCLR TimerB Clear
53479 \ -------------------------------\
53480 \ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
53481 \ -- \CM Capture Mode
53486 \ --- \OUTMOD \ 011 = set/reset
53492 \ -------------------------------\
53494 \ -------------------------------\
53496 \ ------------------------------\
53497 \ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt
53498 \ ------------------------------\
53499 MOV #%1011010100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int
53500 \ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ)
53501 FREQ_KHZ @ 16000 = [IF] \ if 16 MHz
53502 MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ)
53504 FREQ_KHZ @ 24000 = [IF] \ if 24 MHz
53505 MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ)
53507 MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us
53508 \ ------------------------------\
53509 \ set LCD_TIM_.2 to generate PWM for LCD_Vo
53510 \ ------------------------------\
53511 MOV #%01100000,&LCD_TIM_CCTL2 \ output mode = set/reset \ clear CCIFG
53512 MOV #10,&LCD_TIM_CCR2 \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6)
53513 \ MOV #12,&LCD_TIM_CCR2 \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
53514 \ ------------------------------\
53515 BIS.B #LCDVo,&LCDVo_DIR \
53516 BIS.B #LCDVo,&LCDVo_SEL \ SEL.2
53517 \ ------------------------------\
53518 BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
53519 BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
53520 \ ------------------------------\
53521 BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data
53522 BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable
53523 \ ******************************\
53525 \ ******************************\
53526 BIS.B #RC5,&IR_IE \ enable RC5_Int
53527 BIC.B #RC5,&IR_IFG \ reset RC5_Int flag
53528 MOV #RC5_INT,&IR_Vec \ init interrupt vector
53529 \ ******************************\
53530 \ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_
53531 \ ******************************\
53532 \ %01 0001 0100 \ TAxCTL
53533 \ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz
53534 \ -- \ ID divided by 1
53535 \ -- \ MC MODE = up to TAxCCRn
53536 \ - \ TACLR clear timer count
53539 \ ------------------------------\
53540 MOV #%0100010100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int,
53541 \ ------------------------------\
53543 \ --- \ TAIDEX pre divisor
53544 \ ------------------------------\
53545 \ %0000 0000 0000 0101 \ TAxCCR0
53546 MOV ##1638,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 50ms
53547 \ ------------------------------\
53548 \ %0000 0000 0001 0000 \ TAxCCTL0
53549 \ - \ CAP capture/compare mode = compare
53552 MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0
53553 \ ------------------------------\
53554 MOV #WDT_INT,&WDT_TIM_0_Vec \ for only CCIFG0 int, this interrupt clears automatically CCIFG0
53555 \ ------------------------------\
53556 \ define LPM mode for ACCEPT \
53557 \ ------------------------------\
53558 \ MOV #LPM4,&LPM_MODE \ with MSP430FR59xx
53559 \ MOV #LPM2,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2
53560 \ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
53561 \ ------------------------------\
53562 \ redirects to background task \
53563 \ ------------------------------\
53565 MOV #BACKGROUND,2(X) \
53566 \ ------------------------------\ usefull only when any RESET event occurs
53567 \ activate I/O \ because when we type START, it is already done by WARM
53568 \ ------------------------------\ before its redirection by executing START !
53569 BIC #1,&PM5CTL0 \ activate all previous I/O settings; if not activated, nothing works !
53570 BIS.B #TERM_BUS,&TERM_SEL \ Configure pins TXD & RXD for TERM_UART use; if not configured, no TERMINAL !
53571 \ ------------------------------\
53572 \ RESET events handling \ search "SYSRSTIV" in your device datasheet
53573 \ ------------------------------\
53574 MOV &SAVE_SYSRSTIV,Y \
53575 \ CMP #2,Y \ Power_ON event
53576 \ 0= ?JMP STOP \ uncomment if you want to loose application in this case...
53578 0= ?JMP STOP \ hardware RESET performs STOP. Should be mandatory...
53580 \ 0= ?JMP STOP \ COLD event performs STOP... uncomment if it's that you want.
53582 \ 0= ?JMP STOP \ fault event (violation memory protected areas) performs STOP
53584 \ U>= ?JMP STOP \ all other fault events + Deep Reset perform STOP
53585 \ ------------------------------\
53587 \ ------------------------------\
53589 \ ------------------------------\
53590 $03E8 20_US \ 1- wait 20 ms
53591 $03 TOP_LCD \ 2- send DB5=DB4=1
53592 $CD 20_US \ 3- wait 4,1 ms
53593 $03 TOP_LCD \ 4- send again DB5=DB4=1
53594 $5 20_US \ 5- wait 0,1 ms
53595 $03 TOP_LCD \ 6- send again again DB5=DB4=1
53596 $2 20_US \ wait 40 us = LCD cycle
53597 $02 TOP_LCD \ 7- send DB5=1 DB4=0
53598 $2 20_US \ wait 40 us = LCD cycle
53599 $28 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
53600 $08 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off.
53601 LCD_Clear \ 10- "LCD_Clear"
53602 $06 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM
53603 $0C LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off.
53604 LCD_Clear \ 10- "LCD_Clear"
53605 ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME
53606 ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC
53607 CR ." I love you" \ display on LCD
53608 ['] CR >BODY IS CR \
53609 ['] EMIT >BODY IS EMIT \
53610 ." RC5toLCD is running. Type STOP to quit" \ display on FastForth Terminal
53611 \ ------------------------------\
53612 \ START replaces WARM \
53613 \ ------------------------------\
53614 LIT RECURSE IS WARM \ START replaces WARM...
53615 ABORT \ ...and continue with ABORT
53619 ; downloading RC5toLCD.4th is done
53620 RST_HERE ; this app is protected against <reset>