OSDN Git Service

v 162, added Conditionnal Compilation and bootloader
[fast-forth/master.git] / MSP430_COND / PROG100k.f
1 ; -----------------------------------
2 ; prog100k.4th, to test speed of downloading
3 ; -----------------------------------
4     \
5 WIPE
6 NOECHO      ; if an error occurs during download, comment this line then download again
7     \
8 \ Copyright (C) <2016>  <J.M. THOORENS>
9 \
10 \ This program is free software: you can redistribute it and/or modify
11 \ it under the terms of the GNU General Public License as published by
12 \ the Free Software Foundation, either version 3 of the License, or
13 \ (at your option) any later version.
14 \
15 \ This program is distributed in the hope that it will be useful,
16 \ but WITHOUT ANY WARRANTY\ without even the implied warranty of
17 \ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 \ GNU General Public License for more details.
19 \
20 \ You should have received a copy of the GNU General Public License
21 \ along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
23
24 \ ===========================================================================
25 \ remember: for good downloading to target, all lines must be ended with CR+LF !
26 \ ===========================================================================
27
28
29 \ REGISTERS USAGE
30 \ R4 to R7 must be saved before use and restored after
31 \ scratch registers Y to S are free for use
32 \ under interrupt, IP is free for use
33
34 \ PUSHM order : PSP,TOS, IP,  S,  T,  W,  X,  Y, R7, R6, R5, R4
35 \ example : PUSHM IP,Y
36 \
37 \ POPM  order :  R4, R5, R6, R7,  Y,  X,  W,  T,  S, IP,TOS,PSP
38 \ example : POPM Y,IP
39
40 \ ASSEMBLER conditionnal usage after IF UNTIL WHILE : S< S>= U< U>= 0= 0<> 0>=
41 \ ASSEMBLER conditionnal usage before ?JMP ?GOTO    : S< S>= U< U>= 0= 0<> 0< 
42
43 \ FORTH conditionnal    : 0= 0< = < > U<
44
45 \ display on a LCD 2x20 CHAR the code sent by an IR remote under philips RC5 protocol
46 \ target : any TI MSP-EXP430FRxxxx launchpad (FRAM)
47 \ LPM_MODE = LPM0 because use SMCLK for LCDVo
48
49 \ DEMO : driver for IR remote compatible with the PHILIPS RC5 protocol
50 \ plus : driver for 5V LCD 2x20 characters display with 4 bits data interface
51 \        without usage of an auxiliary 5V to feed the LCD_Vo
52 \        and without potentiometer to adjust the LCD contrast :
53 \        to adjust LCD contrast, just press S1 (-) or S2 (+)
54 \        LCDVo current consumption ~ 500 uA.
55
56 \ ===================================================================================
57 \ notice : adjust TA0EX0,TB0CTL,TB0EX0 and 20_us to the target frequency if <> 8MHz !
58 \ ===================================================================================
59
60
61 \ layout : I/O are defined in the launchpad.pat file (don't work with ChipStick_FR2433)
62
63 \  GND  <-------+---0V0---------->  1 LCD_Vss
64 \  VCC  >------ | --3V6-----+---->  2 LCD_Vdd
65 \               |           |
66 \              ___    470n ---
67 \               ^          ---
68 \              / \ 1N4148   |
69 \              ---          |
70 \          100n |    2k2    |
71 \ TB0.2 >---||--+--^/\/\/v--+---->  3 LCD_Vo (= 0V6 without modulation)
72 \       ------------------------->  4 LCD_RW
73 \       ------------------------->  5 LCD_RW
74 \       ------------------------->  6 LCD_EN
75 \       <------------------------> 11 LCD_DB4
76 \       <------------------------> 12 LCD_DB5
77 \       <------------------------> 13 LCD_DB5
78 \       <------------------------> 14 LCD_DB7
79
80 \       <----- LCD contrast + <---    Sw1   <--- (finger) :-)
81 \       <----- LCD contrast - <---    Sw2   <--- (finger) :-)
82
83 \ rc5   <--- OUT IR_Receiver (1 TSOP32236)
84
85
86 CODE MAX    \    n1 n2 -- n3       signed maximum
87             CMP     @PSP,TOS    \ n2-n1
88             S<      ?GOTO FW1   \ n2<n1
89 BW1         ADD     #2,PSP
90             MOV     @IP+,PC
91 ENDCODE
92     \
93
94 CODE MIN    \    n1 n2 -- n3       signed minimum
95             CMP     @PSP,TOS     \ n2-n1
96             S<      ?GOTO BW1    \ n2<n1
97 FW1         MOV     @PSP+,TOS
98             MOV     @IP+,PC
99 ENDCODE
100     \
101
102 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
103   >R  <# 0 # #S #>  
104   R> OVER - 0 MAX SPACES TYPE
105 ;
106     \
107
108 CODE 20_US                      \ n --      n * 20 us
109 BEGIN                           \ 3 cycles loop + 6~  
110 \    MOV     #5,W                \ 3 MCLK = 1 MHz
111 \    MOV     #23,W               \ 3 MCLK = 4 MHz
112     MOV     #51,W               \ 3 MCLK = 8 MHz
113 \    MOV     #104,W              \ 3 MCLK = 16 MHz
114 \    MOV     #158,W              \ 3 MCLK = 24 MHz
115     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
116         SUB #1,W                \ 1
117     0= UNTIL                    \ 2
118     SUB     #1,TOS              \ 1
119 0= UNTIL                        \ 2
120     MOV     @PSP+,TOS           \ 2
121     MOV     @IP+,PC             \ 4
122 ENDCODE
123     \
124
125 CODE TOP_LCD                    \ LCD Sample
126 \                               \ if write : %xxxxWWWW --
127 \                               \ if read  : -- %0000RRRR
128     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
129     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
130 0= IF                           \ write LCD bits pattern
131     AND.B #LCD_DB,TOS           \ 
132     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
133     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
134     MOV @PSP+,TOS               \
135     MOV @IP+,PC
136 THEN                            \ read LCD bits pattern
137     SUB #2,PSP
138     MOV TOS,0(PSP)
139     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
140     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
141     AND.B #LCD_DB,TOS           \
142     MOV @IP+,PC
143 ENDCODE
144     \
145
146 CODE LCD_W                      \ byte --       write byte to LCD 
147     SUB #2,PSP                  \
148     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
149     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
150     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
151     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
152 COLON                           \ high level word starts here 
153     TOP_LCD 2 20_US             \ write high nibble first
154     TOP_LCD 2 20_US 
155 ;
156     \
157
158 CODE LCD_WrC                    \ char --         Write Char
159     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
160     JMP LCD_W 
161 ENDCODE
162     \
163
164 CODE LCD_WrF                    \ func --         Write Fonction
165     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
166     JMP LCD_W 
167 ENDCODE
168     \
169
170 : LCD_Clear 
171     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
172 ;
173     \
174
175 : LCD_Home 
176     $02 LCD_WrF 100 20_us 
177 ;
178     \
179
180 \ : LCD_Entry_set       $04 OR LCD_WrF ;
181
182 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
183
184 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
185
186 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
187
188 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
189
190 \ : LCD_Goto            $80 OR LCD_WrF ;
191
192 \ CODE LCD_R                      \ -- byte       read byte from LCD
193 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
194 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
195 \ COLON                           \ starts a FORTH word
196 \     TOP_LCD 2 20_us             \ -- %0000HHHH
197 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
198 \ HI2LO                           \ switch from FORTH to assembler
199 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
200 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
201 \     MOV @RSP+,IP                \ restore IP saved by COLON
202 \     MOV @IP+,PC                 \
203 \ ENDCODE
204 \     \
205
206 \ CODE LCD_RdS                    \ -- status       Read Status
207 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
208 \     JMP LCD_R
209 \ ENDCODE
210 \     \
211
212 \ CODE LCD_RdC                    \ -- char         Read Char
213 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
214 \     JMP LCD_R
215 \ ENDCODE
216 \     \
217
218 \ -------------+------+------+------+------++---+---+---+---+---------+
219 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
220 \ -------------+------+------+------+------++---+---+---+---+---------+
221 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
222 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
223 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
224 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
225 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
226 \ -------------+------+------+------+------++---+---+---+---+---------+
227
228
229 \ ******************************\
230 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
231 \ ******************************\
232 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
233 \ ------------------------------\
234 \ define LPM mode for ACCEPT    \
235 \ ------------------------------\
236 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
237 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
238 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
239 BIT.B #SW2,&SW2_IN              \ test switch S2
240 0= IF                           \ case of switch S2 pressed
241     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
242     U< IF
243         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
244     THEN
245 ELSE
246     BIT.B #SW1,&SW1_IN          \ test switch S1 input
247     0= IF                       \ case of Switch S1 pressed
248         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
249         U>= IF                  \
250             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
251         THEN                    \
252     THEN                        \
253 THEN                            \
254 RETI                            \ CPU is ON, GIE is OFF
255 ENDASM                          \
256     \
257
258
259 \ ------------------------------\
260 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
261 \ ******************************\
262 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
263 \ ******************************\
264 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
265 \                               \       SMclock = 8|16|24 MHz
266 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
267 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
268 \                               \       SR(9)=new Toggle bit memory (ADD on)
269 \ ------------------------------\
270 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
271 \ ------------------------------\
272 \ define LPM mode for ACCEPT    \
273 \ ------------------------------\
274 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
275 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
276 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
277 \ ------------------------------\
278 \ RC5_FirstStartBitHalfCycle:   \
279 \ ------------------------------\
280 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
281 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
282 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
283 MOV     #1778,X                 \ RC5_Period in us
284 MOV     #14,W                   \ count of loop
285 BEGIN                           \
286 \ ------------------------------\
287 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
288 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
289     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
290 \ RC5_Compute_3/4_Period:       \                   |
291     RRUM    #1,X                \ X=1/2 cycle       |
292     MOV     X,Y                 \ Y=1/2             ^
293     RRUM    #1,Y                \ Y=1/4
294     ADD     X,Y                 \ Y=3/4
295 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
296     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
297     0= UNTIL                    \
298 \ ------------------------------\
299 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
300 \ ------------------------------\
301     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
302     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
303     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
304     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
305     SUB     #1,W                \ decrement count loop
306 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
307 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
308 0<> WHILE                       \ ----> out of loop ----+
309 \ RC5_compute_7/4_Time_out:     \                       |
310     ADD     X,Y                 \                       |   out of bound = 7/4 period 
311 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
312     BEGIN                       \                       |
313         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
314         0>= IF                  \                       |   if cycle time out of bound
315             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
316             RETI                \                       |   then quit to do nothing
317         THEN                    \                       |
318 \ ------------------------------\                       |
319         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
320     0<> UNTIL                   \                   |   |
321     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
322 REPEAT                          \ ----> loop back --+   |
323 \ ------------------------------\                       |
324 \ RC5_SampleEndOf:              \ <---------------------+
325 \ ------------------------------\
326 BIC     #$30,&TA0CTL           \ stop timer_A0
327 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
328 \ ******************************\
329 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
330 \ ******************************\
331 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
332 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
333 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
334 BIT     #BIT13,X                \ X(13) = New_RC5_command
335 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
336 THEN                            \
337 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
338 \ ******************************\
339 \ RC5_ComputeNewRC5word         \
340 \ ******************************\
341 SUB     #4,PSP                  \
342 MOV     &BASE,2(PSP)            \ save variable BASE before use
343 MOV     TOS,0(PSP)              \ save TOS before use
344 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
345 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
346 \ ******************************\
347 \ RC5_ComputeC6bit              \
348 \ ******************************\
349 BIT     #$4000,IP              \ test /C6 bit in IP
350 0= IF   BIS #$40,TOS           \ set C6 bit in S
351 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
352 \ ******************************\
353 \ RC5_CommandByteIsDone         \ RC5_code --
354 \ ******************************\
355
356 \ ------------------------------\
357 \ Display IR_RC5 code           \
358 \ ------------------------------\
359 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
360 \ ------------------------------\
361 LO2HI                           \ switch from assembler to FORTH
362     ['] LCD_CLEAR IS CR         \ redirects CR
363     ['] LCD_WrC  IS EMIT        \ redirects EMIT
364     $10 BASE !                 \ change BASE to hexadecimal
365     CR ." $" 2 U.R             \ print IR_RC5 code
366     ['] (CR) IS CR              \ restore CR
367     ['] (EMIT) IS EMIT          \ restore EMIT
368 HI2LO                           \ switch from FORTH to assembler
369 \ ------------------------------\
370 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
371 \ ------------------------------\
372 MOV @PSP+,&BASE                 \ restore variable BASE
373 RETI                            \ CPU is ON, GIE is OFF
374 ENDASM                          \
375     \ 
376
377 CODE START                      \
378 \ ------------------------------\
379 \ TB0CTL = %0000 0010 1001 0100\$3C0
380 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
381 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
382 \                      --       \ID input divider \ 10 = /4
383 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
384 \                            -  \TBCLR TimerB Clear
385 \                             - \TBIE
386 \                              -\TBIFG
387 \ --------------------------------\\
388 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
389 \              --                 \CM Capture Mode
390 \                --               \CCIS
391 \                   -             \SCS
392 \                    --           \CLLD
393 \                      -          \CAP
394 \                        ---      \OUTMOD \ 011 = set/reset
395 \                           -     \CCIE
396 \                             -   \CCI
397 \                              -  \OUT
398 \                               - \COV
399 \                                -\CCIFG
400 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
401 \ TB0EX0                          \$3E0 
402 \ ------------------------------\
403 \ set TimerB to make 50kHz PWM  \
404 \ ------------------------------\
405 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
406 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
407 \ ------------------------------\
408 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
409 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
410 \ ------------------------------\
411     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
412     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
413 \ ------------------------------\
414 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
415 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
416 \ ------------------------------\
417 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
418 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
419 \ ------------------------------\
420     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
421 \ ------------------------------\
422 \ set TimerB to generate PWM for LCD_Vo
423 \ ------------------------------\
424     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
425 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
426     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
427 \ ------------------------------\
428     BIS.B #LCDVo,&LCDVo_DIR     \
429     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
430 \ ------------------------------\
431     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
432     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
433 \ ------------------------------\
434     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
435     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
436 \ ------------------------------\
437 \ WDT interval init part        \
438 \ ------------------------------\
439     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
440 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
441 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
442     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
443 \ ------------------------------\
444 \ init RC5_Int                  \
445 \ ------------------------------\
446     BIS.B #RC5,&IR_IE           \ enable RC5_Int
447     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
448 \ ------------------------------\
449 \ init interrupt vectors
450 \ ------------------------------\
451     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
452     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
453 \ ------------------------------\
454 \ define LPM mode for ACCEPT    \
455 \ ------------------------------\
456 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
457 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
458 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
459
460 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
461
462 \ ------------------------------\
463 \ Init LCD 2x20                 \
464 \ ------------------------------\
465     $03E8 20_US                \ 1-  wait 20 ms
466     $03 TOP_LCD                \ 2- send DB5=DB4=1
467     $CD 20_US                  \ 3- wait 4,1 ms
468     $03 TOP_LCD                \ 4- send again DB5=DB4=1
469     $5 20_US                   \ 5- wait 0,1 ms
470     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
471     $2 20_US                   \    wait 40 us = LCD cycle
472     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
473     $2 20_US                   \    wait 40 us = LCD cycle
474     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
475     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
476     LCD_Clear                   \ 10- "LCD_Clear"
477     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
478     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
479     LCD_Clear                   \ 10- "LCD_Clear"
480     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
481     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
482     CR ." I love you"   
483     ['] (CR) IS CR              \ ' (CR) is CR
484     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
485     CR
486     ."    RC5toLCD is running. Type STOP to quit"
487 \    NOECHO                      \ uncomment to run this app without terminal connexion
488     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
489     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
490 ;
491     \
492
493 : STOP                  \ stops multitasking, must to be used before downloading app
494     ['] (WARM) IS WARM  \ remove START app from FORTH init process
495     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
496 ;
497     \
498
499
500 RST_STATE   ;
501
502
503 CODE MAX    \    n1 n2 -- n3       signed maximum
504             CMP     @PSP,TOS    \ n2-n1
505             S<      ?GOTO FW1   \ n2<n1
506 BW1         ADD     #2,PSP
507             MOV     @IP+,PC
508 ENDCODE
509     \
510
511 CODE MIN    \    n1 n2 -- n3       signed minimum
512             CMP     @PSP,TOS     \ n2-n1
513             S<      ?GOTO BW1    \ n2<n1
514 FW1         MOV     @PSP+,TOS
515             MOV     @IP+,PC
516 ENDCODE
517     \
518
519 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
520   >R  <# 0 # #S #>  
521   R> OVER - 0 MAX SPACES TYPE
522 ;
523     \
524
525 CODE 20_US                      \ n --      n * 20 us
526 BEGIN                           \ 3 cycles loop + 6~  
527 \    MOV     #5,W                \ 3 MCLK = 1 MHz
528 \    MOV     #23,W               \ 3 MCLK = 4 MHz
529     MOV     #51,W               \ 3 MCLK = 8 MHz
530 \    MOV     #104,W              \ 3 MCLK = 16 MHz
531 \    MOV     #158,W              \ 3 MCLK = 24 MHz
532     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
533         SUB #1,W                \ 1
534     0= UNTIL                    \ 2
535     SUB     #1,TOS              \ 1
536 0= UNTIL                        \ 2
537     MOV     @PSP+,TOS           \ 2
538     MOV     @IP+,PC             \ 4
539 ENDCODE
540     \
541
542 CODE TOP_LCD                    \ LCD Sample
543 \                               \ if write : %xxxxWWWW --
544 \                               \ if read  : -- %0000RRRR
545     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
546     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
547 0= IF                           \ write LCD bits pattern
548     AND.B #LCD_DB,TOS           \ 
549     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
550     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
551     MOV @PSP+,TOS               \
552     MOV @IP+,PC
553 THEN                            \ read LCD bits pattern
554     SUB #2,PSP
555     MOV TOS,0(PSP)
556     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
557     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
558     AND.B #LCD_DB,TOS           \
559     MOV @IP+,PC
560 ENDCODE
561     \
562
563 CODE LCD_W                      \ byte --       write byte to LCD 
564     SUB #2,PSP                  \
565     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
566     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
567     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
568     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
569 COLON                           \ high level word starts here 
570     TOP_LCD 2 20_US             \ write high nibble first
571     TOP_LCD 2 20_US 
572 ;
573     \
574
575 CODE LCD_WrC                    \ char --         Write Char
576     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
577     JMP LCD_W 
578 ENDCODE
579     \
580
581 CODE LCD_WrF                    \ func --         Write Fonction
582     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
583     JMP LCD_W 
584 ENDCODE
585     \
586
587 : LCD_Clear 
588     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
589 ;
590     \
591
592 : LCD_Home 
593     $02 LCD_WrF 100 20_us 
594 ;
595     \
596
597 \ : LCD_Entry_set       $04 OR LCD_WrF ;
598
599 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
600
601 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
602
603 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
604
605 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
606
607 \ : LCD_Goto            $80 OR LCD_WrF ;
608
609 \ CODE LCD_R                      \ -- byte       read byte from LCD
610 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
611 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
612 \ COLON                           \ starts a FORTH word
613 \     TOP_LCD 2 20_us             \ -- %0000HHHH
614 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
615 \ HI2LO                           \ switch from FORTH to assembler
616 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
617 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
618 \     MOV @RSP+,IP                \ restore IP saved by COLON
619 \     MOV @IP+,PC                 \
620 \ ENDCODE
621 \     \
622
623 \ CODE LCD_RdS                    \ -- status       Read Status
624 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
625 \     JMP LCD_R
626 \ ENDCODE
627 \     \
628
629 \ CODE LCD_RdC                    \ -- char         Read Char
630 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
631 \     JMP LCD_R
632 \ ENDCODE
633 \     \
634
635 \ -------------+------+------+------+------++---+---+---+---+---------+
636 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
637 \ -------------+------+------+------+------++---+---+---+---+---------+
638 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
639 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
640 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
641 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
642 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
643 \ -------------+------+------+------+------++---+---+---+---+---------+
644
645
646 \ ******************************\
647 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
648 \ ******************************\
649 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
650 \ ------------------------------\
651 \ define LPM mode for ACCEPT    \
652 \ ------------------------------\
653 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
654 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
655 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
656 BIT.B #SW2,&SW2_IN              \ test switch S2
657 0= IF                           \ case of switch S2 pressed
658     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
659     U< IF
660         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
661     THEN
662 ELSE
663     BIT.B #SW1,&SW1_IN          \ test switch S1 input
664     0= IF                       \ case of Switch S1 pressed
665         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
666         U>= IF                  \
667             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
668         THEN                    \
669     THEN                        \
670 THEN                            \
671 RETI                            \ CPU is ON, GIE is OFF
672 ENDASM                          \
673     \
674
675
676 \ ------------------------------\
677 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
678 \ ******************************\
679 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
680 \ ******************************\
681 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
682 \                               \       SMclock = 8|16|24 MHz
683 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
684 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
685 \                               \       SR(9)=new Toggle bit memory (ADD on)
686 \ ------------------------------\
687 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
688 \ ------------------------------\
689 \ define LPM mode for ACCEPT    \
690 \ ------------------------------\
691 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
692 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
693 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
694 \ ------------------------------\
695 \ RC5_FirstStartBitHalfCycle:   \
696 \ ------------------------------\
697 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
698 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
699 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
700 MOV     #1778,X                 \ RC5_Period in us
701 MOV     #14,W                   \ count of loop
702 BEGIN                           \
703 \ ------------------------------\
704 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
705 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
706     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
707 \ RC5_Compute_3/4_Period:       \                   |
708     RRUM    #1,X                \ X=1/2 cycle       |
709     MOV     X,Y                 \ Y=1/2             ^
710     RRUM    #1,Y                \ Y=1/4
711     ADD     X,Y                 \ Y=3/4
712 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
713     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
714     0= UNTIL                    \
715 \ ------------------------------\
716 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
717 \ ------------------------------\
718     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
719     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
720     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
721     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
722     SUB     #1,W                \ decrement count loop
723 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
724 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
725 0<> WHILE                       \ ----> out of loop ----+
726 \ RC5_compute_7/4_Time_out:     \                       |
727     ADD     X,Y                 \                       |   out of bound = 7/4 period 
728 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
729     BEGIN                       \                       |
730         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
731         0>= IF                  \                       |   if cycle time out of bound
732             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
733             RETI                \                       |   then quit to do nothing
734         THEN                    \                       |
735 \ ------------------------------\                       |
736         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
737     0<> UNTIL                   \                   |   |
738     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
739 REPEAT                          \ ----> loop back --+   |
740 \ ------------------------------\                       |
741 \ RC5_SampleEndOf:              \ <---------------------+
742 \ ------------------------------\
743 BIC     #$30,&TA0CTL           \ stop timer_A0
744 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
745 \ ******************************\
746 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
747 \ ******************************\
748 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
749 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
750 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
751 BIT     #BIT13,X                \ X(13) = New_RC5_command
752 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
753 THEN                            \
754 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
755 \ ******************************\
756 \ RC5_ComputeNewRC5word         \
757 \ ******************************\
758 SUB     #4,PSP                  \
759 MOV     &BASE,2(PSP)            \ save variable BASE before use
760 MOV     TOS,0(PSP)              \ save TOS before use
761 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
762 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
763 \ ******************************\
764 \ RC5_ComputeC6bit              \
765 \ ******************************\
766 BIT     #$4000,IP              \ test /C6 bit in IP
767 0= IF   BIS #$40,TOS           \ set C6 bit in S
768 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
769 \ ******************************\
770 \ RC5_CommandByteIsDone         \ RC5_code --
771 \ ******************************\
772
773 \ ------------------------------\
774 \ Display IR_RC5 code           \
775 \ ------------------------------\
776 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
777 \ ------------------------------\
778 LO2HI                           \ switch from assembler to FORTH
779     ['] LCD_CLEAR IS CR         \ redirects CR
780     ['] LCD_WrC  IS EMIT        \ redirects EMIT
781     $10 BASE !                 \ change BASE to hexadecimal
782     CR ." $" 2 U.R             \ print IR_RC5 code
783     ['] (CR) IS CR              \ restore CR
784     ['] (EMIT) IS EMIT          \ restore EMIT
785 HI2LO                           \ switch from FORTH to assembler
786 \ ------------------------------\
787 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
788 \ ------------------------------\
789 MOV @PSP+,&BASE                 \ restore variable BASE
790 RETI                            \ CPU is ON, GIE is OFF
791 ENDASM                          \
792     \ 
793
794 CODE START                      \
795 \ ------------------------------\
796 \ TB0CTL = %0000 0010 1001 0100\$3C0
797 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
798 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
799 \                      --       \ID input divider \ 10 = /4
800 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
801 \                            -  \TBCLR TimerB Clear
802 \                             - \TBIE
803 \                              -\TBIFG
804 \ --------------------------------\\
805 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
806 \              --                 \CM Capture Mode
807 \                --               \CCIS
808 \                   -             \SCS
809 \                    --           \CLLD
810 \                      -          \CAP
811 \                        ---      \OUTMOD \ 011 = set/reset
812 \                           -     \CCIE
813 \                             -   \CCI
814 \                              -  \OUT
815 \                               - \COV
816 \                                -\CCIFG
817 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
818 \ TB0EX0                          \$3E0 
819 \ ------------------------------\
820 \ set TimerB to make 50kHz PWM  \
821 \ ------------------------------\
822 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
823 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
824 \ ------------------------------\
825 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
826 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
827 \ ------------------------------\
828     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
829     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
830 \ ------------------------------\
831 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
832 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
833 \ ------------------------------\
834 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
835 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
836 \ ------------------------------\
837     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
838 \ ------------------------------\
839 \ set TimerB to generate PWM for LCD_Vo
840 \ ------------------------------\
841     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
842 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
843     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
844 \ ------------------------------\
845     BIS.B #LCDVo,&LCDVo_DIR     \
846     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
847 \ ------------------------------\
848     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
849     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
850 \ ------------------------------\
851     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
852     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
853 \ ------------------------------\
854 \ WDT interval init part        \
855 \ ------------------------------\
856     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
857 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
858 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
859     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
860 \ ------------------------------\
861 \ init RC5_Int                  \
862 \ ------------------------------\
863     BIS.B #RC5,&IR_IE           \ enable RC5_Int
864     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
865 \ ------------------------------\
866 \ init interrupt vectors
867 \ ------------------------------\
868     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
869     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
870 \ ------------------------------\
871 \ define LPM mode for ACCEPT    \
872 \ ------------------------------\
873 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
874 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
875 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
876
877 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
878
879 \ ------------------------------\
880 \ Init LCD 2x20                 \
881 \ ------------------------------\
882     $03E8 20_US                \ 1-  wait 20 ms
883     $03 TOP_LCD                \ 2- send DB5=DB4=1
884     $CD 20_US                  \ 3- wait 4,1 ms
885     $03 TOP_LCD                \ 4- send again DB5=DB4=1
886     $5 20_US                   \ 5- wait 0,1 ms
887     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
888     $2 20_US                   \    wait 40 us = LCD cycle
889     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
890     $2 20_US                   \    wait 40 us = LCD cycle
891     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
892     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
893     LCD_Clear                   \ 10- "LCD_Clear"
894     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
895     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
896     LCD_Clear                   \ 10- "LCD_Clear"
897     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
898     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
899     CR ." I love you"   
900     ['] (CR) IS CR              \ ' (CR) is CR
901     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
902     CR
903     ."    RC5toLCD is running. Type STOP to quit"
904 \    NOECHO                      \ uncomment to run this app without terminal connexion
905     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
906     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
907 ;
908     \
909
910 : STOP                  \ stops multitasking, must to be used before downloading app
911     ['] (WARM) IS WARM  \ remove START app from FORTH init process
912     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
913 ;
914     \
915
916
917 RST_STATE   ;
918
919
920 CODE MAX    \    n1 n2 -- n3       signed maximum
921             CMP     @PSP,TOS    \ n2-n1
922             S<      ?GOTO FW1   \ n2<n1
923 BW1         ADD     #2,PSP
924             MOV     @IP+,PC
925 ENDCODE
926     \
927
928 CODE MIN    \    n1 n2 -- n3       signed minimum
929             CMP     @PSP,TOS     \ n2-n1
930             S<      ?GOTO BW1    \ n2<n1
931 FW1         MOV     @PSP+,TOS
932             MOV     @IP+,PC
933 ENDCODE
934     \
935
936 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
937   >R  <# 0 # #S #>  
938   R> OVER - 0 MAX SPACES TYPE
939 ;
940     \
941
942 CODE 20_US                      \ n --      n * 20 us
943 BEGIN                           \ 3 cycles loop + 6~  
944 \    MOV     #5,W                \ 3 MCLK = 1 MHz
945 \    MOV     #23,W               \ 3 MCLK = 4 MHz
946     MOV     #51,W               \ 3 MCLK = 8 MHz
947 \    MOV     #104,W              \ 3 MCLK = 16 MHz
948 \    MOV     #158,W              \ 3 MCLK = 24 MHz
949     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
950         SUB #1,W                \ 1
951     0= UNTIL                    \ 2
952     SUB     #1,TOS              \ 1
953 0= UNTIL                        \ 2
954     MOV     @PSP+,TOS           \ 2
955     MOV     @IP+,PC             \ 4
956 ENDCODE
957     \
958
959 CODE TOP_LCD                    \ LCD Sample
960 \                               \ if write : %xxxxWWWW --
961 \                               \ if read  : -- %0000RRRR
962     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
963     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
964 0= IF                           \ write LCD bits pattern
965     AND.B #LCD_DB,TOS           \ 
966     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
967     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
968     MOV @PSP+,TOS               \
969     MOV @IP+,PC
970 THEN                            \ read LCD bits pattern
971     SUB #2,PSP
972     MOV TOS,0(PSP)
973     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
974     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
975     AND.B #LCD_DB,TOS           \
976     MOV @IP+,PC
977 ENDCODE
978     \
979
980 CODE LCD_W                      \ byte --       write byte to LCD 
981     SUB #2,PSP                  \
982     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
983     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
984     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
985     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
986 COLON                           \ high level word starts here 
987     TOP_LCD 2 20_US             \ write high nibble first
988     TOP_LCD 2 20_US 
989 ;
990     \
991
992 CODE LCD_WrC                    \ char --         Write Char
993     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
994     JMP LCD_W 
995 ENDCODE
996     \
997
998 CODE LCD_WrF                    \ func --         Write Fonction
999     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
1000     JMP LCD_W 
1001 ENDCODE
1002     \
1003
1004 : LCD_Clear 
1005     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
1006 ;
1007     \
1008
1009 : LCD_Home 
1010     $02 LCD_WrF 100 20_us 
1011 ;
1012     \
1013
1014 \ : LCD_Entry_set       $04 OR LCD_WrF ;
1015
1016 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
1017
1018 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
1019
1020 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
1021
1022 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
1023
1024 \ : LCD_Goto            $80 OR LCD_WrF ;
1025
1026 \ CODE LCD_R                      \ -- byte       read byte from LCD
1027 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
1028 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
1029 \ COLON                           \ starts a FORTH word
1030 \     TOP_LCD 2 20_us             \ -- %0000HHHH
1031 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
1032 \ HI2LO                           \ switch from FORTH to assembler
1033 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
1034 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
1035 \     MOV @RSP+,IP                \ restore IP saved by COLON
1036 \     MOV @IP+,PC                 \
1037 \ ENDCODE
1038 \     \
1039
1040 \ CODE LCD_RdS                    \ -- status       Read Status
1041 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
1042 \     JMP LCD_R
1043 \ ENDCODE
1044 \     \
1045
1046 \ CODE LCD_RdC                    \ -- char         Read Char
1047 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
1048 \     JMP LCD_R
1049 \ ENDCODE
1050 \     \
1051
1052 \ -------------+------+------+------+------++---+---+---+---+---------+
1053 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
1054 \ -------------+------+------+------+------++---+---+---+---+---------+
1055 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
1056 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
1057 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
1058 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
1059 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
1060 \ -------------+------+------+------+------++---+---+---+---+---------+
1061
1062
1063 \ ******************************\
1064 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
1065 \ ******************************\
1066 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
1067 \ ------------------------------\
1068 \ define LPM mode for ACCEPT    \
1069 \ ------------------------------\
1070 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
1071 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1072 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1073 BIT.B #SW2,&SW2_IN              \ test switch S2
1074 0= IF                           \ case of switch S2 pressed
1075     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
1076     U< IF
1077         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
1078     THEN
1079 ELSE
1080     BIT.B #SW1,&SW1_IN          \ test switch S1 input
1081     0= IF                       \ case of Switch S1 pressed
1082         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
1083         U>= IF                  \
1084             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
1085         THEN                    \
1086     THEN                        \
1087 THEN                            \
1088 RETI                            \ CPU is ON, GIE is OFF
1089 ENDASM                          \
1090     \
1091
1092
1093 \ ------------------------------\
1094 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
1095 \ ******************************\
1096 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
1097 \ ******************************\
1098 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
1099 \                               \       SMclock = 8|16|24 MHz
1100 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
1101 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
1102 \                               \       SR(9)=new Toggle bit memory (ADD on)
1103 \ ------------------------------\
1104 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
1105 \ ------------------------------\
1106 \ define LPM mode for ACCEPT    \
1107 \ ------------------------------\
1108 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
1109 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1110 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1111 \ ------------------------------\
1112 \ RC5_FirstStartBitHalfCycle:   \
1113 \ ------------------------------\
1114 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
1115 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
1116 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
1117 MOV     #1778,X                 \ RC5_Period in us
1118 MOV     #14,W                   \ count of loop
1119 BEGIN                           \
1120 \ ------------------------------\
1121 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
1122 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
1123     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
1124 \ RC5_Compute_3/4_Period:       \                   |
1125     RRUM    #1,X                \ X=1/2 cycle       |
1126     MOV     X,Y                 \ Y=1/2             ^
1127     RRUM    #1,Y                \ Y=1/4
1128     ADD     X,Y                 \ Y=3/4
1129 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
1130     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
1131     0= UNTIL                    \
1132 \ ------------------------------\
1133 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
1134 \ ------------------------------\
1135     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
1136     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
1137     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
1138     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
1139     SUB     #1,W                \ decrement count loop
1140 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
1141 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
1142 0<> WHILE                       \ ----> out of loop ----+
1143 \ RC5_compute_7/4_Time_out:     \                       |
1144     ADD     X,Y                 \                       |   out of bound = 7/4 period 
1145 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
1146     BEGIN                       \                       |
1147         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
1148         0>= IF                  \                       |   if cycle time out of bound
1149             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
1150             RETI                \                       |   then quit to do nothing
1151         THEN                    \                       |
1152 \ ------------------------------\                       |
1153         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
1154     0<> UNTIL                   \                   |   |
1155     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
1156 REPEAT                          \ ----> loop back --+   |
1157 \ ------------------------------\                       |
1158 \ RC5_SampleEndOf:              \ <---------------------+
1159 \ ------------------------------\
1160 BIC     #$30,&TA0CTL           \ stop timer_A0
1161 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
1162 \ ******************************\
1163 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
1164 \ ******************************\
1165 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
1166 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
1167 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
1168 BIT     #BIT13,X                \ X(13) = New_RC5_command
1169 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
1170 THEN                            \
1171 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
1172 \ ******************************\
1173 \ RC5_ComputeNewRC5word         \
1174 \ ******************************\
1175 SUB     #4,PSP                  \
1176 MOV     &BASE,2(PSP)            \ save variable BASE before use
1177 MOV     TOS,0(PSP)              \ save TOS before use
1178 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
1179 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
1180 \ ******************************\
1181 \ RC5_ComputeC6bit              \
1182 \ ******************************\
1183 BIT     #$4000,IP              \ test /C6 bit in IP
1184 0= IF   BIS #$40,TOS           \ set C6 bit in S
1185 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
1186 \ ******************************\
1187 \ RC5_CommandByteIsDone         \ RC5_code --
1188 \ ******************************\
1189
1190 \ ------------------------------\
1191 \ Display IR_RC5 code           \
1192 \ ------------------------------\
1193 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
1194 \ ------------------------------\
1195 LO2HI                           \ switch from assembler to FORTH
1196     ['] LCD_CLEAR IS CR         \ redirects CR
1197     ['] LCD_WrC  IS EMIT        \ redirects EMIT
1198     $10 BASE !                 \ change BASE to hexadecimal
1199     CR ." $" 2 U.R             \ print IR_RC5 code
1200     ['] (CR) IS CR              \ restore CR
1201     ['] (EMIT) IS EMIT          \ restore EMIT
1202 HI2LO                           \ switch from FORTH to assembler
1203 \ ------------------------------\
1204 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
1205 \ ------------------------------\
1206 MOV @PSP+,&BASE                 \ restore variable BASE
1207 RETI                            \ CPU is ON, GIE is OFF
1208 ENDASM                          \
1209     \ 
1210
1211 CODE START                      \
1212 \ ------------------------------\
1213 \ TB0CTL = %0000 0010 1001 0100\$3C0
1214 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
1215 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
1216 \                      --       \ID input divider \ 10 = /4
1217 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
1218 \                            -  \TBCLR TimerB Clear
1219 \                             - \TBIE
1220 \                              -\TBIFG
1221 \ --------------------------------\\
1222 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
1223 \              --                 \CM Capture Mode
1224 \                --               \CCIS
1225 \                   -             \SCS
1226 \                    --           \CLLD
1227 \                      -          \CAP
1228 \                        ---      \OUTMOD \ 011 = set/reset
1229 \                           -     \CCIE
1230 \                             -   \CCI
1231 \                              -  \OUT
1232 \                               - \COV
1233 \                                -\CCIFG
1234 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
1235 \ TB0EX0                          \$3E0 
1236 \ ------------------------------\
1237 \ set TimerB to make 50kHz PWM  \
1238 \ ------------------------------\
1239 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
1240 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
1241 \ ------------------------------\
1242 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
1243 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
1244 \ ------------------------------\
1245     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
1246     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
1247 \ ------------------------------\
1248 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
1249 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
1250 \ ------------------------------\
1251 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
1252 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
1253 \ ------------------------------\
1254     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
1255 \ ------------------------------\
1256 \ set TimerB to generate PWM for LCD_Vo
1257 \ ------------------------------\
1258     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
1259 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
1260     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
1261 \ ------------------------------\
1262     BIS.B #LCDVo,&LCDVo_DIR     \
1263     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
1264 \ ------------------------------\
1265     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
1266     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
1267 \ ------------------------------\
1268     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
1269     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
1270 \ ------------------------------\
1271 \ WDT interval init part        \
1272 \ ------------------------------\
1273     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
1274 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
1275 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
1276     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
1277 \ ------------------------------\
1278 \ init RC5_Int                  \
1279 \ ------------------------------\
1280     BIS.B #RC5,&IR_IE           \ enable RC5_Int
1281     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
1282 \ ------------------------------\
1283 \ init interrupt vectors
1284 \ ------------------------------\
1285     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
1286     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
1287 \ ------------------------------\
1288 \ define LPM mode for ACCEPT    \
1289 \ ------------------------------\
1290 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
1291 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1292 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1293
1294 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
1295
1296 \ ------------------------------\
1297 \ Init LCD 2x20                 \
1298 \ ------------------------------\
1299     $03E8 20_US                \ 1-  wait 20 ms
1300     $03 TOP_LCD                \ 2- send DB5=DB4=1
1301     $CD 20_US                  \ 3- wait 4,1 ms
1302     $03 TOP_LCD                \ 4- send again DB5=DB4=1
1303     $5 20_US                   \ 5- wait 0,1 ms
1304     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
1305     $2 20_US                   \    wait 40 us = LCD cycle
1306     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
1307     $2 20_US                   \    wait 40 us = LCD cycle
1308     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
1309     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
1310     LCD_Clear                   \ 10- "LCD_Clear"
1311     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
1312     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
1313     LCD_Clear                   \ 10- "LCD_Clear"
1314     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
1315     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
1316     CR ." I love you"   
1317     ['] (CR) IS CR              \ ' (CR) is CR
1318     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
1319     CR
1320     ."    RC5toLCD is running. Type STOP to quit"
1321 \    NOECHO                      \ uncomment to run this app without terminal connexion
1322     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
1323     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
1324 ;
1325     \
1326
1327 : STOP                  \ stops multitasking, must to be used before downloading app
1328     ['] (WARM) IS WARM  \ remove START app from FORTH init process
1329     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
1330 ;
1331     \
1332
1333
1334 RST_STATE   ;
1335
1336
1337 CODE MAX    \    n1 n2 -- n3       signed maximum
1338             CMP     @PSP,TOS    \ n2-n1
1339             S<      ?GOTO FW1   \ n2<n1
1340 BW1         ADD     #2,PSP
1341             MOV     @IP+,PC
1342 ENDCODE
1343     \
1344
1345 CODE MIN    \    n1 n2 -- n3       signed minimum
1346             CMP     @PSP,TOS     \ n2-n1
1347             S<      ?GOTO BW1    \ n2<n1
1348 FW1         MOV     @PSP+,TOS
1349             MOV     @IP+,PC
1350 ENDCODE
1351     \
1352
1353 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
1354   >R  <# 0 # #S #>  
1355   R> OVER - 0 MAX SPACES TYPE
1356 ;
1357     \
1358
1359 CODE 20_US                      \ n --      n * 20 us
1360 BEGIN                           \ 3 cycles loop + 6~  
1361 \    MOV     #5,W                \ 3 MCLK = 1 MHz
1362 \    MOV     #23,W               \ 3 MCLK = 4 MHz
1363     MOV     #51,W               \ 3 MCLK = 8 MHz
1364 \    MOV     #104,W              \ 3 MCLK = 16 MHz
1365 \    MOV     #158,W              \ 3 MCLK = 24 MHz
1366     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
1367         SUB #1,W                \ 1
1368     0= UNTIL                    \ 2
1369     SUB     #1,TOS              \ 1
1370 0= UNTIL                        \ 2
1371     MOV     @PSP+,TOS           \ 2
1372     MOV     @IP+,PC             \ 4
1373 ENDCODE
1374     \
1375
1376 CODE TOP_LCD                    \ LCD Sample
1377 \                               \ if write : %xxxxWWWW --
1378 \                               \ if read  : -- %0000RRRR
1379     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
1380     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
1381 0= IF                           \ write LCD bits pattern
1382     AND.B #LCD_DB,TOS           \ 
1383     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
1384     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
1385     MOV @PSP+,TOS               \
1386     MOV @IP+,PC
1387 THEN                            \ read LCD bits pattern
1388     SUB #2,PSP
1389     MOV TOS,0(PSP)
1390     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
1391     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
1392     AND.B #LCD_DB,TOS           \
1393     MOV @IP+,PC
1394 ENDCODE
1395     \
1396
1397 CODE LCD_W                      \ byte --       write byte to LCD 
1398     SUB #2,PSP                  \
1399     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
1400     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
1401     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
1402     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
1403 COLON                           \ high level word starts here 
1404     TOP_LCD 2 20_US             \ write high nibble first
1405     TOP_LCD 2 20_US 
1406 ;
1407     \
1408
1409 CODE LCD_WrC                    \ char --         Write Char
1410     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
1411     JMP LCD_W 
1412 ENDCODE
1413     \
1414
1415 CODE LCD_WrF                    \ func --         Write Fonction
1416     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
1417     JMP LCD_W 
1418 ENDCODE
1419     \
1420
1421 : LCD_Clear 
1422     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
1423 ;
1424     \
1425
1426 : LCD_Home 
1427     $02 LCD_WrF 100 20_us 
1428 ;
1429     \
1430
1431 \ : LCD_Entry_set       $04 OR LCD_WrF ;
1432
1433 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
1434
1435 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
1436
1437 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
1438
1439 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
1440
1441 \ : LCD_Goto            $80 OR LCD_WrF ;
1442
1443 \ CODE LCD_R                      \ -- byte       read byte from LCD
1444 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
1445 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
1446 \ COLON                           \ starts a FORTH word
1447 \     TOP_LCD 2 20_us             \ -- %0000HHHH
1448 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
1449 \ HI2LO                           \ switch from FORTH to assembler
1450 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
1451 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
1452 \     MOV @RSP+,IP                \ restore IP saved by COLON
1453 \     MOV @IP+,PC                 \
1454 \ ENDCODE
1455 \     \
1456
1457 \ CODE LCD_RdS                    \ -- status       Read Status
1458 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
1459 \     JMP LCD_R
1460 \ ENDCODE
1461 \     \
1462
1463 \ CODE LCD_RdC                    \ -- char         Read Char
1464 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
1465 \     JMP LCD_R
1466 \ ENDCODE
1467 \     \
1468
1469 \ -------------+------+------+------+------++---+---+---+---+---------+
1470 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
1471 \ -------------+------+------+------+------++---+---+---+---+---------+
1472 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
1473 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
1474 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
1475 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
1476 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
1477 \ -------------+------+------+------+------++---+---+---+---+---------+
1478
1479
1480 \ ******************************\
1481 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
1482 \ ******************************\
1483 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
1484 \ ------------------------------\
1485 \ define LPM mode for ACCEPT    \
1486 \ ------------------------------\
1487 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
1488 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1489 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1490 BIT.B #SW2,&SW2_IN              \ test switch S2
1491 0= IF                           \ case of switch S2 pressed
1492     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
1493     U< IF
1494         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
1495     THEN
1496 ELSE
1497     BIT.B #SW1,&SW1_IN          \ test switch S1 input
1498     0= IF                       \ case of Switch S1 pressed
1499         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
1500         U>= IF                  \
1501             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
1502         THEN                    \
1503     THEN                        \
1504 THEN                            \
1505 RETI                            \ CPU is ON, GIE is OFF
1506 ENDASM                          \
1507     \
1508
1509
1510 \ ------------------------------\
1511 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
1512 \ ******************************\
1513 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
1514 \ ******************************\
1515 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
1516 \                               \       SMclock = 8|16|24 MHz
1517 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
1518 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
1519 \                               \       SR(9)=new Toggle bit memory (ADD on)
1520 \ ------------------------------\
1521 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
1522 \ ------------------------------\
1523 \ define LPM mode for ACCEPT    \
1524 \ ------------------------------\
1525 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
1526 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1527 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1528 \ ------------------------------\
1529 \ RC5_FirstStartBitHalfCycle:   \
1530 \ ------------------------------\
1531 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
1532 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
1533 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
1534 MOV     #1778,X                 \ RC5_Period in us
1535 MOV     #14,W                   \ count of loop
1536 BEGIN                           \
1537 \ ------------------------------\
1538 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
1539 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
1540     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
1541 \ RC5_Compute_3/4_Period:       \                   |
1542     RRUM    #1,X                \ X=1/2 cycle       |
1543     MOV     X,Y                 \ Y=1/2             ^
1544     RRUM    #1,Y                \ Y=1/4
1545     ADD     X,Y                 \ Y=3/4
1546 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
1547     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
1548     0= UNTIL                    \
1549 \ ------------------------------\
1550 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
1551 \ ------------------------------\
1552     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
1553     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
1554     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
1555     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
1556     SUB     #1,W                \ decrement count loop
1557 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
1558 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
1559 0<> WHILE                       \ ----> out of loop ----+
1560 \ RC5_compute_7/4_Time_out:     \                       |
1561     ADD     X,Y                 \                       |   out of bound = 7/4 period 
1562 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
1563     BEGIN                       \                       |
1564         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
1565         0>= IF                  \                       |   if cycle time out of bound
1566             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
1567             RETI                \                       |   then quit to do nothing
1568         THEN                    \                       |
1569 \ ------------------------------\                       |
1570         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
1571     0<> UNTIL                   \                   |   |
1572     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
1573 REPEAT                          \ ----> loop back --+   |
1574 \ ------------------------------\                       |
1575 \ RC5_SampleEndOf:              \ <---------------------+
1576 \ ------------------------------\
1577 BIC     #$30,&TA0CTL           \ stop timer_A0
1578 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
1579 \ ******************************\
1580 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
1581 \ ******************************\
1582 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
1583 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
1584 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
1585 BIT     #BIT13,X                \ X(13) = New_RC5_command
1586 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
1587 THEN                            \
1588 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
1589 \ ******************************\
1590 \ RC5_ComputeNewRC5word         \
1591 \ ******************************\
1592 SUB     #4,PSP                  \
1593 MOV     &BASE,2(PSP)            \ save variable BASE before use
1594 MOV     TOS,0(PSP)              \ save TOS before use
1595 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
1596 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
1597 \ ******************************\
1598 \ RC5_ComputeC6bit              \
1599 \ ******************************\
1600 BIT     #$4000,IP              \ test /C6 bit in IP
1601 0= IF   BIS #$40,TOS           \ set C6 bit in S
1602 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
1603 \ ******************************\
1604 \ RC5_CommandByteIsDone         \ RC5_code --
1605 \ ******************************\
1606
1607 \ ------------------------------\
1608 \ Display IR_RC5 code           \
1609 \ ------------------------------\
1610 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
1611 \ ------------------------------\
1612 LO2HI                           \ switch from assembler to FORTH
1613     ['] LCD_CLEAR IS CR         \ redirects CR
1614     ['] LCD_WrC  IS EMIT        \ redirects EMIT
1615     $10 BASE !                 \ change BASE to hexadecimal
1616     CR ." $" 2 U.R             \ print IR_RC5 code
1617     ['] (CR) IS CR              \ restore CR
1618     ['] (EMIT) IS EMIT          \ restore EMIT
1619 HI2LO                           \ switch from FORTH to assembler
1620 \ ------------------------------\
1621 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
1622 \ ------------------------------\
1623 MOV @PSP+,&BASE                 \ restore variable BASE
1624 RETI                            \ CPU is ON, GIE is OFF
1625 ENDASM                          \
1626     \ 
1627
1628 CODE START                      \
1629 \ ------------------------------\
1630 \ TB0CTL = %0000 0010 1001 0100\$3C0
1631 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
1632 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
1633 \                      --       \ID input divider \ 10 = /4
1634 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
1635 \                            -  \TBCLR TimerB Clear
1636 \                             - \TBIE
1637 \                              -\TBIFG
1638 \ --------------------------------\\
1639 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
1640 \              --                 \CM Capture Mode
1641 \                --               \CCIS
1642 \                   -             \SCS
1643 \                    --           \CLLD
1644 \                      -          \CAP
1645 \                        ---      \OUTMOD \ 011 = set/reset
1646 \                           -     \CCIE
1647 \                             -   \CCI
1648 \                              -  \OUT
1649 \                               - \COV
1650 \                                -\CCIFG
1651 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
1652 \ TB0EX0                          \$3E0 
1653 \ ------------------------------\
1654 \ set TimerB to make 50kHz PWM  \
1655 \ ------------------------------\
1656 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
1657 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
1658 \ ------------------------------\
1659 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
1660 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
1661 \ ------------------------------\
1662     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
1663     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
1664 \ ------------------------------\
1665 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
1666 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
1667 \ ------------------------------\
1668 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
1669 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
1670 \ ------------------------------\
1671     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
1672 \ ------------------------------\
1673 \ set TimerB to generate PWM for LCD_Vo
1674 \ ------------------------------\
1675     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
1676 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
1677     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
1678 \ ------------------------------\
1679     BIS.B #LCDVo,&LCDVo_DIR     \
1680     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
1681 \ ------------------------------\
1682     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
1683     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
1684 \ ------------------------------\
1685     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
1686     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
1687 \ ------------------------------\
1688 \ WDT interval init part        \
1689 \ ------------------------------\
1690     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
1691 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
1692 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
1693     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
1694 \ ------------------------------\
1695 \ init RC5_Int                  \
1696 \ ------------------------------\
1697     BIS.B #RC5,&IR_IE           \ enable RC5_Int
1698     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
1699 \ ------------------------------\
1700 \ init interrupt vectors
1701 \ ------------------------------\
1702     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
1703     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
1704 \ ------------------------------\
1705 \ define LPM mode for ACCEPT    \
1706 \ ------------------------------\
1707 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
1708 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1709 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1710
1711 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
1712
1713 \ ------------------------------\
1714 \ Init LCD 2x20                 \
1715 \ ------------------------------\
1716     $03E8 20_US                \ 1-  wait 20 ms
1717     $03 TOP_LCD                \ 2- send DB5=DB4=1
1718     $CD 20_US                  \ 3- wait 4,1 ms
1719     $03 TOP_LCD                \ 4- send again DB5=DB4=1
1720     $5 20_US                   \ 5- wait 0,1 ms
1721     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
1722     $2 20_US                   \    wait 40 us = LCD cycle
1723     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
1724     $2 20_US                   \    wait 40 us = LCD cycle
1725     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
1726     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
1727     LCD_Clear                   \ 10- "LCD_Clear"
1728     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
1729     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
1730     LCD_Clear                   \ 10- "LCD_Clear"
1731     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
1732     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
1733     CR ." I love you"   
1734     ['] (CR) IS CR              \ ' (CR) is CR
1735     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
1736     CR
1737     ."    RC5toLCD is running. Type STOP to quit"
1738 \    NOECHO                      \ uncomment to run this app without terminal connexion
1739     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
1740     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
1741 ;
1742     \
1743
1744 : STOP                  \ stops multitasking, must to be used before downloading app
1745     ['] (WARM) IS WARM  \ remove START app from FORTH init process
1746     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
1747 ;
1748     \
1749
1750
1751 RST_STATE   ;
1752
1753
1754 CODE MAX    \    n1 n2 -- n3       signed maximum
1755             CMP     @PSP,TOS    \ n2-n1
1756             S<      ?GOTO FW1   \ n2<n1
1757 BW1         ADD     #2,PSP
1758             MOV     @IP+,PC
1759 ENDCODE
1760     \
1761
1762 CODE MIN    \    n1 n2 -- n3       signed minimum
1763             CMP     @PSP,TOS     \ n2-n1
1764             S<      ?GOTO BW1    \ n2<n1
1765 FW1         MOV     @PSP+,TOS
1766             MOV     @IP+,PC
1767 ENDCODE
1768     \
1769
1770 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
1771   >R  <# 0 # #S #>  
1772   R> OVER - 0 MAX SPACES TYPE
1773 ;
1774     \
1775
1776 CODE 20_US                      \ n --      n * 20 us
1777 BEGIN                           \ 3 cycles loop + 6~  
1778 \    MOV     #5,W                \ 3 MCLK = 1 MHz
1779 \    MOV     #23,W               \ 3 MCLK = 4 MHz
1780     MOV     #51,W               \ 3 MCLK = 8 MHz
1781 \    MOV     #104,W              \ 3 MCLK = 16 MHz
1782 \    MOV     #158,W              \ 3 MCLK = 24 MHz
1783     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
1784         SUB #1,W                \ 1
1785     0= UNTIL                    \ 2
1786     SUB     #1,TOS              \ 1
1787 0= UNTIL                        \ 2
1788     MOV     @PSP+,TOS           \ 2
1789     MOV     @IP+,PC             \ 4
1790 ENDCODE
1791     \
1792
1793 CODE TOP_LCD                    \ LCD Sample
1794 \                               \ if write : %xxxxWWWW --
1795 \                               \ if read  : -- %0000RRRR
1796     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
1797     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
1798 0= IF                           \ write LCD bits pattern
1799     AND.B #LCD_DB,TOS           \ 
1800     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
1801     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
1802     MOV @PSP+,TOS               \
1803     MOV @IP+,PC
1804 THEN                            \ read LCD bits pattern
1805     SUB #2,PSP
1806     MOV TOS,0(PSP)
1807     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
1808     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
1809     AND.B #LCD_DB,TOS           \
1810     MOV @IP+,PC
1811 ENDCODE
1812     \
1813
1814 CODE LCD_W                      \ byte --       write byte to LCD 
1815     SUB #2,PSP                  \
1816     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
1817     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
1818     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
1819     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
1820 COLON                           \ high level word starts here 
1821     TOP_LCD 2 20_US             \ write high nibble first
1822     TOP_LCD 2 20_US 
1823 ;
1824     \
1825
1826 CODE LCD_WrC                    \ char --         Write Char
1827     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
1828     JMP LCD_W 
1829 ENDCODE
1830     \
1831
1832 CODE LCD_WrF                    \ func --         Write Fonction
1833     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
1834     JMP LCD_W 
1835 ENDCODE
1836     \
1837
1838 : LCD_Clear 
1839     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
1840 ;
1841     \
1842
1843 : LCD_Home 
1844     $02 LCD_WrF 100 20_us 
1845 ;
1846     \
1847
1848 \ : LCD_Entry_set       $04 OR LCD_WrF ;
1849
1850 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
1851
1852 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
1853
1854 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
1855
1856 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
1857
1858 \ : LCD_Goto            $80 OR LCD_WrF ;
1859
1860 \ CODE LCD_R                      \ -- byte       read byte from LCD
1861 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
1862 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
1863 \ COLON                           \ starts a FORTH word
1864 \     TOP_LCD 2 20_us             \ -- %0000HHHH
1865 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
1866 \ HI2LO                           \ switch from FORTH to assembler
1867 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
1868 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
1869 \     MOV @RSP+,IP                \ restore IP saved by COLON
1870 \     MOV @IP+,PC                 \
1871 \ ENDCODE
1872 \     \
1873
1874 \ CODE LCD_RdS                    \ -- status       Read Status
1875 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
1876 \     JMP LCD_R
1877 \ ENDCODE
1878 \     \
1879
1880 \ CODE LCD_RdC                    \ -- char         Read Char
1881 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
1882 \     JMP LCD_R
1883 \ ENDCODE
1884 \     \
1885
1886 \ -------------+------+------+------+------++---+---+---+---+---------+
1887 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
1888 \ -------------+------+------+------+------++---+---+---+---+---------+
1889 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
1890 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
1891 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
1892 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
1893 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
1894 \ -------------+------+------+------+------++---+---+---+---+---------+
1895
1896
1897 \ ******************************\
1898 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
1899 \ ******************************\
1900 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
1901 \ ------------------------------\
1902 \ define LPM mode for ACCEPT    \
1903 \ ------------------------------\
1904 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
1905 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1906 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1907 BIT.B #SW2,&SW2_IN              \ test switch S2
1908 0= IF                           \ case of switch S2 pressed
1909     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
1910     U< IF
1911         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
1912     THEN
1913 ELSE
1914     BIT.B #SW1,&SW1_IN          \ test switch S1 input
1915     0= IF                       \ case of Switch S1 pressed
1916         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
1917         U>= IF                  \
1918             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
1919         THEN                    \
1920     THEN                        \
1921 THEN                            \
1922 RETI                            \ CPU is ON, GIE is OFF
1923 ENDASM                          \
1924     \
1925
1926
1927 \ ------------------------------\
1928 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
1929 \ ******************************\
1930 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
1931 \ ******************************\
1932 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
1933 \                               \       SMclock = 8|16|24 MHz
1934 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
1935 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
1936 \                               \       SR(9)=new Toggle bit memory (ADD on)
1937 \ ------------------------------\
1938 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
1939 \ ------------------------------\
1940 \ define LPM mode for ACCEPT    \
1941 \ ------------------------------\
1942 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
1943 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1944 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1945 \ ------------------------------\
1946 \ RC5_FirstStartBitHalfCycle:   \
1947 \ ------------------------------\
1948 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
1949 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
1950 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
1951 MOV     #1778,X                 \ RC5_Period in us
1952 MOV     #14,W                   \ count of loop
1953 BEGIN                           \
1954 \ ------------------------------\
1955 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
1956 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
1957     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
1958 \ RC5_Compute_3/4_Period:       \                   |
1959     RRUM    #1,X                \ X=1/2 cycle       |
1960     MOV     X,Y                 \ Y=1/2             ^
1961     RRUM    #1,Y                \ Y=1/4
1962     ADD     X,Y                 \ Y=3/4
1963 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
1964     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
1965     0= UNTIL                    \
1966 \ ------------------------------\
1967 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
1968 \ ------------------------------\
1969     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
1970     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
1971     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
1972     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
1973     SUB     #1,W                \ decrement count loop
1974 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
1975 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
1976 0<> WHILE                       \ ----> out of loop ----+
1977 \ RC5_compute_7/4_Time_out:     \                       |
1978     ADD     X,Y                 \                       |   out of bound = 7/4 period 
1979 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
1980     BEGIN                       \                       |
1981         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
1982         0>= IF                  \                       |   if cycle time out of bound
1983             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
1984             RETI                \                       |   then quit to do nothing
1985         THEN                    \                       |
1986 \ ------------------------------\                       |
1987         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
1988     0<> UNTIL                   \                   |   |
1989     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
1990 REPEAT                          \ ----> loop back --+   |
1991 \ ------------------------------\                       |
1992 \ RC5_SampleEndOf:              \ <---------------------+
1993 \ ------------------------------\
1994 BIC     #$30,&TA0CTL           \ stop timer_A0
1995 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
1996 \ ******************************\
1997 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
1998 \ ******************************\
1999 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
2000 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
2001 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
2002 BIT     #BIT13,X                \ X(13) = New_RC5_command
2003 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
2004 THEN                            \
2005 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
2006 \ ******************************\
2007 \ RC5_ComputeNewRC5word         \
2008 \ ******************************\
2009 SUB     #4,PSP                  \
2010 MOV     &BASE,2(PSP)            \ save variable BASE before use
2011 MOV     TOS,0(PSP)              \ save TOS before use
2012 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
2013 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
2014 \ ******************************\
2015 \ RC5_ComputeC6bit              \
2016 \ ******************************\
2017 BIT     #$4000,IP              \ test /C6 bit in IP
2018 0= IF   BIS #$40,TOS           \ set C6 bit in S
2019 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
2020 \ ******************************\
2021 \ RC5_CommandByteIsDone         \ RC5_code --
2022 \ ******************************\
2023
2024 \ ------------------------------\
2025 \ Display IR_RC5 code           \
2026 \ ------------------------------\
2027 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
2028 \ ------------------------------\
2029 LO2HI                           \ switch from assembler to FORTH
2030     ['] LCD_CLEAR IS CR         \ redirects CR
2031     ['] LCD_WrC  IS EMIT        \ redirects EMIT
2032     $10 BASE !                 \ change BASE to hexadecimal
2033     CR ." $" 2 U.R             \ print IR_RC5 code
2034     ['] (CR) IS CR              \ restore CR
2035     ['] (EMIT) IS EMIT          \ restore EMIT
2036 HI2LO                           \ switch from FORTH to assembler
2037 \ ------------------------------\
2038 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
2039 \ ------------------------------\
2040 MOV @PSP+,&BASE                 \ restore variable BASE
2041 RETI                            \ CPU is ON, GIE is OFF
2042 ENDASM                          \
2043     \ 
2044
2045 CODE START                      \
2046 \ ------------------------------\
2047 \ TB0CTL = %0000 0010 1001 0100\$3C0
2048 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
2049 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
2050 \                      --       \ID input divider \ 10 = /4
2051 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
2052 \                            -  \TBCLR TimerB Clear
2053 \                             - \TBIE
2054 \                              -\TBIFG
2055 \ --------------------------------\\
2056 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
2057 \              --                 \CM Capture Mode
2058 \                --               \CCIS
2059 \                   -             \SCS
2060 \                    --           \CLLD
2061 \                      -          \CAP
2062 \                        ---      \OUTMOD \ 011 = set/reset
2063 \                           -     \CCIE
2064 \                             -   \CCI
2065 \                              -  \OUT
2066 \                               - \COV
2067 \                                -\CCIFG
2068 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
2069 \ TB0EX0                          \$3E0 
2070 \ ------------------------------\
2071 \ set TimerB to make 50kHz PWM  \
2072 \ ------------------------------\
2073 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
2074 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
2075 \ ------------------------------\
2076 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
2077 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
2078 \ ------------------------------\
2079     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
2080     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
2081 \ ------------------------------\
2082 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
2083 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
2084 \ ------------------------------\
2085 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
2086 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
2087 \ ------------------------------\
2088     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
2089 \ ------------------------------\
2090 \ set TimerB to generate PWM for LCD_Vo
2091 \ ------------------------------\
2092     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
2093 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
2094     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
2095 \ ------------------------------\
2096     BIS.B #LCDVo,&LCDVo_DIR     \
2097     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
2098 \ ------------------------------\
2099     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
2100     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
2101 \ ------------------------------\
2102     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
2103     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
2104 \ ------------------------------\
2105 \ WDT interval init part        \
2106 \ ------------------------------\
2107     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
2108 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
2109 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
2110     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
2111 \ ------------------------------\
2112 \ init RC5_Int                  \
2113 \ ------------------------------\
2114     BIS.B #RC5,&IR_IE           \ enable RC5_Int
2115     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
2116 \ ------------------------------\
2117 \ init interrupt vectors
2118 \ ------------------------------\
2119     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
2120     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
2121 \ ------------------------------\
2122 \ define LPM mode for ACCEPT    \
2123 \ ------------------------------\
2124 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
2125 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
2126 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
2127
2128 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
2129
2130 \ ------------------------------\
2131 \ Init LCD 2x20                 \
2132 \ ------------------------------\
2133     $03E8 20_US                \ 1-  wait 20 ms
2134     $03 TOP_LCD                \ 2- send DB5=DB4=1
2135     $CD 20_US                  \ 3- wait 4,1 ms
2136     $03 TOP_LCD                \ 4- send again DB5=DB4=1
2137     $5 20_US                   \ 5- wait 0,1 ms
2138     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
2139     $2 20_US                   \    wait 40 us = LCD cycle
2140     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
2141     $2 20_US                   \    wait 40 us = LCD cycle
2142     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
2143     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
2144     LCD_Clear                   \ 10- "LCD_Clear"
2145     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
2146     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
2147     LCD_Clear                   \ 10- "LCD_Clear"
2148     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
2149     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
2150     CR ." I love you"   
2151     ['] (CR) IS CR              \ ' (CR) is CR
2152     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
2153     CR
2154     ."    RC5toLCD is running. Type STOP to quit"
2155 \    NOECHO                      \ uncomment to run this app without terminal connexion
2156     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
2157     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
2158 ;
2159     \
2160
2161 : STOP                  \ stops multitasking, must to be used before downloading app
2162     ['] (WARM) IS WARM  \ remove START app from FORTH init process
2163     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
2164 ;
2165     \
2166
2167
2168 RST_STATE   ;
2169
2170
2171 CODE MAX    \    n1 n2 -- n3       signed maximum
2172             CMP     @PSP,TOS    \ n2-n1
2173             S<      ?GOTO FW1   \ n2<n1
2174 BW1         ADD     #2,PSP
2175             MOV     @IP+,PC
2176 ENDCODE
2177     \
2178
2179 CODE MIN    \    n1 n2 -- n3       signed minimum
2180             CMP     @PSP,TOS     \ n2-n1
2181             S<      ?GOTO BW1    \ n2<n1
2182 FW1         MOV     @PSP+,TOS
2183             MOV     @IP+,PC
2184 ENDCODE
2185     \
2186
2187 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
2188   >R  <# 0 # #S #>  
2189   R> OVER - 0 MAX SPACES TYPE
2190 ;
2191     \
2192
2193 CODE 20_US                      \ n --      n * 20 us
2194 BEGIN                           \ 3 cycles loop + 6~  
2195 \    MOV     #5,W                \ 3 MCLK = 1 MHz
2196 \    MOV     #23,W               \ 3 MCLK = 4 MHz
2197     MOV     #51,W               \ 3 MCLK = 8 MHz
2198 \    MOV     #104,W              \ 3 MCLK = 16 MHz
2199 \    MOV     #158,W              \ 3 MCLK = 24 MHz
2200     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
2201         SUB #1,W                \ 1
2202     0= UNTIL                    \ 2
2203     SUB     #1,TOS              \ 1
2204 0= UNTIL                        \ 2
2205     MOV     @PSP+,TOS           \ 2
2206     MOV     @IP+,PC             \ 4
2207 ENDCODE
2208     \
2209
2210 CODE TOP_LCD                    \ LCD Sample
2211 \                               \ if write : %xxxxWWWW --
2212 \                               \ if read  : -- %0000RRRR
2213     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
2214     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
2215 0= IF                           \ write LCD bits pattern
2216     AND.B #LCD_DB,TOS           \ 
2217     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
2218     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
2219     MOV @PSP+,TOS               \
2220     MOV @IP+,PC
2221 THEN                            \ read LCD bits pattern
2222     SUB #2,PSP
2223     MOV TOS,0(PSP)
2224     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
2225     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
2226     AND.B #LCD_DB,TOS           \
2227     MOV @IP+,PC
2228 ENDCODE
2229     \
2230
2231 CODE LCD_W                      \ byte --       write byte to LCD 
2232     SUB #2,PSP                  \
2233     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
2234     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
2235     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
2236     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
2237 COLON                           \ high level word starts here 
2238     TOP_LCD 2 20_US             \ write high nibble first
2239     TOP_LCD 2 20_US 
2240 ;
2241     \
2242
2243 CODE LCD_WrC                    \ char --         Write Char
2244     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
2245     JMP LCD_W 
2246 ENDCODE
2247     \
2248
2249 CODE LCD_WrF                    \ func --         Write Fonction
2250     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
2251     JMP LCD_W 
2252 ENDCODE
2253     \
2254
2255 : LCD_Clear 
2256     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
2257 ;
2258     \
2259
2260 : LCD_Home 
2261     $02 LCD_WrF 100 20_us 
2262 ;
2263     \
2264
2265 \ : LCD_Entry_set       $04 OR LCD_WrF ;
2266
2267 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
2268
2269 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
2270
2271 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
2272
2273 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
2274
2275 \ : LCD_Goto            $80 OR LCD_WrF ;
2276
2277 \ CODE LCD_R                      \ -- byte       read byte from LCD
2278 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
2279 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
2280 \ COLON                           \ starts a FORTH word
2281 \     TOP_LCD 2 20_us             \ -- %0000HHHH
2282 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
2283 \ HI2LO                           \ switch from FORTH to assembler
2284 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
2285 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
2286 \     MOV @RSP+,IP                \ restore IP saved by COLON
2287 \     MOV @IP+,PC                 \
2288 \ ENDCODE
2289 \     \
2290
2291 \ CODE LCD_RdS                    \ -- status       Read Status
2292 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
2293 \     JMP LCD_R
2294 \ ENDCODE
2295 \     \
2296
2297 \ CODE LCD_RdC                    \ -- char         Read Char
2298 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
2299 \     JMP LCD_R
2300 \ ENDCODE
2301 \     \
2302
2303 \ -------------+------+------+------+------++---+---+---+---+---------+
2304 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
2305 \ -------------+------+------+------+------++---+---+---+---+---------+
2306 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
2307 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
2308 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
2309 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
2310 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
2311 \ -------------+------+------+------+------++---+---+---+---+---------+
2312
2313
2314 \ ******************************\
2315 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
2316 \ ******************************\
2317 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
2318 \ ------------------------------\
2319 \ define LPM mode for ACCEPT    \
2320 \ ------------------------------\
2321 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
2322 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
2323 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
2324 BIT.B #SW2,&SW2_IN              \ test switch S2
2325 0= IF                           \ case of switch S2 pressed
2326     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
2327     U< IF
2328         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
2329     THEN
2330 ELSE
2331     BIT.B #SW1,&SW1_IN          \ test switch S1 input
2332     0= IF                       \ case of Switch S1 pressed
2333         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
2334         U>= IF                  \
2335             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
2336         THEN                    \
2337     THEN                        \
2338 THEN                            \
2339 RETI                            \ CPU is ON, GIE is OFF
2340 ENDASM                          \
2341     \
2342
2343
2344 \ ------------------------------\
2345 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
2346 \ ******************************\
2347 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
2348 \ ******************************\
2349 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
2350 \                               \       SMclock = 8|16|24 MHz
2351 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
2352 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
2353 \                               \       SR(9)=new Toggle bit memory (ADD on)
2354 \ ------------------------------\
2355 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
2356 \ ------------------------------\
2357 \ define LPM mode for ACCEPT    \
2358 \ ------------------------------\
2359 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
2360 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
2361 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
2362 \ ------------------------------\
2363 \ RC5_FirstStartBitHalfCycle:   \
2364 \ ------------------------------\
2365 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
2366 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
2367 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
2368 MOV     #1778,X                 \ RC5_Period in us
2369 MOV     #14,W                   \ count of loop
2370 BEGIN                           \
2371 \ ------------------------------\
2372 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
2373 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
2374     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
2375 \ RC5_Compute_3/4_Period:       \                   |
2376     RRUM    #1,X                \ X=1/2 cycle       |
2377     MOV     X,Y                 \ Y=1/2             ^
2378     RRUM    #1,Y                \ Y=1/4
2379     ADD     X,Y                 \ Y=3/4
2380 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
2381     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
2382     0= UNTIL                    \
2383 \ ------------------------------\
2384 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
2385 \ ------------------------------\
2386     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
2387     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
2388     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
2389     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
2390     SUB     #1,W                \ decrement count loop
2391 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
2392 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
2393 0<> WHILE                       \ ----> out of loop ----+
2394 \ RC5_compute_7/4_Time_out:     \                       |
2395     ADD     X,Y                 \                       |   out of bound = 7/4 period 
2396 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
2397     BEGIN                       \                       |
2398         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
2399         0>= IF                  \                       |   if cycle time out of bound
2400             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
2401             RETI                \                       |   then quit to do nothing
2402         THEN                    \                       |
2403 \ ------------------------------\                       |
2404         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
2405     0<> UNTIL                   \                   |   |
2406     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
2407 REPEAT                          \ ----> loop back --+   |
2408 \ ------------------------------\                       |
2409 \ RC5_SampleEndOf:              \ <---------------------+
2410 \ ------------------------------\
2411 BIC     #$30,&TA0CTL           \ stop timer_A0
2412 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
2413 \ ******************************\
2414 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
2415 \ ******************************\
2416 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
2417 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
2418 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
2419 BIT     #BIT13,X                \ X(13) = New_RC5_command
2420 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
2421 THEN                            \
2422 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
2423 \ ******************************\
2424 \ RC5_ComputeNewRC5word         \
2425 \ ******************************\
2426 SUB     #4,PSP                  \
2427 MOV     &BASE,2(PSP)            \ save variable BASE before use
2428 MOV     TOS,0(PSP)              \ save TOS before use
2429 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
2430 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
2431 \ ******************************\
2432 \ RC5_ComputeC6bit              \
2433 \ ******************************\
2434 BIT     #$4000,IP              \ test /C6 bit in IP
2435 0= IF   BIS #$40,TOS           \ set C6 bit in S
2436 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
2437 \ ******************************\
2438 \ RC5_CommandByteIsDone         \ RC5_code --
2439 \ ******************************\
2440
2441 \ ------------------------------\
2442 \ Display IR_RC5 code           \
2443 \ ------------------------------\
2444 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
2445 \ ------------------------------\
2446 LO2HI                           \ switch from assembler to FORTH
2447     ['] LCD_CLEAR IS CR         \ redirects CR
2448     ['] LCD_WrC  IS EMIT        \ redirects EMIT
2449     $10 BASE !                 \ change BASE to hexadecimal
2450     CR ." $" 2 U.R             \ print IR_RC5 code
2451     ['] (CR) IS CR              \ restore CR
2452     ['] (EMIT) IS EMIT          \ restore EMIT
2453 HI2LO                           \ switch from FORTH to assembler
2454 \ ------------------------------\
2455 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
2456 \ ------------------------------\
2457 MOV @PSP+,&BASE                 \ restore variable BASE
2458 RETI                            \ CPU is ON, GIE is OFF
2459 ENDASM                          \
2460     \ 
2461
2462 CODE START                      \
2463 \ ------------------------------\
2464 \ TB0CTL = %0000 0010 1001 0100\$3C0
2465 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
2466 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
2467 \                      --       \ID input divider \ 10 = /4
2468 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
2469 \                            -  \TBCLR TimerB Clear
2470 \                             - \TBIE
2471 \                              -\TBIFG
2472 \ --------------------------------\\
2473 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
2474 \              --                 \CM Capture Mode
2475 \                --               \CCIS
2476 \                   -             \SCS
2477 \                    --           \CLLD
2478 \                      -          \CAP
2479 \                        ---      \OUTMOD \ 011 = set/reset
2480 \                           -     \CCIE
2481 \                             -   \CCI
2482 \                              -  \OUT
2483 \                               - \COV
2484 \                                -\CCIFG
2485 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
2486 \ TB0EX0                          \$3E0 
2487 \ ------------------------------\
2488 \ set TimerB to make 50kHz PWM  \
2489 \ ------------------------------\
2490 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
2491 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
2492 \ ------------------------------\
2493 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
2494 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
2495 \ ------------------------------\
2496     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
2497     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
2498 \ ------------------------------\
2499 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
2500 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
2501 \ ------------------------------\
2502 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
2503 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
2504 \ ------------------------------\
2505     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
2506 \ ------------------------------\
2507 \ set TimerB to generate PWM for LCD_Vo
2508 \ ------------------------------\
2509     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
2510 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
2511     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
2512 \ ------------------------------\
2513     BIS.B #LCDVo,&LCDVo_DIR     \
2514     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
2515 \ ------------------------------\
2516     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
2517     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
2518 \ ------------------------------\
2519     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
2520     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
2521 \ ------------------------------\
2522 \ WDT interval init part        \
2523 \ ------------------------------\
2524     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
2525 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
2526 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
2527     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
2528 \ ------------------------------\
2529 \ init RC5_Int                  \
2530 \ ------------------------------\
2531     BIS.B #RC5,&IR_IE           \ enable RC5_Int
2532     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
2533 \ ------------------------------\
2534 \ init interrupt vectors
2535 \ ------------------------------\
2536     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
2537     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
2538 \ ------------------------------\
2539 \ define LPM mode for ACCEPT    \
2540 \ ------------------------------\
2541 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
2542 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
2543 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
2544
2545 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
2546
2547 \ ------------------------------\
2548 \ Init LCD 2x20                 \
2549 \ ------------------------------\
2550     $03E8 20_US                \ 1-  wait 20 ms
2551     $03 TOP_LCD                \ 2- send DB5=DB4=1
2552     $CD 20_US                  \ 3- wait 4,1 ms
2553     $03 TOP_LCD                \ 4- send again DB5=DB4=1
2554     $5 20_US                   \ 5- wait 0,1 ms
2555     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
2556     $2 20_US                   \    wait 40 us = LCD cycle
2557     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
2558     $2 20_US                   \    wait 40 us = LCD cycle
2559     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
2560     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
2561     LCD_Clear                   \ 10- "LCD_Clear"
2562     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
2563     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
2564     LCD_Clear                   \ 10- "LCD_Clear"
2565     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
2566     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
2567     CR ." I love you"   
2568     ['] (CR) IS CR              \ ' (CR) is CR
2569     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
2570     CR
2571     ."    RC5toLCD is running. Type STOP to quit"
2572 \    NOECHO                      \ uncomment to run this app without terminal connexion
2573     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
2574     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
2575 ;
2576     \
2577
2578 : STOP                  \ stops multitasking, must to be used before downloading app
2579     ['] (WARM) IS WARM  \ remove START app from FORTH init process
2580     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
2581 ;
2582     \
2583
2584
2585 RST_STATE   ;
2586
2587
2588 CODE MAX    \    n1 n2 -- n3       signed maximum
2589             CMP     @PSP,TOS    \ n2-n1
2590             S<      ?GOTO FW1   \ n2<n1
2591 BW1         ADD     #2,PSP
2592             MOV     @IP+,PC
2593 ENDCODE
2594     \
2595
2596 CODE MIN    \    n1 n2 -- n3       signed minimum
2597             CMP     @PSP,TOS     \ n2-n1
2598             S<      ?GOTO BW1    \ n2<n1
2599 FW1         MOV     @PSP+,TOS
2600             MOV     @IP+,PC
2601 ENDCODE
2602     \
2603
2604 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
2605   >R  <# 0 # #S #>  
2606   R> OVER - 0 MAX SPACES TYPE
2607 ;
2608     \
2609
2610 CODE 20_US                      \ n --      n * 20 us
2611 BEGIN                           \ 3 cycles loop + 6~  
2612 \    MOV     #5,W                \ 3 MCLK = 1 MHz
2613 \    MOV     #23,W               \ 3 MCLK = 4 MHz
2614     MOV     #51,W               \ 3 MCLK = 8 MHz
2615 \    MOV     #104,W              \ 3 MCLK = 16 MHz
2616 \    MOV     #158,W              \ 3 MCLK = 24 MHz
2617     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
2618         SUB #1,W                \ 1
2619     0= UNTIL                    \ 2
2620     SUB     #1,TOS              \ 1
2621 0= UNTIL                        \ 2
2622     MOV     @PSP+,TOS           \ 2
2623     MOV     @IP+,PC             \ 4
2624 ENDCODE
2625     \
2626
2627 CODE TOP_LCD                    \ LCD Sample
2628 \                               \ if write : %xxxxWWWW --
2629 \                               \ if read  : -- %0000RRRR
2630     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
2631     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
2632 0= IF                           \ write LCD bits pattern
2633     AND.B #LCD_DB,TOS           \ 
2634     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
2635     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
2636     MOV @PSP+,TOS               \
2637     MOV @IP+,PC
2638 THEN                            \ read LCD bits pattern
2639     SUB #2,PSP
2640     MOV TOS,0(PSP)
2641     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
2642     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
2643     AND.B #LCD_DB,TOS           \
2644     MOV @IP+,PC
2645 ENDCODE
2646     \
2647
2648 CODE LCD_W                      \ byte --       write byte to LCD 
2649     SUB #2,PSP                  \
2650     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
2651     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
2652     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
2653     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
2654 COLON                           \ high level word starts here 
2655     TOP_LCD 2 20_US             \ write high nibble first
2656     TOP_LCD 2 20_US 
2657 ;
2658     \
2659
2660 CODE LCD_WrC                    \ char --         Write Char
2661     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
2662     JMP LCD_W 
2663 ENDCODE
2664     \
2665
2666 CODE LCD_WrF                    \ func --         Write Fonction
2667     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
2668     JMP LCD_W 
2669 ENDCODE
2670     \
2671
2672 : LCD_Clear 
2673     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
2674 ;
2675     \
2676
2677 : LCD_Home 
2678     $02 LCD_WrF 100 20_us 
2679 ;
2680     \
2681
2682 \ : LCD_Entry_set       $04 OR LCD_WrF ;
2683
2684 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
2685
2686 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
2687
2688 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
2689
2690 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
2691
2692 \ : LCD_Goto            $80 OR LCD_WrF ;
2693
2694 \ CODE LCD_R                      \ -- byte       read byte from LCD
2695 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
2696 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
2697 \ COLON                           \ starts a FORTH word
2698 \     TOP_LCD 2 20_us             \ -- %0000HHHH
2699 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
2700 \ HI2LO                           \ switch from FORTH to assembler
2701 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
2702 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
2703 \     MOV @RSP+,IP                \ restore IP saved by COLON
2704 \     MOV @IP+,PC                 \
2705 \ ENDCODE
2706 \     \
2707
2708 \ CODE LCD_RdS                    \ -- status       Read Status
2709 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
2710 \     JMP LCD_R
2711 \ ENDCODE
2712 \     \
2713
2714 \ CODE LCD_RdC                    \ -- char         Read Char
2715 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
2716 \     JMP LCD_R
2717 \ ENDCODE
2718 \     \
2719
2720 \ -------------+------+------+------+------++---+---+---+---+---------+
2721 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
2722 \ -------------+------+------+------+------++---+---+---+---+---------+
2723 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
2724 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
2725 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
2726 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
2727 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
2728 \ -------------+------+------+------+------++---+---+---+---+---------+
2729
2730
2731 \ ******************************\
2732 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
2733 \ ******************************\
2734 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
2735 \ ------------------------------\
2736 \ define LPM mode for ACCEPT    \
2737 \ ------------------------------\
2738 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
2739 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
2740 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
2741 BIT.B #SW2,&SW2_IN              \ test switch S2
2742 0= IF                           \ case of switch S2 pressed
2743     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
2744     U< IF
2745         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
2746     THEN
2747 ELSE
2748     BIT.B #SW1,&SW1_IN          \ test switch S1 input
2749     0= IF                       \ case of Switch S1 pressed
2750         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
2751         U>= IF                  \
2752             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
2753         THEN                    \
2754     THEN                        \
2755 THEN                            \
2756 RETI                            \ CPU is ON, GIE is OFF
2757 ENDASM                          \
2758     \
2759
2760
2761 \ ------------------------------\
2762 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
2763 \ ******************************\
2764 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
2765 \ ******************************\
2766 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
2767 \                               \       SMclock = 8|16|24 MHz
2768 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
2769 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
2770 \                               \       SR(9)=new Toggle bit memory (ADD on)
2771 \ ------------------------------\
2772 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
2773 \ ------------------------------\
2774 \ define LPM mode for ACCEPT    \
2775 \ ------------------------------\
2776 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
2777 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
2778 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
2779 \ ------------------------------\
2780 \ RC5_FirstStartBitHalfCycle:   \
2781 \ ------------------------------\
2782 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
2783 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
2784 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
2785 MOV     #1778,X                 \ RC5_Period in us
2786 MOV     #14,W                   \ count of loop
2787 BEGIN                           \
2788 \ ------------------------------\
2789 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
2790 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
2791     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
2792 \ RC5_Compute_3/4_Period:       \                   |
2793     RRUM    #1,X                \ X=1/2 cycle       |
2794     MOV     X,Y                 \ Y=1/2             ^
2795     RRUM    #1,Y                \ Y=1/4
2796     ADD     X,Y                 \ Y=3/4
2797 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
2798     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
2799     0= UNTIL                    \
2800 \ ------------------------------\
2801 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
2802 \ ------------------------------\
2803     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
2804     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
2805     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
2806     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
2807     SUB     #1,W                \ decrement count loop
2808 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
2809 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
2810 0<> WHILE                       \ ----> out of loop ----+
2811 \ RC5_compute_7/4_Time_out:     \                       |
2812     ADD     X,Y                 \                       |   out of bound = 7/4 period 
2813 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
2814     BEGIN                       \                       |
2815         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
2816         0>= IF                  \                       |   if cycle time out of bound
2817             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
2818             RETI                \                       |   then quit to do nothing
2819         THEN                    \                       |
2820 \ ------------------------------\                       |
2821         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
2822     0<> UNTIL                   \                   |   |
2823     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
2824 REPEAT                          \ ----> loop back --+   |
2825 \ ------------------------------\                       |
2826 \ RC5_SampleEndOf:              \ <---------------------+
2827 \ ------------------------------\
2828 BIC     #$30,&TA0CTL           \ stop timer_A0
2829 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
2830 \ ******************************\
2831 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
2832 \ ******************************\
2833 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
2834 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
2835 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
2836 BIT     #BIT13,X                \ X(13) = New_RC5_command
2837 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
2838 THEN                            \
2839 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
2840 \ ******************************\
2841 \ RC5_ComputeNewRC5word         \
2842 \ ******************************\
2843 SUB     #4,PSP                  \
2844 MOV     &BASE,2(PSP)            \ save variable BASE before use
2845 MOV     TOS,0(PSP)              \ save TOS before use
2846 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
2847 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
2848 \ ******************************\
2849 \ RC5_ComputeC6bit              \
2850 \ ******************************\
2851 BIT     #$4000,IP              \ test /C6 bit in IP
2852 0= IF   BIS #$40,TOS           \ set C6 bit in S
2853 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
2854 \ ******************************\
2855 \ RC5_CommandByteIsDone         \ RC5_code --
2856 \ ******************************\
2857
2858 \ ------------------------------\
2859 \ Display IR_RC5 code           \
2860 \ ------------------------------\
2861 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
2862 \ ------------------------------\
2863 LO2HI                           \ switch from assembler to FORTH
2864     ['] LCD_CLEAR IS CR         \ redirects CR
2865     ['] LCD_WrC  IS EMIT        \ redirects EMIT
2866     $10 BASE !                 \ change BASE to hexadecimal
2867     CR ." $" 2 U.R             \ print IR_RC5 code
2868     ['] (CR) IS CR              \ restore CR
2869     ['] (EMIT) IS EMIT          \ restore EMIT
2870 HI2LO                           \ switch from FORTH to assembler
2871 \ ------------------------------\
2872 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
2873 \ ------------------------------\
2874 MOV @PSP+,&BASE                 \ restore variable BASE
2875 RETI                            \ CPU is ON, GIE is OFF
2876 ENDASM                          \
2877     \ 
2878
2879 CODE START                      \
2880 \ ------------------------------\
2881 \ TB0CTL = %0000 0010 1001 0100\$3C0
2882 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
2883 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
2884 \                      --       \ID input divider \ 10 = /4
2885 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
2886 \                            -  \TBCLR TimerB Clear
2887 \                             - \TBIE
2888 \                              -\TBIFG
2889 \ --------------------------------\\
2890 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
2891 \              --                 \CM Capture Mode
2892 \                --               \CCIS
2893 \                   -             \SCS
2894 \                    --           \CLLD
2895 \                      -          \CAP
2896 \                        ---      \OUTMOD \ 011 = set/reset
2897 \                           -     \CCIE
2898 \                             -   \CCI
2899 \                              -  \OUT
2900 \                               - \COV
2901 \                                -\CCIFG
2902 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
2903 \ TB0EX0                          \$3E0 
2904 \ ------------------------------\
2905 \ set TimerB to make 50kHz PWM  \
2906 \ ------------------------------\
2907 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
2908 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
2909 \ ------------------------------\
2910 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
2911 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
2912 \ ------------------------------\
2913     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
2914     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
2915 \ ------------------------------\
2916 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
2917 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
2918 \ ------------------------------\
2919 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
2920 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
2921 \ ------------------------------\
2922     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
2923 \ ------------------------------\
2924 \ set TimerB to generate PWM for LCD_Vo
2925 \ ------------------------------\
2926     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
2927 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
2928     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
2929 \ ------------------------------\
2930     BIS.B #LCDVo,&LCDVo_DIR     \
2931     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
2932 \ ------------------------------\
2933     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
2934     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
2935 \ ------------------------------\
2936     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
2937     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
2938 \ ------------------------------\
2939 \ WDT interval init part        \
2940 \ ------------------------------\
2941     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
2942 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
2943 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
2944     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
2945 \ ------------------------------\
2946 \ init RC5_Int                  \
2947 \ ------------------------------\
2948     BIS.B #RC5,&IR_IE           \ enable RC5_Int
2949     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
2950 \ ------------------------------\
2951 \ init interrupt vectors
2952 \ ------------------------------\
2953     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
2954     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
2955 \ ------------------------------\
2956 \ define LPM mode for ACCEPT    \
2957 \ ------------------------------\
2958 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
2959 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
2960 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
2961
2962 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
2963
2964 \ ------------------------------\
2965 \ Init LCD 2x20                 \
2966 \ ------------------------------\
2967     $03E8 20_US                \ 1-  wait 20 ms
2968     $03 TOP_LCD                \ 2- send DB5=DB4=1
2969     $CD 20_US                  \ 3- wait 4,1 ms
2970     $03 TOP_LCD                \ 4- send again DB5=DB4=1
2971     $5 20_US                   \ 5- wait 0,1 ms
2972     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
2973     $2 20_US                   \    wait 40 us = LCD cycle
2974     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
2975     $2 20_US                   \    wait 40 us = LCD cycle
2976     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
2977     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
2978     LCD_Clear                   \ 10- "LCD_Clear"
2979     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
2980     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
2981     LCD_Clear                   \ 10- "LCD_Clear"
2982     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
2983     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
2984     CR ." I love you"   
2985     ['] (CR) IS CR              \ ' (CR) is CR
2986     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
2987     CR
2988     ."    RC5toLCD is running. Type STOP to quit"
2989 \    NOECHO                      \ uncomment to run this app without terminal connexion
2990     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
2991     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
2992 ;
2993     \
2994
2995 : STOP                  \ stops multitasking, must to be used before downloading app
2996     ['] (WARM) IS WARM  \ remove START app from FORTH init process
2997     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
2998 ;
2999     \
3000
3001
3002 RST_STATE   ;
3003
3004
3005 CODE MAX    \    n1 n2 -- n3       signed maximum
3006             CMP     @PSP,TOS    \ n2-n1
3007             S<      ?GOTO FW1   \ n2<n1
3008 BW1         ADD     #2,PSP
3009             MOV     @IP+,PC
3010 ENDCODE
3011     \
3012
3013 CODE MIN    \    n1 n2 -- n3       signed minimum
3014             CMP     @PSP,TOS     \ n2-n1
3015             S<      ?GOTO BW1    \ n2<n1
3016 FW1         MOV     @PSP+,TOS
3017             MOV     @IP+,PC
3018 ENDCODE
3019     \
3020
3021 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
3022   >R  <# 0 # #S #>  
3023   R> OVER - 0 MAX SPACES TYPE
3024 ;
3025     \
3026
3027 CODE 20_US                      \ n --      n * 20 us
3028 BEGIN                           \ 3 cycles loop + 6~  
3029 \    MOV     #5,W                \ 3 MCLK = 1 MHz
3030 \    MOV     #23,W               \ 3 MCLK = 4 MHz
3031     MOV     #51,W               \ 3 MCLK = 8 MHz
3032 \    MOV     #104,W              \ 3 MCLK = 16 MHz
3033 \    MOV     #158,W              \ 3 MCLK = 24 MHz
3034     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
3035         SUB #1,W                \ 1
3036     0= UNTIL                    \ 2
3037     SUB     #1,TOS              \ 1
3038 0= UNTIL                        \ 2
3039     MOV     @PSP+,TOS           \ 2
3040     MOV     @IP+,PC             \ 4
3041 ENDCODE
3042     \
3043
3044 CODE TOP_LCD                    \ LCD Sample
3045 \                               \ if write : %xxxxWWWW --
3046 \                               \ if read  : -- %0000RRRR
3047     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
3048     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
3049 0= IF                           \ write LCD bits pattern
3050     AND.B #LCD_DB,TOS           \ 
3051     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
3052     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
3053     MOV @PSP+,TOS               \
3054     MOV @IP+,PC
3055 THEN                            \ read LCD bits pattern
3056     SUB #2,PSP
3057     MOV TOS,0(PSP)
3058     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
3059     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
3060     AND.B #LCD_DB,TOS           \
3061     MOV @IP+,PC
3062 ENDCODE
3063     \
3064
3065 CODE LCD_W                      \ byte --       write byte to LCD 
3066     SUB #2,PSP                  \
3067     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
3068     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
3069     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
3070     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
3071 COLON                           \ high level word starts here 
3072     TOP_LCD 2 20_US             \ write high nibble first
3073     TOP_LCD 2 20_US 
3074 ;
3075     \
3076
3077 CODE LCD_WrC                    \ char --         Write Char
3078     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
3079     JMP LCD_W 
3080 ENDCODE
3081     \
3082
3083 CODE LCD_WrF                    \ func --         Write Fonction
3084     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
3085     JMP LCD_W 
3086 ENDCODE
3087     \
3088
3089 : LCD_Clear 
3090     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
3091 ;
3092     \
3093
3094 : LCD_Home 
3095     $02 LCD_WrF 100 20_us 
3096 ;
3097     \
3098
3099 \ : LCD_Entry_set       $04 OR LCD_WrF ;
3100
3101 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
3102
3103 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
3104
3105 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
3106
3107 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
3108
3109 \ : LCD_Goto            $80 OR LCD_WrF ;
3110
3111 \ CODE LCD_R                      \ -- byte       read byte from LCD
3112 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
3113 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
3114 \ COLON                           \ starts a FORTH word
3115 \     TOP_LCD 2 20_us             \ -- %0000HHHH
3116 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
3117 \ HI2LO                           \ switch from FORTH to assembler
3118 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
3119 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
3120 \     MOV @RSP+,IP                \ restore IP saved by COLON
3121 \     MOV @IP+,PC                 \
3122 \ ENDCODE
3123 \     \
3124
3125 \ CODE LCD_RdS                    \ -- status       Read Status
3126 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
3127 \     JMP LCD_R
3128 \ ENDCODE
3129 \     \
3130
3131 \ CODE LCD_RdC                    \ -- char         Read Char
3132 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
3133 \     JMP LCD_R
3134 \ ENDCODE
3135 \     \
3136
3137 \ -------------+------+------+------+------++---+---+---+---+---------+
3138 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
3139 \ -------------+------+------+------+------++---+---+---+---+---------+
3140 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
3141 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
3142 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
3143 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
3144 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
3145 \ -------------+------+------+------+------++---+---+---+---+---------+
3146
3147
3148 \ ******************************\
3149 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
3150 \ ******************************\
3151 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
3152 \ ------------------------------\
3153 \ define LPM mode for ACCEPT    \
3154 \ ------------------------------\
3155 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
3156 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
3157 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
3158 BIT.B #SW2,&SW2_IN              \ test switch S2
3159 0= IF                           \ case of switch S2 pressed
3160     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
3161     U< IF
3162         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
3163     THEN
3164 ELSE
3165     BIT.B #SW1,&SW1_IN          \ test switch S1 input
3166     0= IF                       \ case of Switch S1 pressed
3167         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
3168         U>= IF                  \
3169             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
3170         THEN                    \
3171     THEN                        \
3172 THEN                            \
3173 RETI                            \ CPU is ON, GIE is OFF
3174 ENDASM                          \
3175     \
3176
3177
3178 \ ------------------------------\
3179 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
3180 \ ******************************\
3181 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
3182 \ ******************************\
3183 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
3184 \                               \       SMclock = 8|16|24 MHz
3185 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
3186 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
3187 \                               \       SR(9)=new Toggle bit memory (ADD on)
3188 \ ------------------------------\
3189 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
3190 \ ------------------------------\
3191 \ define LPM mode for ACCEPT    \
3192 \ ------------------------------\
3193 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
3194 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
3195 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
3196 \ ------------------------------\
3197 \ RC5_FirstStartBitHalfCycle:   \
3198 \ ------------------------------\
3199 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
3200 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
3201 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
3202 MOV     #1778,X                 \ RC5_Period in us
3203 MOV     #14,W                   \ count of loop
3204 BEGIN                           \
3205 \ ------------------------------\
3206 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
3207 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
3208     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
3209 \ RC5_Compute_3/4_Period:       \                   |
3210     RRUM    #1,X                \ X=1/2 cycle       |
3211     MOV     X,Y                 \ Y=1/2             ^
3212     RRUM    #1,Y                \ Y=1/4
3213     ADD     X,Y                 \ Y=3/4
3214 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
3215     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
3216     0= UNTIL                    \
3217 \ ------------------------------\
3218 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
3219 \ ------------------------------\
3220     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
3221     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
3222     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
3223     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
3224     SUB     #1,W                \ decrement count loop
3225 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
3226 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
3227 0<> WHILE                       \ ----> out of loop ----+
3228 \ RC5_compute_7/4_Time_out:     \                       |
3229     ADD     X,Y                 \                       |   out of bound = 7/4 period 
3230 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
3231     BEGIN                       \                       |
3232         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
3233         0>= IF                  \                       |   if cycle time out of bound
3234             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
3235             RETI                \                       |   then quit to do nothing
3236         THEN                    \                       |
3237 \ ------------------------------\                       |
3238         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
3239     0<> UNTIL                   \                   |   |
3240     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
3241 REPEAT                          \ ----> loop back --+   |
3242 \ ------------------------------\                       |
3243 \ RC5_SampleEndOf:              \ <---------------------+
3244 \ ------------------------------\
3245 BIC     #$30,&TA0CTL           \ stop timer_A0
3246 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
3247 \ ******************************\
3248 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
3249 \ ******************************\
3250 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
3251 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
3252 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
3253 BIT     #BIT13,X                \ X(13) = New_RC5_command
3254 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
3255 THEN                            \
3256 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
3257 \ ******************************\
3258 \ RC5_ComputeNewRC5word         \
3259 \ ******************************\
3260 SUB     #4,PSP                  \
3261 MOV     &BASE,2(PSP)            \ save variable BASE before use
3262 MOV     TOS,0(PSP)              \ save TOS before use
3263 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
3264 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
3265 \ ******************************\
3266 \ RC5_ComputeC6bit              \
3267 \ ******************************\
3268 BIT     #$4000,IP              \ test /C6 bit in IP
3269 0= IF   BIS #$40,TOS           \ set C6 bit in S
3270 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
3271 \ ******************************\
3272 \ RC5_CommandByteIsDone         \ RC5_code --
3273 \ ******************************\
3274
3275 \ ------------------------------\
3276 \ Display IR_RC5 code           \
3277 \ ------------------------------\
3278 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
3279 \ ------------------------------\
3280 LO2HI                           \ switch from assembler to FORTH
3281     ['] LCD_CLEAR IS CR         \ redirects CR
3282     ['] LCD_WrC  IS EMIT        \ redirects EMIT
3283     $10 BASE !                 \ change BASE to hexadecimal
3284     CR ." $" 2 U.R             \ print IR_RC5 code
3285     ['] (CR) IS CR              \ restore CR
3286     ['] (EMIT) IS EMIT          \ restore EMIT
3287 HI2LO                           \ switch from FORTH to assembler
3288 \ ------------------------------\
3289 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
3290 \ ------------------------------\
3291 MOV @PSP+,&BASE                 \ restore variable BASE
3292 RETI                            \ CPU is ON, GIE is OFF
3293 ENDASM                          \
3294     \ 
3295
3296 CODE START                      \
3297 \ ------------------------------\
3298 \ TB0CTL = %0000 0010 1001 0100\$3C0
3299 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
3300 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
3301 \                      --       \ID input divider \ 10 = /4
3302 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
3303 \                            -  \TBCLR TimerB Clear
3304 \                             - \TBIE
3305 \                              -\TBIFG
3306 \ --------------------------------\\
3307 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
3308 \              --                 \CM Capture Mode
3309 \                --               \CCIS
3310 \                   -             \SCS
3311 \                    --           \CLLD
3312 \                      -          \CAP
3313 \                        ---      \OUTMOD \ 011 = set/reset
3314 \                           -     \CCIE
3315 \                             -   \CCI
3316 \                              -  \OUT
3317 \                               - \COV
3318 \                                -\CCIFG
3319 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
3320 \ TB0EX0                          \$3E0 
3321 \ ------------------------------\
3322 \ set TimerB to make 50kHz PWM  \
3323 \ ------------------------------\
3324 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
3325 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
3326 \ ------------------------------\
3327 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
3328 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
3329 \ ------------------------------\
3330     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
3331     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
3332 \ ------------------------------\
3333 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
3334 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
3335 \ ------------------------------\
3336 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
3337 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
3338 \ ------------------------------\
3339     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
3340 \ ------------------------------\
3341 \ set TimerB to generate PWM for LCD_Vo
3342 \ ------------------------------\
3343     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
3344 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
3345     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
3346 \ ------------------------------\
3347     BIS.B #LCDVo,&LCDVo_DIR     \
3348     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
3349 \ ------------------------------\
3350     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
3351     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
3352 \ ------------------------------\
3353     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
3354     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
3355 \ ------------------------------\
3356 \ WDT interval init part        \
3357 \ ------------------------------\
3358     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
3359 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
3360 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
3361     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
3362 \ ------------------------------\
3363 \ init RC5_Int                  \
3364 \ ------------------------------\
3365     BIS.B #RC5,&IR_IE           \ enable RC5_Int
3366     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
3367 \ ------------------------------\
3368 \ init interrupt vectors
3369 \ ------------------------------\
3370     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
3371     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
3372 \ ------------------------------\
3373 \ define LPM mode for ACCEPT    \
3374 \ ------------------------------\
3375 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
3376 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
3377 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
3378
3379 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
3380
3381 \ ------------------------------\
3382 \ Init LCD 2x20                 \
3383 \ ------------------------------\
3384     $03E8 20_US                \ 1-  wait 20 ms
3385     $03 TOP_LCD                \ 2- send DB5=DB4=1
3386     $CD 20_US                  \ 3- wait 4,1 ms
3387     $03 TOP_LCD                \ 4- send again DB5=DB4=1
3388     $5 20_US                   \ 5- wait 0,1 ms
3389     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
3390     $2 20_US                   \    wait 40 us = LCD cycle
3391     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
3392     $2 20_US                   \    wait 40 us = LCD cycle
3393     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
3394     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
3395     LCD_Clear                   \ 10- "LCD_Clear"
3396     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
3397     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
3398     LCD_Clear                   \ 10- "LCD_Clear"
3399     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
3400     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
3401     CR ." I love you"   
3402     ['] (CR) IS CR              \ ' (CR) is CR
3403     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
3404     CR
3405     ."    RC5toLCD is running. Type STOP to quit"
3406 \    NOECHO                      \ uncomment to run this app without terminal connexion
3407     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
3408     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
3409 ;
3410     \
3411
3412 : STOP                  \ stops multitasking, must to be used before downloading app
3413     ['] (WARM) IS WARM  \ remove START app from FORTH init process
3414     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
3415 ;
3416     \
3417
3418
3419 RST_STATE   ;
3420
3421
3422 CODE MAX    \    n1 n2 -- n3       signed maximum
3423             CMP     @PSP,TOS    \ n2-n1
3424             S<      ?GOTO FW1   \ n2<n1
3425 BW1         ADD     #2,PSP
3426             MOV     @IP+,PC
3427 ENDCODE
3428     \
3429
3430 CODE MIN    \    n1 n2 -- n3       signed minimum
3431             CMP     @PSP,TOS     \ n2-n1
3432             S<      ?GOTO BW1    \ n2<n1
3433 FW1         MOV     @PSP+,TOS
3434             MOV     @IP+,PC
3435 ENDCODE
3436     \
3437
3438 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
3439   >R  <# 0 # #S #>  
3440   R> OVER - 0 MAX SPACES TYPE
3441 ;
3442     \
3443
3444 CODE 20_US                      \ n --      n * 20 us
3445 BEGIN                           \ 3 cycles loop + 6~  
3446 \    MOV     #5,W                \ 3 MCLK = 1 MHz
3447 \    MOV     #23,W               \ 3 MCLK = 4 MHz
3448     MOV     #51,W               \ 3 MCLK = 8 MHz
3449 \    MOV     #104,W              \ 3 MCLK = 16 MHz
3450 \    MOV     #158,W              \ 3 MCLK = 24 MHz
3451     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
3452         SUB #1,W                \ 1
3453     0= UNTIL                    \ 2
3454     SUB     #1,TOS              \ 1
3455 0= UNTIL                        \ 2
3456     MOV     @PSP+,TOS           \ 2
3457     MOV     @IP+,PC             \ 4
3458 ENDCODE
3459     \
3460
3461 CODE TOP_LCD                    \ LCD Sample
3462 \                               \ if write : %xxxxWWWW --
3463 \                               \ if read  : -- %0000RRRR
3464     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
3465     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
3466 0= IF                           \ write LCD bits pattern
3467     AND.B #LCD_DB,TOS           \ 
3468     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
3469     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
3470     MOV @PSP+,TOS               \
3471     MOV @IP+,PC
3472 THEN                            \ read LCD bits pattern
3473     SUB #2,PSP
3474     MOV TOS,0(PSP)
3475     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
3476     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
3477     AND.B #LCD_DB,TOS           \
3478     MOV @IP+,PC
3479 ENDCODE
3480     \
3481
3482 CODE LCD_W                      \ byte --       write byte to LCD 
3483     SUB #2,PSP                  \
3484     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
3485     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
3486     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
3487     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
3488 COLON                           \ high level word starts here 
3489     TOP_LCD 2 20_US             \ write high nibble first
3490     TOP_LCD 2 20_US 
3491 ;
3492     \
3493
3494 CODE LCD_WrC                    \ char --         Write Char
3495     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
3496     JMP LCD_W 
3497 ENDCODE
3498     \
3499
3500 CODE LCD_WrF                    \ func --         Write Fonction
3501     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
3502     JMP LCD_W 
3503 ENDCODE
3504     \
3505
3506 : LCD_Clear 
3507     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
3508 ;
3509     \
3510
3511 : LCD_Home 
3512     $02 LCD_WrF 100 20_us 
3513 ;
3514     \
3515
3516 \ : LCD_Entry_set       $04 OR LCD_WrF ;
3517
3518 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
3519
3520 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
3521
3522 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
3523
3524 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
3525
3526 \ : LCD_Goto            $80 OR LCD_WrF ;
3527
3528 \ CODE LCD_R                      \ -- byte       read byte from LCD
3529 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
3530 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
3531 \ COLON                           \ starts a FORTH word
3532 \     TOP_LCD 2 20_us             \ -- %0000HHHH
3533 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
3534 \ HI2LO                           \ switch from FORTH to assembler
3535 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
3536 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
3537 \     MOV @RSP+,IP                \ restore IP saved by COLON
3538 \     MOV @IP+,PC                 \
3539 \ ENDCODE
3540 \     \
3541
3542 \ CODE LCD_RdS                    \ -- status       Read Status
3543 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
3544 \     JMP LCD_R
3545 \ ENDCODE
3546 \     \
3547
3548 \ CODE LCD_RdC                    \ -- char         Read Char
3549 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
3550 \     JMP LCD_R
3551 \ ENDCODE
3552 \     \
3553
3554 \ -------------+------+------+------+------++---+---+---+---+---------+
3555 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
3556 \ -------------+------+------+------+------++---+---+---+---+---------+
3557 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
3558 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
3559 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
3560 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
3561 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
3562 \ -------------+------+------+------+------++---+---+---+---+---------+
3563
3564
3565 \ ******************************\
3566 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
3567 \ ******************************\
3568 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
3569 \ ------------------------------\
3570 \ define LPM mode for ACCEPT    \
3571 \ ------------------------------\
3572 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
3573 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
3574 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
3575 BIT.B #SW2,&SW2_IN              \ test switch S2
3576 0= IF                           \ case of switch S2 pressed
3577     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
3578     U< IF
3579         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
3580     THEN
3581 ELSE
3582     BIT.B #SW1,&SW1_IN          \ test switch S1 input
3583     0= IF                       \ case of Switch S1 pressed
3584         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
3585         U>= IF                  \
3586             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
3587         THEN                    \
3588     THEN                        \
3589 THEN                            \
3590 RETI                            \ CPU is ON, GIE is OFF
3591 ENDASM                          \
3592     \
3593
3594
3595 \ ------------------------------\
3596 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
3597 \ ******************************\
3598 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
3599 \ ******************************\
3600 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
3601 \                               \       SMclock = 8|16|24 MHz
3602 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
3603 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
3604 \                               \       SR(9)=new Toggle bit memory (ADD on)
3605 \ ------------------------------\
3606 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
3607 \ ------------------------------\
3608 \ define LPM mode for ACCEPT    \
3609 \ ------------------------------\
3610 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
3611 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
3612 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
3613 \ ------------------------------\
3614 \ RC5_FirstStartBitHalfCycle:   \
3615 \ ------------------------------\
3616 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
3617 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
3618 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
3619 MOV     #1778,X                 \ RC5_Period in us
3620 MOV     #14,W                   \ count of loop
3621 BEGIN                           \
3622 \ ------------------------------\
3623 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
3624 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
3625     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
3626 \ RC5_Compute_3/4_Period:       \                   |
3627     RRUM    #1,X                \ X=1/2 cycle       |
3628     MOV     X,Y                 \ Y=1/2             ^
3629     RRUM    #1,Y                \ Y=1/4
3630     ADD     X,Y                 \ Y=3/4
3631 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
3632     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
3633     0= UNTIL                    \
3634 \ ------------------------------\
3635 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
3636 \ ------------------------------\
3637     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
3638     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
3639     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
3640     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
3641     SUB     #1,W                \ decrement count loop
3642 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
3643 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
3644 0<> WHILE                       \ ----> out of loop ----+
3645 \ RC5_compute_7/4_Time_out:     \                       |
3646     ADD     X,Y                 \                       |   out of bound = 7/4 period 
3647 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
3648     BEGIN                       \                       |
3649         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
3650         0>= IF                  \                       |   if cycle time out of bound
3651             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
3652             RETI                \                       |   then quit to do nothing
3653         THEN                    \                       |
3654 \ ------------------------------\                       |
3655         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
3656     0<> UNTIL                   \                   |   |
3657     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
3658 REPEAT                          \ ----> loop back --+   |
3659 \ ------------------------------\                       |
3660 \ RC5_SampleEndOf:              \ <---------------------+
3661 \ ------------------------------\
3662 BIC     #$30,&TA0CTL           \ stop timer_A0
3663 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
3664 \ ******************************\
3665 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
3666 \ ******************************\
3667 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
3668 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
3669 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
3670 BIT     #BIT13,X                \ X(13) = New_RC5_command
3671 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
3672 THEN                            \
3673 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
3674 \ ******************************\
3675 \ RC5_ComputeNewRC5word         \
3676 \ ******************************\
3677 SUB     #4,PSP                  \
3678 MOV     &BASE,2(PSP)            \ save variable BASE before use
3679 MOV     TOS,0(PSP)              \ save TOS before use
3680 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
3681 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
3682 \ ******************************\
3683 \ RC5_ComputeC6bit              \
3684 \ ******************************\
3685 BIT     #$4000,IP              \ test /C6 bit in IP
3686 0= IF   BIS #$40,TOS           \ set C6 bit in S
3687 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
3688 \ ******************************\
3689 \ RC5_CommandByteIsDone         \ RC5_code --
3690 \ ******************************\
3691
3692 \ ------------------------------\
3693 \ Display IR_RC5 code           \
3694 \ ------------------------------\
3695 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
3696 \ ------------------------------\
3697 LO2HI                           \ switch from assembler to FORTH
3698     ['] LCD_CLEAR IS CR         \ redirects CR
3699     ['] LCD_WrC  IS EMIT        \ redirects EMIT
3700     $10 BASE !                 \ change BASE to hexadecimal
3701     CR ." $" 2 U.R             \ print IR_RC5 code
3702     ['] (CR) IS CR              \ restore CR
3703     ['] (EMIT) IS EMIT          \ restore EMIT
3704 HI2LO                           \ switch from FORTH to assembler
3705 \ ------------------------------\
3706 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
3707 \ ------------------------------\
3708 MOV @PSP+,&BASE                 \ restore variable BASE
3709 RETI                            \ CPU is ON, GIE is OFF
3710 ENDASM                          \
3711     \ 
3712
3713 CODE START                      \
3714 \ ------------------------------\
3715 \ TB0CTL = %0000 0010 1001 0100\$3C0
3716 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
3717 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
3718 \                      --       \ID input divider \ 10 = /4
3719 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
3720 \                            -  \TBCLR TimerB Clear
3721 \                             - \TBIE
3722 \                              -\TBIFG
3723 \ --------------------------------\\
3724 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
3725 \              --                 \CM Capture Mode
3726 \                --               \CCIS
3727 \                   -             \SCS
3728 \                    --           \CLLD
3729 \                      -          \CAP
3730 \                        ---      \OUTMOD \ 011 = set/reset
3731 \                           -     \CCIE
3732 \                             -   \CCI
3733 \                              -  \OUT
3734 \                               - \COV
3735 \                                -\CCIFG
3736 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
3737 \ TB0EX0                          \$3E0 
3738 \ ------------------------------\
3739 \ set TimerB to make 50kHz PWM  \
3740 \ ------------------------------\
3741 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
3742 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
3743 \ ------------------------------\
3744 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
3745 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
3746 \ ------------------------------\
3747     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
3748     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
3749 \ ------------------------------\
3750 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
3751 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
3752 \ ------------------------------\
3753 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
3754 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
3755 \ ------------------------------\
3756     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
3757 \ ------------------------------\
3758 \ set TimerB to generate PWM for LCD_Vo
3759 \ ------------------------------\
3760     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
3761 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
3762     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
3763 \ ------------------------------\
3764     BIS.B #LCDVo,&LCDVo_DIR     \
3765     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
3766 \ ------------------------------\
3767     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
3768     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
3769 \ ------------------------------\
3770     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
3771     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
3772 \ ------------------------------\
3773 \ WDT interval init part        \
3774 \ ------------------------------\
3775     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
3776 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
3777 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
3778     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
3779 \ ------------------------------\
3780 \ init RC5_Int                  \
3781 \ ------------------------------\
3782     BIS.B #RC5,&IR_IE           \ enable RC5_Int
3783     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
3784 \ ------------------------------\
3785 \ init interrupt vectors
3786 \ ------------------------------\
3787     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
3788     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
3789 \ ------------------------------\
3790 \ define LPM mode for ACCEPT    \
3791 \ ------------------------------\
3792 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
3793 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
3794 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
3795
3796 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
3797
3798 \ ------------------------------\
3799 \ Init LCD 2x20                 \
3800 \ ------------------------------\
3801     $03E8 20_US                \ 1-  wait 20 ms
3802     $03 TOP_LCD                \ 2- send DB5=DB4=1
3803     $CD 20_US                  \ 3- wait 4,1 ms
3804     $03 TOP_LCD                \ 4- send again DB5=DB4=1
3805     $5 20_US                   \ 5- wait 0,1 ms
3806     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
3807     $2 20_US                   \    wait 40 us = LCD cycle
3808     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
3809     $2 20_US                   \    wait 40 us = LCD cycle
3810     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
3811     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
3812     LCD_Clear                   \ 10- "LCD_Clear"
3813     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
3814     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
3815     LCD_Clear                   \ 10- "LCD_Clear"
3816     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
3817     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
3818     CR ." I love you"   
3819     ['] (CR) IS CR              \ ' (CR) is CR
3820     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
3821     CR
3822     ."    RC5toLCD is running. Type STOP to quit"
3823 \    NOECHO                      \ uncomment to run this app without terminal connexion
3824     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
3825     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
3826 ;
3827     \
3828
3829 : STOP                  \ stops multitasking, must to be used before downloading app
3830     ['] (WARM) IS WARM  \ remove START app from FORTH init process
3831     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
3832 ;
3833     \
3834
3835
3836 RST_STATE   ;
3837
3838
3839 CODE MAX    \    n1 n2 -- n3       signed maximum
3840             CMP     @PSP,TOS    \ n2-n1
3841             S<      ?GOTO FW1   \ n2<n1
3842 BW1         ADD     #2,PSP
3843             MOV     @IP+,PC
3844 ENDCODE
3845     \
3846
3847 CODE MIN    \    n1 n2 -- n3       signed minimum
3848             CMP     @PSP,TOS     \ n2-n1
3849             S<      ?GOTO BW1    \ n2<n1
3850 FW1         MOV     @PSP+,TOS
3851             MOV     @IP+,PC
3852 ENDCODE
3853     \
3854
3855 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
3856   >R  <# 0 # #S #>  
3857   R> OVER - 0 MAX SPACES TYPE
3858 ;
3859     \
3860
3861 CODE 20_US                      \ n --      n * 20 us
3862 BEGIN                           \ 3 cycles loop + 6~  
3863 \    MOV     #5,W                \ 3 MCLK = 1 MHz
3864 \    MOV     #23,W               \ 3 MCLK = 4 MHz
3865     MOV     #51,W               \ 3 MCLK = 8 MHz
3866 \    MOV     #104,W              \ 3 MCLK = 16 MHz
3867 \    MOV     #158,W              \ 3 MCLK = 24 MHz
3868     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
3869         SUB #1,W                \ 1
3870     0= UNTIL                    \ 2
3871     SUB     #1,TOS              \ 1
3872 0= UNTIL                        \ 2
3873     MOV     @PSP+,TOS           \ 2
3874     MOV     @IP+,PC             \ 4
3875 ENDCODE
3876     \
3877
3878 CODE TOP_LCD                    \ LCD Sample
3879 \                               \ if write : %xxxxWWWW --
3880 \                               \ if read  : -- %0000RRRR
3881     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
3882     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
3883 0= IF                           \ write LCD bits pattern
3884     AND.B #LCD_DB,TOS           \ 
3885     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
3886     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
3887     MOV @PSP+,TOS               \
3888     MOV @IP+,PC
3889 THEN                            \ read LCD bits pattern
3890     SUB #2,PSP
3891     MOV TOS,0(PSP)
3892     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
3893     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
3894     AND.B #LCD_DB,TOS           \
3895     MOV @IP+,PC
3896 ENDCODE
3897     \
3898
3899 CODE LCD_W                      \ byte --       write byte to LCD 
3900     SUB #2,PSP                  \
3901     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
3902     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
3903     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
3904     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
3905 COLON                           \ high level word starts here 
3906     TOP_LCD 2 20_US             \ write high nibble first
3907     TOP_LCD 2 20_US 
3908 ;
3909     \
3910
3911 CODE LCD_WrC                    \ char --         Write Char
3912     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
3913     JMP LCD_W 
3914 ENDCODE
3915     \
3916
3917 CODE LCD_WrF                    \ func --         Write Fonction
3918     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
3919     JMP LCD_W 
3920 ENDCODE
3921     \
3922
3923 : LCD_Clear 
3924     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
3925 ;
3926     \
3927
3928 : LCD_Home 
3929     $02 LCD_WrF 100 20_us 
3930 ;
3931     \
3932
3933 \ : LCD_Entry_set       $04 OR LCD_WrF ;
3934
3935 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
3936
3937 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
3938
3939 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
3940
3941 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
3942
3943 \ : LCD_Goto            $80 OR LCD_WrF ;
3944
3945 \ CODE LCD_R                      \ -- byte       read byte from LCD
3946 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
3947 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
3948 \ COLON                           \ starts a FORTH word
3949 \     TOP_LCD 2 20_us             \ -- %0000HHHH
3950 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
3951 \ HI2LO                           \ switch from FORTH to assembler
3952 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
3953 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
3954 \     MOV @RSP+,IP                \ restore IP saved by COLON
3955 \     MOV @IP+,PC                 \
3956 \ ENDCODE
3957 \     \
3958
3959 \ CODE LCD_RdS                    \ -- status       Read Status
3960 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
3961 \     JMP LCD_R
3962 \ ENDCODE
3963 \     \
3964
3965 \ CODE LCD_RdC                    \ -- char         Read Char
3966 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
3967 \     JMP LCD_R
3968 \ ENDCODE
3969 \     \
3970
3971 \ -------------+------+------+------+------++---+---+---+---+---------+
3972 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
3973 \ -------------+------+------+------+------++---+---+---+---+---------+
3974 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
3975 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
3976 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
3977 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
3978 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
3979 \ -------------+------+------+------+------++---+---+---+---+---------+
3980
3981
3982 \ ******************************\
3983 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
3984 \ ******************************\
3985 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
3986 \ ------------------------------\
3987 \ define LPM mode for ACCEPT    \
3988 \ ------------------------------\
3989 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
3990 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
3991 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
3992 BIT.B #SW2,&SW2_IN              \ test switch S2
3993 0= IF                           \ case of switch S2 pressed
3994     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
3995     U< IF
3996         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
3997     THEN
3998 ELSE
3999     BIT.B #SW1,&SW1_IN          \ test switch S1 input
4000     0= IF                       \ case of Switch S1 pressed
4001         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
4002         U>= IF                  \
4003             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
4004         THEN                    \
4005     THEN                        \
4006 THEN                            \
4007 RETI                            \ CPU is ON, GIE is OFF
4008 ENDASM                          \
4009     \
4010
4011
4012 \ ------------------------------\
4013 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
4014 \ ******************************\
4015 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
4016 \ ******************************\
4017 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
4018 \                               \       SMclock = 8|16|24 MHz
4019 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
4020 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
4021 \                               \       SR(9)=new Toggle bit memory (ADD on)
4022 \ ------------------------------\
4023 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
4024 \ ------------------------------\
4025 \ define LPM mode for ACCEPT    \
4026 \ ------------------------------\
4027 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
4028 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
4029 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
4030 \ ------------------------------\
4031 \ RC5_FirstStartBitHalfCycle:   \
4032 \ ------------------------------\
4033 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
4034 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
4035 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
4036 MOV     #1778,X                 \ RC5_Period in us
4037 MOV     #14,W                   \ count of loop
4038 BEGIN                           \
4039 \ ------------------------------\
4040 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
4041 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
4042     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
4043 \ RC5_Compute_3/4_Period:       \                   |
4044     RRUM    #1,X                \ X=1/2 cycle       |
4045     MOV     X,Y                 \ Y=1/2             ^
4046     RRUM    #1,Y                \ Y=1/4
4047     ADD     X,Y                 \ Y=3/4
4048 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
4049     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
4050     0= UNTIL                    \
4051 \ ------------------------------\
4052 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
4053 \ ------------------------------\
4054     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
4055     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
4056     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
4057     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
4058     SUB     #1,W                \ decrement count loop
4059 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
4060 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
4061 0<> WHILE                       \ ----> out of loop ----+
4062 \ RC5_compute_7/4_Time_out:     \                       |
4063     ADD     X,Y                 \                       |   out of bound = 7/4 period 
4064 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
4065     BEGIN                       \                       |
4066         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
4067         0>= IF                  \                       |   if cycle time out of bound
4068             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
4069             RETI                \                       |   then quit to do nothing
4070         THEN                    \                       |
4071 \ ------------------------------\                       |
4072         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
4073     0<> UNTIL                   \                   |   |
4074     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
4075 REPEAT                          \ ----> loop back --+   |
4076 \ ------------------------------\                       |
4077 \ RC5_SampleEndOf:              \ <---------------------+
4078 \ ------------------------------\
4079 BIC     #$30,&TA0CTL           \ stop timer_A0
4080 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
4081 \ ******************************\
4082 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
4083 \ ******************************\
4084 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
4085 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
4086 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
4087 BIT     #BIT13,X                \ X(13) = New_RC5_command
4088 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
4089 THEN                            \
4090 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
4091 \ ******************************\
4092 \ RC5_ComputeNewRC5word         \
4093 \ ******************************\
4094 SUB     #4,PSP                  \
4095 MOV     &BASE,2(PSP)            \ save variable BASE before use
4096 MOV     TOS,0(PSP)              \ save TOS before use
4097 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
4098 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
4099 \ ******************************\
4100 \ RC5_ComputeC6bit              \
4101 \ ******************************\
4102 BIT     #$4000,IP              \ test /C6 bit in IP
4103 0= IF   BIS #$40,TOS           \ set C6 bit in S
4104 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
4105 \ ******************************\
4106 \ RC5_CommandByteIsDone         \ RC5_code --
4107 \ ******************************\
4108
4109 \ ------------------------------\
4110 \ Display IR_RC5 code           \
4111 \ ------------------------------\
4112 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
4113 \ ------------------------------\
4114 LO2HI                           \ switch from assembler to FORTH
4115     ['] LCD_CLEAR IS CR         \ redirects CR
4116     ['] LCD_WrC  IS EMIT        \ redirects EMIT
4117     $10 BASE !                 \ change BASE to hexadecimal
4118     CR ." $" 2 U.R             \ print IR_RC5 code
4119     ['] (CR) IS CR              \ restore CR
4120     ['] (EMIT) IS EMIT          \ restore EMIT
4121 HI2LO                           \ switch from FORTH to assembler
4122 \ ------------------------------\
4123 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
4124 \ ------------------------------\
4125 MOV @PSP+,&BASE                 \ restore variable BASE
4126 RETI                            \ CPU is ON, GIE is OFF
4127 ENDASM                          \
4128     \ 
4129
4130 CODE START                      \
4131 \ ------------------------------\
4132 \ TB0CTL = %0000 0010 1001 0100\$3C0
4133 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
4134 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
4135 \                      --       \ID input divider \ 10 = /4
4136 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
4137 \                            -  \TBCLR TimerB Clear
4138 \                             - \TBIE
4139 \                              -\TBIFG
4140 \ --------------------------------\\
4141 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
4142 \              --                 \CM Capture Mode
4143 \                --               \CCIS
4144 \                   -             \SCS
4145 \                    --           \CLLD
4146 \                      -          \CAP
4147 \                        ---      \OUTMOD \ 011 = set/reset
4148 \                           -     \CCIE
4149 \                             -   \CCI
4150 \                              -  \OUT
4151 \                               - \COV
4152 \                                -\CCIFG
4153 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
4154 \ TB0EX0                          \$3E0 
4155 \ ------------------------------\
4156 \ set TimerB to make 50kHz PWM  \
4157 \ ------------------------------\
4158 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
4159 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
4160 \ ------------------------------\
4161 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
4162 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
4163 \ ------------------------------\
4164     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
4165     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
4166 \ ------------------------------\
4167 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
4168 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
4169 \ ------------------------------\
4170 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
4171 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
4172 \ ------------------------------\
4173     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
4174 \ ------------------------------\
4175 \ set TimerB to generate PWM for LCD_Vo
4176 \ ------------------------------\
4177     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
4178 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
4179     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
4180 \ ------------------------------\
4181     BIS.B #LCDVo,&LCDVo_DIR     \
4182     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
4183 \ ------------------------------\
4184     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
4185     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
4186 \ ------------------------------\
4187     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
4188     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
4189 \ ------------------------------\
4190 \ WDT interval init part        \
4191 \ ------------------------------\
4192     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
4193 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
4194 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
4195     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
4196 \ ------------------------------\
4197 \ init RC5_Int                  \
4198 \ ------------------------------\
4199     BIS.B #RC5,&IR_IE           \ enable RC5_Int
4200     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
4201 \ ------------------------------\
4202 \ init interrupt vectors
4203 \ ------------------------------\
4204     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
4205     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
4206 \ ------------------------------\
4207 \ define LPM mode for ACCEPT    \
4208 \ ------------------------------\
4209 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
4210 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
4211 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
4212
4213 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
4214
4215 \ ------------------------------\
4216 \ Init LCD 2x20                 \
4217 \ ------------------------------\
4218     $03E8 20_US                \ 1-  wait 20 ms
4219     $03 TOP_LCD                \ 2- send DB5=DB4=1
4220     $CD 20_US                  \ 3- wait 4,1 ms
4221     $03 TOP_LCD                \ 4- send again DB5=DB4=1
4222     $5 20_US                   \ 5- wait 0,1 ms
4223     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
4224     $2 20_US                   \    wait 40 us = LCD cycle
4225     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
4226     $2 20_US                   \    wait 40 us = LCD cycle
4227     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
4228     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
4229     LCD_Clear                   \ 10- "LCD_Clear"
4230     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
4231     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
4232     LCD_Clear                   \ 10- "LCD_Clear"
4233     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
4234     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
4235     CR ." I love you"   
4236     ['] (CR) IS CR              \ ' (CR) is CR
4237     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
4238     CR
4239     ."    RC5toLCD is running. Type STOP to quit"
4240 \    NOECHO                      \ uncomment to run this app without terminal connexion
4241     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
4242     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
4243 ;
4244     \
4245
4246 : STOP                  \ stops multitasking, must to be used before downloading app
4247     ['] (WARM) IS WARM  \ remove START app from FORTH init process
4248     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
4249 ;
4250     \
4251
4252
4253 RST_STATE   ;
4254
4255
4256 CODE MAX    \    n1 n2 -- n3       signed maximum
4257             CMP     @PSP,TOS    \ n2-n1
4258             S<      ?GOTO FW1   \ n2<n1
4259 BW1         ADD     #2,PSP
4260             MOV     @IP+,PC
4261 ENDCODE
4262     \
4263
4264 CODE MIN    \    n1 n2 -- n3       signed minimum
4265             CMP     @PSP,TOS     \ n2-n1
4266             S<      ?GOTO BW1    \ n2<n1
4267 FW1         MOV     @PSP+,TOS
4268             MOV     @IP+,PC
4269 ENDCODE
4270     \
4271
4272 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
4273   >R  <# 0 # #S #>  
4274   R> OVER - 0 MAX SPACES TYPE
4275 ;
4276     \
4277
4278 CODE 20_US                      \ n --      n * 20 us
4279 BEGIN                           \ 3 cycles loop + 6~  
4280 \    MOV     #5,W                \ 3 MCLK = 1 MHz
4281 \    MOV     #23,W               \ 3 MCLK = 4 MHz
4282     MOV     #51,W               \ 3 MCLK = 8 MHz
4283 \    MOV     #104,W              \ 3 MCLK = 16 MHz
4284 \    MOV     #158,W              \ 3 MCLK = 24 MHz
4285     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
4286         SUB #1,W                \ 1
4287     0= UNTIL                    \ 2
4288     SUB     #1,TOS              \ 1
4289 0= UNTIL                        \ 2
4290     MOV     @PSP+,TOS           \ 2
4291     MOV     @IP+,PC             \ 4
4292 ENDCODE
4293     \
4294
4295 CODE TOP_LCD                    \ LCD Sample
4296 \                               \ if write : %xxxxWWWW --
4297 \                               \ if read  : -- %0000RRRR
4298     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
4299     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
4300 0= IF                           \ write LCD bits pattern
4301     AND.B #LCD_DB,TOS           \ 
4302     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
4303     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
4304     MOV @PSP+,TOS               \
4305     MOV @IP+,PC
4306 THEN                            \ read LCD bits pattern
4307     SUB #2,PSP
4308     MOV TOS,0(PSP)
4309     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
4310     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
4311     AND.B #LCD_DB,TOS           \
4312     MOV @IP+,PC
4313 ENDCODE
4314     \
4315
4316 CODE LCD_W                      \ byte --       write byte to LCD 
4317     SUB #2,PSP                  \
4318     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
4319     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
4320     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
4321     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
4322 COLON                           \ high level word starts here 
4323     TOP_LCD 2 20_US             \ write high nibble first
4324     TOP_LCD 2 20_US 
4325 ;
4326     \
4327
4328 CODE LCD_WrC                    \ char --         Write Char
4329     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
4330     JMP LCD_W 
4331 ENDCODE
4332     \
4333
4334 CODE LCD_WrF                    \ func --         Write Fonction
4335     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
4336     JMP LCD_W 
4337 ENDCODE
4338     \
4339
4340 : LCD_Clear 
4341     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
4342 ;
4343     \
4344
4345 : LCD_Home 
4346     $02 LCD_WrF 100 20_us 
4347 ;
4348     \
4349
4350 \ : LCD_Entry_set       $04 OR LCD_WrF ;
4351
4352 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
4353
4354 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
4355
4356 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
4357
4358 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
4359
4360 \ : LCD_Goto            $80 OR LCD_WrF ;
4361
4362 \ CODE LCD_R                      \ -- byte       read byte from LCD
4363 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
4364 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
4365 \ COLON                           \ starts a FORTH word
4366 \     TOP_LCD 2 20_us             \ -- %0000HHHH
4367 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
4368 \ HI2LO                           \ switch from FORTH to assembler
4369 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
4370 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
4371 \     MOV @RSP+,IP                \ restore IP saved by COLON
4372 \     MOV @IP+,PC                 \
4373 \ ENDCODE
4374 \     \
4375
4376 \ CODE LCD_RdS                    \ -- status       Read Status
4377 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
4378 \     JMP LCD_R
4379 \ ENDCODE
4380 \     \
4381
4382 \ CODE LCD_RdC                    \ -- char         Read Char
4383 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
4384 \     JMP LCD_R
4385 \ ENDCODE
4386 \     \
4387
4388 \ -------------+------+------+------+------++---+---+---+---+---------+
4389 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
4390 \ -------------+------+------+------+------++---+---+---+---+---------+
4391 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
4392 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
4393 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
4394 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
4395 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
4396 \ -------------+------+------+------+------++---+---+---+---+---------+
4397
4398
4399 \ ******************************\
4400 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
4401 \ ******************************\
4402 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
4403 \ ------------------------------\
4404 \ define LPM mode for ACCEPT    \
4405 \ ------------------------------\
4406 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
4407 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
4408 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
4409 BIT.B #SW2,&SW2_IN              \ test switch S2
4410 0= IF                           \ case of switch S2 pressed
4411     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
4412     U< IF
4413         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
4414     THEN
4415 ELSE
4416     BIT.B #SW1,&SW1_IN          \ test switch S1 input
4417     0= IF                       \ case of Switch S1 pressed
4418         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
4419         U>= IF                  \
4420             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
4421         THEN                    \
4422     THEN                        \
4423 THEN                            \
4424 RETI                            \ CPU is ON, GIE is OFF
4425 ENDASM                          \
4426     \
4427
4428
4429 \ ------------------------------\
4430 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
4431 \ ******************************\
4432 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
4433 \ ******************************\
4434 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
4435 \                               \       SMclock = 8|16|24 MHz
4436 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
4437 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
4438 \                               \       SR(9)=new Toggle bit memory (ADD on)
4439 \ ------------------------------\
4440 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
4441 \ ------------------------------\
4442 \ define LPM mode for ACCEPT    \
4443 \ ------------------------------\
4444 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
4445 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
4446 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
4447 \ ------------------------------\
4448 \ RC5_FirstStartBitHalfCycle:   \
4449 \ ------------------------------\
4450 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
4451 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
4452 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
4453 MOV     #1778,X                 \ RC5_Period in us
4454 MOV     #14,W                   \ count of loop
4455 BEGIN                           \
4456 \ ------------------------------\
4457 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
4458 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
4459     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
4460 \ RC5_Compute_3/4_Period:       \                   |
4461     RRUM    #1,X                \ X=1/2 cycle       |
4462     MOV     X,Y                 \ Y=1/2             ^
4463     RRUM    #1,Y                \ Y=1/4
4464     ADD     X,Y                 \ Y=3/4
4465 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
4466     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
4467     0= UNTIL                    \
4468 \ ------------------------------\
4469 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
4470 \ ------------------------------\
4471     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
4472     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
4473     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
4474     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
4475     SUB     #1,W                \ decrement count loop
4476 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
4477 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
4478 0<> WHILE                       \ ----> out of loop ----+
4479 \ RC5_compute_7/4_Time_out:     \                       |
4480     ADD     X,Y                 \                       |   out of bound = 7/4 period 
4481 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
4482     BEGIN                       \                       |
4483         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
4484         0>= IF                  \                       |   if cycle time out of bound
4485             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
4486             RETI                \                       |   then quit to do nothing
4487         THEN                    \                       |
4488 \ ------------------------------\                       |
4489         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
4490     0<> UNTIL                   \                   |   |
4491     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
4492 REPEAT                          \ ----> loop back --+   |
4493 \ ------------------------------\                       |
4494 \ RC5_SampleEndOf:              \ <---------------------+
4495 \ ------------------------------\
4496 BIC     #$30,&TA0CTL           \ stop timer_A0
4497 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
4498 \ ******************************\
4499 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
4500 \ ******************************\
4501 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
4502 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
4503 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
4504 BIT     #BIT13,X                \ X(13) = New_RC5_command
4505 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
4506 THEN                            \
4507 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
4508 \ ******************************\
4509 \ RC5_ComputeNewRC5word         \
4510 \ ******************************\
4511 SUB     #4,PSP                  \
4512 MOV     &BASE,2(PSP)            \ save variable BASE before use
4513 MOV     TOS,0(PSP)              \ save TOS before use
4514 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
4515 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
4516 \ ******************************\
4517 \ RC5_ComputeC6bit              \
4518 \ ******************************\
4519 BIT     #$4000,IP              \ test /C6 bit in IP
4520 0= IF   BIS #$40,TOS           \ set C6 bit in S
4521 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
4522 \ ******************************\
4523 \ RC5_CommandByteIsDone         \ RC5_code --
4524 \ ******************************\
4525
4526 \ ------------------------------\
4527 \ Display IR_RC5 code           \
4528 \ ------------------------------\
4529 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
4530 \ ------------------------------\
4531 LO2HI                           \ switch from assembler to FORTH
4532     ['] LCD_CLEAR IS CR         \ redirects CR
4533     ['] LCD_WrC  IS EMIT        \ redirects EMIT
4534     $10 BASE !                 \ change BASE to hexadecimal
4535     CR ." $" 2 U.R             \ print IR_RC5 code
4536     ['] (CR) IS CR              \ restore CR
4537     ['] (EMIT) IS EMIT          \ restore EMIT
4538 HI2LO                           \ switch from FORTH to assembler
4539 \ ------------------------------\
4540 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
4541 \ ------------------------------\
4542 MOV @PSP+,&BASE                 \ restore variable BASE
4543 RETI                            \ CPU is ON, GIE is OFF
4544 ENDASM                          \
4545     \ 
4546
4547 CODE START                      \
4548 \ ------------------------------\
4549 \ TB0CTL = %0000 0010 1001 0100\$3C0
4550 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
4551 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
4552 \                      --       \ID input divider \ 10 = /4
4553 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
4554 \                            -  \TBCLR TimerB Clear
4555 \                             - \TBIE
4556 \                              -\TBIFG
4557 \ --------------------------------\\
4558 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
4559 \              --                 \CM Capture Mode
4560 \                --               \CCIS
4561 \                   -             \SCS
4562 \                    --           \CLLD
4563 \                      -          \CAP
4564 \                        ---      \OUTMOD \ 011 = set/reset
4565 \                           -     \CCIE
4566 \                             -   \CCI
4567 \                              -  \OUT
4568 \                               - \COV
4569 \                                -\CCIFG
4570 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
4571 \ TB0EX0                          \$3E0 
4572 \ ------------------------------\
4573 \ set TimerB to make 50kHz PWM  \
4574 \ ------------------------------\
4575 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
4576 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
4577 \ ------------------------------\
4578 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
4579 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
4580 \ ------------------------------\
4581     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
4582     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
4583 \ ------------------------------\
4584 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
4585 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
4586 \ ------------------------------\
4587 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
4588 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
4589 \ ------------------------------\
4590     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
4591 \ ------------------------------\
4592 \ set TimerB to generate PWM for LCD_Vo
4593 \ ------------------------------\
4594     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
4595 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
4596     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
4597 \ ------------------------------\
4598     BIS.B #LCDVo,&LCDVo_DIR     \
4599     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
4600 \ ------------------------------\
4601     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
4602     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
4603 \ ------------------------------\
4604     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
4605     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
4606 \ ------------------------------\
4607 \ WDT interval init part        \
4608 \ ------------------------------\
4609     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
4610 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
4611 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
4612     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
4613 \ ------------------------------\
4614 \ init RC5_Int                  \
4615 \ ------------------------------\
4616     BIS.B #RC5,&IR_IE           \ enable RC5_Int
4617     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
4618 \ ------------------------------\
4619 \ init interrupt vectors
4620 \ ------------------------------\
4621     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
4622     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
4623 \ ------------------------------\
4624 \ define LPM mode for ACCEPT    \
4625 \ ------------------------------\
4626 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
4627 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
4628 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
4629
4630 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
4631
4632 \ ------------------------------\
4633 \ Init LCD 2x20                 \
4634 \ ------------------------------\
4635     $03E8 20_US                \ 1-  wait 20 ms
4636     $03 TOP_LCD                \ 2- send DB5=DB4=1
4637     $CD 20_US                  \ 3- wait 4,1 ms
4638     $03 TOP_LCD                \ 4- send again DB5=DB4=1
4639     $5 20_US                   \ 5- wait 0,1 ms
4640     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
4641     $2 20_US                   \    wait 40 us = LCD cycle
4642     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
4643     $2 20_US                   \    wait 40 us = LCD cycle
4644     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
4645     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
4646     LCD_Clear                   \ 10- "LCD_Clear"
4647     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
4648     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
4649     LCD_Clear                   \ 10- "LCD_Clear"
4650     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
4651     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
4652     CR ." I love you"   
4653     ['] (CR) IS CR              \ ' (CR) is CR
4654     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
4655     CR
4656     ."    RC5toLCD is running. Type STOP to quit"
4657 \    NOECHO                      \ uncomment to run this app without terminal connexion
4658     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
4659     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
4660 ;
4661     \
4662
4663 : STOP                  \ stops multitasking, must to be used before downloading app
4664     ['] (WARM) IS WARM  \ remove START app from FORTH init process
4665     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
4666 ;
4667     \
4668
4669
4670 RST_STATE   ;
4671
4672
4673 CODE MAX    \    n1 n2 -- n3       signed maximum
4674             CMP     @PSP,TOS    \ n2-n1
4675             S<      ?GOTO FW1   \ n2<n1
4676 BW1         ADD     #2,PSP
4677             MOV     @IP+,PC
4678 ENDCODE
4679     \
4680
4681 CODE MIN    \    n1 n2 -- n3       signed minimum
4682             CMP     @PSP,TOS     \ n2-n1
4683             S<      ?GOTO BW1    \ n2<n1
4684 FW1         MOV     @PSP+,TOS
4685             MOV     @IP+,PC
4686 ENDCODE
4687     \
4688
4689 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
4690   >R  <# 0 # #S #>  
4691   R> OVER - 0 MAX SPACES TYPE
4692 ;
4693     \
4694
4695 CODE 20_US                      \ n --      n * 20 us
4696 BEGIN                           \ 3 cycles loop + 6~  
4697 \    MOV     #5,W                \ 3 MCLK = 1 MHz
4698 \    MOV     #23,W               \ 3 MCLK = 4 MHz
4699     MOV     #51,W               \ 3 MCLK = 8 MHz
4700 \    MOV     #104,W              \ 3 MCLK = 16 MHz
4701 \    MOV     #158,W              \ 3 MCLK = 24 MHz
4702     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
4703         SUB #1,W                \ 1
4704     0= UNTIL                    \ 2
4705     SUB     #1,TOS              \ 1
4706 0= UNTIL                        \ 2
4707     MOV     @PSP+,TOS           \ 2
4708     MOV     @IP+,PC             \ 4
4709 ENDCODE
4710     \
4711
4712 CODE TOP_LCD                    \ LCD Sample
4713 \                               \ if write : %xxxxWWWW --
4714 \                               \ if read  : -- %0000RRRR
4715     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
4716     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
4717 0= IF                           \ write LCD bits pattern
4718     AND.B #LCD_DB,TOS           \ 
4719     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
4720     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
4721     MOV @PSP+,TOS               \
4722     MOV @IP+,PC
4723 THEN                            \ read LCD bits pattern
4724     SUB #2,PSP
4725     MOV TOS,0(PSP)
4726     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
4727     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
4728     AND.B #LCD_DB,TOS           \
4729     MOV @IP+,PC
4730 ENDCODE
4731     \
4732
4733 CODE LCD_W                      \ byte --       write byte to LCD 
4734     SUB #2,PSP                  \
4735     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
4736     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
4737     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
4738     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
4739 COLON                           \ high level word starts here 
4740     TOP_LCD 2 20_US             \ write high nibble first
4741     TOP_LCD 2 20_US 
4742 ;
4743     \
4744
4745 CODE LCD_WrC                    \ char --         Write Char
4746     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
4747     JMP LCD_W 
4748 ENDCODE
4749     \
4750
4751 CODE LCD_WrF                    \ func --         Write Fonction
4752     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
4753     JMP LCD_W 
4754 ENDCODE
4755     \
4756
4757 : LCD_Clear 
4758     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
4759 ;
4760     \
4761
4762 : LCD_Home 
4763     $02 LCD_WrF 100 20_us 
4764 ;
4765     \
4766
4767 \ : LCD_Entry_set       $04 OR LCD_WrF ;
4768
4769 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
4770
4771 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
4772
4773 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
4774
4775 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
4776
4777 \ : LCD_Goto            $80 OR LCD_WrF ;
4778
4779 \ CODE LCD_R                      \ -- byte       read byte from LCD
4780 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
4781 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
4782 \ COLON                           \ starts a FORTH word
4783 \     TOP_LCD 2 20_us             \ -- %0000HHHH
4784 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
4785 \ HI2LO                           \ switch from FORTH to assembler
4786 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
4787 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
4788 \     MOV @RSP+,IP                \ restore IP saved by COLON
4789 \     MOV @IP+,PC                 \
4790 \ ENDCODE
4791 \     \
4792
4793 \ CODE LCD_RdS                    \ -- status       Read Status
4794 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
4795 \     JMP LCD_R
4796 \ ENDCODE
4797 \     \
4798
4799 \ CODE LCD_RdC                    \ -- char         Read Char
4800 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
4801 \     JMP LCD_R
4802 \ ENDCODE
4803 \     \
4804
4805 \ -------------+------+------+------+------++---+---+---+---+---------+
4806 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
4807 \ -------------+------+------+------+------++---+---+---+---+---------+
4808 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
4809 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
4810 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
4811 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
4812 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
4813 \ -------------+------+------+------+------++---+---+---+---+---------+
4814
4815
4816 \ ******************************\
4817 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
4818 \ ******************************\
4819 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
4820 \ ------------------------------\
4821 \ define LPM mode for ACCEPT    \
4822 \ ------------------------------\
4823 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
4824 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
4825 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
4826 BIT.B #SW2,&SW2_IN              \ test switch S2
4827 0= IF                           \ case of switch S2 pressed
4828     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
4829     U< IF
4830         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
4831     THEN
4832 ELSE
4833     BIT.B #SW1,&SW1_IN          \ test switch S1 input
4834     0= IF                       \ case of Switch S1 pressed
4835         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
4836         U>= IF                  \
4837             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
4838         THEN                    \
4839     THEN                        \
4840 THEN                            \
4841 RETI                            \ CPU is ON, GIE is OFF
4842 ENDASM                          \
4843     \
4844
4845
4846 \ ------------------------------\
4847 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
4848 \ ******************************\
4849 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
4850 \ ******************************\
4851 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
4852 \                               \       SMclock = 8|16|24 MHz
4853 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
4854 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
4855 \                               \       SR(9)=new Toggle bit memory (ADD on)
4856 \ ------------------------------\
4857 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
4858 \ ------------------------------\
4859 \ define LPM mode for ACCEPT    \
4860 \ ------------------------------\
4861 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
4862 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
4863 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
4864 \ ------------------------------\
4865 \ RC5_FirstStartBitHalfCycle:   \
4866 \ ------------------------------\
4867 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
4868 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
4869 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
4870 MOV     #1778,X                 \ RC5_Period in us
4871 MOV     #14,W                   \ count of loop
4872 BEGIN                           \
4873 \ ------------------------------\
4874 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
4875 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
4876     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
4877 \ RC5_Compute_3/4_Period:       \                   |
4878     RRUM    #1,X                \ X=1/2 cycle       |
4879     MOV     X,Y                 \ Y=1/2             ^
4880     RRUM    #1,Y                \ Y=1/4
4881     ADD     X,Y                 \ Y=3/4
4882 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
4883     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
4884     0= UNTIL                    \
4885 \ ------------------------------\
4886 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
4887 \ ------------------------------\
4888     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
4889     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
4890     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
4891     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
4892     SUB     #1,W                \ decrement count loop
4893 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
4894 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
4895 0<> WHILE                       \ ----> out of loop ----+
4896 \ RC5_compute_7/4_Time_out:     \                       |
4897     ADD     X,Y                 \                       |   out of bound = 7/4 period 
4898 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
4899     BEGIN                       \                       |
4900         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
4901         0>= IF                  \                       |   if cycle time out of bound
4902             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
4903             RETI                \                       |   then quit to do nothing
4904         THEN                    \                       |
4905 \ ------------------------------\                       |
4906         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
4907     0<> UNTIL                   \                   |   |
4908     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
4909 REPEAT                          \ ----> loop back --+   |
4910 \ ------------------------------\                       |
4911 \ RC5_SampleEndOf:              \ <---------------------+
4912 \ ------------------------------\
4913 BIC     #$30,&TA0CTL           \ stop timer_A0
4914 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
4915 \ ******************************\
4916 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
4917 \ ******************************\
4918 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
4919 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
4920 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
4921 BIT     #BIT13,X                \ X(13) = New_RC5_command
4922 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
4923 THEN                            \
4924 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
4925 \ ******************************\
4926 \ RC5_ComputeNewRC5word         \
4927 \ ******************************\
4928 SUB     #4,PSP                  \
4929 MOV     &BASE,2(PSP)            \ save variable BASE before use
4930 MOV     TOS,0(PSP)              \ save TOS before use
4931 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
4932 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
4933 \ ******************************\
4934 \ RC5_ComputeC6bit              \
4935 \ ******************************\
4936 BIT     #$4000,IP              \ test /C6 bit in IP
4937 0= IF   BIS #$40,TOS           \ set C6 bit in S
4938 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
4939 \ ******************************\
4940 \ RC5_CommandByteIsDone         \ RC5_code --
4941 \ ******************************\
4942
4943 \ ------------------------------\
4944 \ Display IR_RC5 code           \
4945 \ ------------------------------\
4946 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
4947 \ ------------------------------\
4948 LO2HI                           \ switch from assembler to FORTH
4949     ['] LCD_CLEAR IS CR         \ redirects CR
4950     ['] LCD_WrC  IS EMIT        \ redirects EMIT
4951     $10 BASE !                 \ change BASE to hexadecimal
4952     CR ." $" 2 U.R             \ print IR_RC5 code
4953     ['] (CR) IS CR              \ restore CR
4954     ['] (EMIT) IS EMIT          \ restore EMIT
4955 HI2LO                           \ switch from FORTH to assembler
4956 \ ------------------------------\
4957 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
4958 \ ------------------------------\
4959 MOV @PSP+,&BASE                 \ restore variable BASE
4960 RETI                            \ CPU is ON, GIE is OFF
4961 ENDASM                          \
4962     \ 
4963
4964 CODE START                      \
4965 \ ------------------------------\
4966 \ TB0CTL = %0000 0010 1001 0100\$3C0
4967 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
4968 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
4969 \                      --       \ID input divider \ 10 = /4
4970 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
4971 \                            -  \TBCLR TimerB Clear
4972 \                             - \TBIE
4973 \                              -\TBIFG
4974 \ --------------------------------\\
4975 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
4976 \              --                 \CM Capture Mode
4977 \                --               \CCIS
4978 \                   -             \SCS
4979 \                    --           \CLLD
4980 \                      -          \CAP
4981 \                        ---      \OUTMOD \ 011 = set/reset
4982 \                           -     \CCIE
4983 \                             -   \CCI
4984 \                              -  \OUT
4985 \                               - \COV
4986 \                                -\CCIFG
4987 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
4988 \ TB0EX0                          \$3E0 
4989 \ ------------------------------\
4990 \ set TimerB to make 50kHz PWM  \
4991 \ ------------------------------\
4992 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
4993 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
4994 \ ------------------------------\
4995 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
4996 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
4997 \ ------------------------------\
4998     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
4999     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
5000 \ ------------------------------\
5001 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
5002 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
5003 \ ------------------------------\
5004 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
5005 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
5006 \ ------------------------------\
5007     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
5008 \ ------------------------------\
5009 \ set TimerB to generate PWM for LCD_Vo
5010 \ ------------------------------\
5011     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
5012 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
5013     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
5014 \ ------------------------------\
5015     BIS.B #LCDVo,&LCDVo_DIR     \
5016     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
5017 \ ------------------------------\
5018     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
5019     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
5020 \ ------------------------------\
5021     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
5022     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
5023 \ ------------------------------\
5024 \ WDT interval init part        \
5025 \ ------------------------------\
5026     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
5027 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
5028 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
5029     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
5030 \ ------------------------------\
5031 \ init RC5_Int                  \
5032 \ ------------------------------\
5033     BIS.B #RC5,&IR_IE           \ enable RC5_Int
5034     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
5035 \ ------------------------------\
5036 \ init interrupt vectors
5037 \ ------------------------------\
5038     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
5039     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
5040 \ ------------------------------\
5041 \ define LPM mode for ACCEPT    \
5042 \ ------------------------------\
5043 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
5044 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
5045 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
5046
5047 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
5048
5049 \ ------------------------------\
5050 \ Init LCD 2x20                 \
5051 \ ------------------------------\
5052     $03E8 20_US                \ 1-  wait 20 ms
5053     $03 TOP_LCD                \ 2- send DB5=DB4=1
5054     $CD 20_US                  \ 3- wait 4,1 ms
5055     $03 TOP_LCD                \ 4- send again DB5=DB4=1
5056     $5 20_US                   \ 5- wait 0,1 ms
5057     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
5058     $2 20_US                   \    wait 40 us = LCD cycle
5059     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
5060     $2 20_US                   \    wait 40 us = LCD cycle
5061     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
5062     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
5063     LCD_Clear                   \ 10- "LCD_Clear"
5064     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
5065     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
5066     LCD_Clear                   \ 10- "LCD_Clear"
5067     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
5068     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
5069     CR ." I love you"   
5070     ['] (CR) IS CR              \ ' (CR) is CR
5071     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
5072     CR
5073     ."    RC5toLCD is running. Type STOP to quit"
5074 \    NOECHO                      \ uncomment to run this app without terminal connexion
5075     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
5076     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
5077 ;
5078     \
5079
5080 : STOP                  \ stops multitasking, must to be used before downloading app
5081     ['] (WARM) IS WARM  \ remove START app from FORTH init process
5082     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
5083 ;
5084     \
5085
5086
5087 RST_STATE   ;
5088
5089
5090 CODE MAX    \    n1 n2 -- n3       signed maximum
5091             CMP     @PSP,TOS    \ n2-n1
5092             S<      ?GOTO FW1   \ n2<n1
5093 BW1         ADD     #2,PSP
5094             MOV     @IP+,PC
5095 ENDCODE
5096     \
5097
5098 CODE MIN    \    n1 n2 -- n3       signed minimum
5099             CMP     @PSP,TOS     \ n2-n1
5100             S<      ?GOTO BW1    \ n2<n1
5101 FW1         MOV     @PSP+,TOS
5102             MOV     @IP+,PC
5103 ENDCODE
5104     \
5105
5106 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
5107   >R  <# 0 # #S #>  
5108   R> OVER - 0 MAX SPACES TYPE
5109 ;
5110     \
5111
5112 CODE 20_US                      \ n --      n * 20 us
5113 BEGIN                           \ 3 cycles loop + 6~  
5114 \    MOV     #5,W                \ 3 MCLK = 1 MHz
5115 \    MOV     #23,W               \ 3 MCLK = 4 MHz
5116     MOV     #51,W               \ 3 MCLK = 8 MHz
5117 \    MOV     #104,W              \ 3 MCLK = 16 MHz
5118 \    MOV     #158,W              \ 3 MCLK = 24 MHz
5119     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
5120         SUB #1,W                \ 1
5121     0= UNTIL                    \ 2
5122     SUB     #1,TOS              \ 1
5123 0= UNTIL                        \ 2
5124     MOV     @PSP+,TOS           \ 2
5125     MOV     @IP+,PC             \ 4
5126 ENDCODE
5127     \
5128
5129 CODE TOP_LCD                    \ LCD Sample
5130 \                               \ if write : %xxxxWWWW --
5131 \                               \ if read  : -- %0000RRRR
5132     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
5133     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
5134 0= IF                           \ write LCD bits pattern
5135     AND.B #LCD_DB,TOS           \ 
5136     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
5137     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
5138     MOV @PSP+,TOS               \
5139     MOV @IP+,PC
5140 THEN                            \ read LCD bits pattern
5141     SUB #2,PSP
5142     MOV TOS,0(PSP)
5143     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
5144     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
5145     AND.B #LCD_DB,TOS           \
5146     MOV @IP+,PC
5147 ENDCODE
5148     \
5149
5150 CODE LCD_W                      \ byte --       write byte to LCD 
5151     SUB #2,PSP                  \
5152     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
5153     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
5154     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
5155     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
5156 COLON                           \ high level word starts here 
5157     TOP_LCD 2 20_US             \ write high nibble first
5158     TOP_LCD 2 20_US 
5159 ;
5160     \
5161
5162 CODE LCD_WrC                    \ char --         Write Char
5163     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
5164     JMP LCD_W 
5165 ENDCODE
5166     \
5167
5168 CODE LCD_WrF                    \ func --         Write Fonction
5169     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
5170     JMP LCD_W 
5171 ENDCODE
5172     \
5173
5174 : LCD_Clear 
5175     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
5176 ;
5177     \
5178
5179 : LCD_Home 
5180     $02 LCD_WrF 100 20_us 
5181 ;
5182     \
5183
5184 \ : LCD_Entry_set       $04 OR LCD_WrF ;
5185
5186 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
5187
5188 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
5189
5190 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
5191
5192 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
5193
5194 \ : LCD_Goto            $80 OR LCD_WrF ;
5195
5196 \ CODE LCD_R                      \ -- byte       read byte from LCD
5197 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
5198 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
5199 \ COLON                           \ starts a FORTH word
5200 \     TOP_LCD 2 20_us             \ -- %0000HHHH
5201 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
5202 \ HI2LO                           \ switch from FORTH to assembler
5203 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
5204 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
5205 \     MOV @RSP+,IP                \ restore IP saved by COLON
5206 \     MOV @IP+,PC                 \
5207 \ ENDCODE
5208 \     \
5209
5210 \ CODE LCD_RdS                    \ -- status       Read Status
5211 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
5212 \     JMP LCD_R
5213 \ ENDCODE
5214 \     \
5215
5216 \ CODE LCD_RdC                    \ -- char         Read Char
5217 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
5218 \     JMP LCD_R
5219 \ ENDCODE
5220 \     \
5221
5222 \ -------------+------+------+------+------++---+---+---+---+---------+
5223 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
5224 \ -------------+------+------+------+------++---+---+---+---+---------+
5225 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
5226 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
5227 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
5228 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
5229 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
5230 \ -------------+------+------+------+------++---+---+---+---+---------+
5231
5232
5233 \ ******************************\
5234 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
5235 \ ******************************\
5236 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
5237 \ ------------------------------\
5238 \ define LPM mode for ACCEPT    \
5239 \ ------------------------------\
5240 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
5241 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
5242 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
5243 BIT.B #SW2,&SW2_IN              \ test switch S2
5244 0= IF                           \ case of switch S2 pressed
5245     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
5246     U< IF
5247         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
5248     THEN
5249 ELSE
5250     BIT.B #SW1,&SW1_IN          \ test switch S1 input
5251     0= IF                       \ case of Switch S1 pressed
5252         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
5253         U>= IF                  \
5254             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
5255         THEN                    \
5256     THEN                        \
5257 THEN                            \
5258 RETI                            \ CPU is ON, GIE is OFF
5259 ENDASM                          \
5260     \
5261
5262
5263 \ ------------------------------\
5264 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
5265 \ ******************************\
5266 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
5267 \ ******************************\
5268 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
5269 \                               \       SMclock = 8|16|24 MHz
5270 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
5271 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
5272 \                               \       SR(9)=new Toggle bit memory (ADD on)
5273 \ ------------------------------\
5274 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
5275 \ ------------------------------\
5276 \ define LPM mode for ACCEPT    \
5277 \ ------------------------------\
5278 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
5279 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
5280 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
5281 \ ------------------------------\
5282 \ RC5_FirstStartBitHalfCycle:   \
5283 \ ------------------------------\
5284 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
5285 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
5286 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
5287 MOV     #1778,X                 \ RC5_Period in us
5288 MOV     #14,W                   \ count of loop
5289 BEGIN                           \
5290 \ ------------------------------\
5291 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
5292 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
5293     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
5294 \ RC5_Compute_3/4_Period:       \                   |
5295     RRUM    #1,X                \ X=1/2 cycle       |
5296     MOV     X,Y                 \ Y=1/2             ^
5297     RRUM    #1,Y                \ Y=1/4
5298     ADD     X,Y                 \ Y=3/4
5299 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
5300     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
5301     0= UNTIL                    \
5302 \ ------------------------------\
5303 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
5304 \ ------------------------------\
5305     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
5306     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
5307     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
5308     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
5309     SUB     #1,W                \ decrement count loop
5310 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
5311 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
5312 0<> WHILE                       \ ----> out of loop ----+
5313 \ RC5_compute_7/4_Time_out:     \                       |
5314     ADD     X,Y                 \                       |   out of bound = 7/4 period 
5315 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
5316     BEGIN                       \                       |
5317         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
5318         0>= IF                  \                       |   if cycle time out of bound
5319             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
5320             RETI                \                       |   then quit to do nothing
5321         THEN                    \                       |
5322 \ ------------------------------\                       |
5323         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
5324     0<> UNTIL                   \                   |   |
5325     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
5326 REPEAT                          \ ----> loop back --+   |
5327 \ ------------------------------\                       |
5328 \ RC5_SampleEndOf:              \ <---------------------+
5329 \ ------------------------------\
5330 BIC     #$30,&TA0CTL           \ stop timer_A0
5331 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
5332 \ ******************************\
5333 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
5334 \ ******************************\
5335 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
5336 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
5337 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
5338 BIT     #BIT13,X                \ X(13) = New_RC5_command
5339 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
5340 THEN                            \
5341 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
5342 \ ******************************\
5343 \ RC5_ComputeNewRC5word         \
5344 \ ******************************\
5345 SUB     #4,PSP                  \
5346 MOV     &BASE,2(PSP)            \ save variable BASE before use
5347 MOV     TOS,0(PSP)              \ save TOS before use
5348 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
5349 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
5350 \ ******************************\
5351 \ RC5_ComputeC6bit              \
5352 \ ******************************\
5353 BIT     #$4000,IP              \ test /C6 bit in IP
5354 0= IF   BIS #$40,TOS           \ set C6 bit in S
5355 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
5356 \ ******************************\
5357 \ RC5_CommandByteIsDone         \ RC5_code --
5358 \ ******************************\
5359
5360 \ ------------------------------\
5361 \ Display IR_RC5 code           \
5362 \ ------------------------------\
5363 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
5364 \ ------------------------------\
5365 LO2HI                           \ switch from assembler to FORTH
5366     ['] LCD_CLEAR IS CR         \ redirects CR
5367     ['] LCD_WrC  IS EMIT        \ redirects EMIT
5368     $10 BASE !                 \ change BASE to hexadecimal
5369     CR ." $" 2 U.R             \ print IR_RC5 code
5370     ['] (CR) IS CR              \ restore CR
5371     ['] (EMIT) IS EMIT          \ restore EMIT
5372 HI2LO                           \ switch from FORTH to assembler
5373 \ ------------------------------\
5374 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
5375 \ ------------------------------\
5376 MOV @PSP+,&BASE                 \ restore variable BASE
5377 RETI                            \ CPU is ON, GIE is OFF
5378 ENDASM                          \
5379     \ 
5380
5381 CODE START                      \
5382 \ ------------------------------\
5383 \ TB0CTL = %0000 0010 1001 0100\$3C0
5384 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
5385 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
5386 \                      --       \ID input divider \ 10 = /4
5387 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
5388 \                            -  \TBCLR TimerB Clear
5389 \                             - \TBIE
5390 \                              -\TBIFG
5391 \ --------------------------------\\
5392 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
5393 \              --                 \CM Capture Mode
5394 \                --               \CCIS
5395 \                   -             \SCS
5396 \                    --           \CLLD
5397 \                      -          \CAP
5398 \                        ---      \OUTMOD \ 011 = set/reset
5399 \                           -     \CCIE
5400 \                             -   \CCI
5401 \                              -  \OUT
5402 \                               - \COV
5403 \                                -\CCIFG
5404 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
5405 \ TB0EX0                          \$3E0 
5406 \ ------------------------------\
5407 \ set TimerB to make 50kHz PWM  \
5408 \ ------------------------------\
5409 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
5410 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
5411 \ ------------------------------\
5412 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
5413 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
5414 \ ------------------------------\
5415     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
5416     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
5417 \ ------------------------------\
5418 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
5419 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
5420 \ ------------------------------\
5421 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
5422 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
5423 \ ------------------------------\
5424     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
5425 \ ------------------------------\
5426 \ set TimerB to generate PWM for LCD_Vo
5427 \ ------------------------------\
5428     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
5429 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
5430     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
5431 \ ------------------------------\
5432     BIS.B #LCDVo,&LCDVo_DIR     \
5433     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
5434 \ ------------------------------\
5435     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
5436     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
5437 \ ------------------------------\
5438     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
5439     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
5440 \ ------------------------------\
5441 \ WDT interval init part        \
5442 \ ------------------------------\
5443     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
5444 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
5445 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
5446     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
5447 \ ------------------------------\
5448 \ init RC5_Int                  \
5449 \ ------------------------------\
5450     BIS.B #RC5,&IR_IE           \ enable RC5_Int
5451     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
5452 \ ------------------------------\
5453 \ init interrupt vectors
5454 \ ------------------------------\
5455     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
5456     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
5457 \ ------------------------------\
5458 \ define LPM mode for ACCEPT    \
5459 \ ------------------------------\
5460 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
5461 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
5462 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
5463
5464 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
5465
5466 \ ------------------------------\
5467 \ Init LCD 2x20                 \
5468 \ ------------------------------\
5469     $03E8 20_US                \ 1-  wait 20 ms
5470     $03 TOP_LCD                \ 2- send DB5=DB4=1
5471     $CD 20_US                  \ 3- wait 4,1 ms
5472     $03 TOP_LCD                \ 4- send again DB5=DB4=1
5473     $5 20_US                   \ 5- wait 0,1 ms
5474     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
5475     $2 20_US                   \    wait 40 us = LCD cycle
5476     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
5477     $2 20_US                   \    wait 40 us = LCD cycle
5478     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
5479     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
5480     LCD_Clear                   \ 10- "LCD_Clear"
5481     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
5482     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
5483     LCD_Clear                   \ 10- "LCD_Clear"
5484     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
5485     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
5486     CR ." I love you"   
5487     ['] (CR) IS CR              \ ' (CR) is CR
5488     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
5489     CR
5490     ."    RC5toLCD is running. Type STOP to quit"
5491 \    NOECHO                      \ uncomment to run this app without terminal connexion
5492     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
5493     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
5494 ;
5495     \
5496
5497 : STOP                  \ stops multitasking, must to be used before downloading app
5498     ['] (WARM) IS WARM  \ remove START app from FORTH init process
5499     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
5500 ;
5501     \
5502
5503
5504 RST_STATE   ;
5505
5506
5507 CODE MAX    \    n1 n2 -- n3       signed maximum
5508             CMP     @PSP,TOS    \ n2-n1
5509             S<      ?GOTO FW1   \ n2<n1
5510 BW1         ADD     #2,PSP
5511             MOV     @IP+,PC
5512 ENDCODE
5513     \
5514
5515 CODE MIN    \    n1 n2 -- n3       signed minimum
5516             CMP     @PSP,TOS     \ n2-n1
5517             S<      ?GOTO BW1    \ n2<n1
5518 FW1         MOV     @PSP+,TOS
5519             MOV     @IP+,PC
5520 ENDCODE
5521     \
5522
5523 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
5524   >R  <# 0 # #S #>  
5525   R> OVER - 0 MAX SPACES TYPE
5526 ;
5527     \
5528
5529 CODE 20_US                      \ n --      n * 20 us
5530 BEGIN                           \ 3 cycles loop + 6~  
5531 \    MOV     #5,W                \ 3 MCLK = 1 MHz
5532 \    MOV     #23,W               \ 3 MCLK = 4 MHz
5533     MOV     #51,W               \ 3 MCLK = 8 MHz
5534 \    MOV     #104,W              \ 3 MCLK = 16 MHz
5535 \    MOV     #158,W              \ 3 MCLK = 24 MHz
5536     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
5537         SUB #1,W                \ 1
5538     0= UNTIL                    \ 2
5539     SUB     #1,TOS              \ 1
5540 0= UNTIL                        \ 2
5541     MOV     @PSP+,TOS           \ 2
5542     MOV     @IP+,PC             \ 4
5543 ENDCODE
5544     \
5545
5546 CODE TOP_LCD                    \ LCD Sample
5547 \                               \ if write : %xxxxWWWW --
5548 \                               \ if read  : -- %0000RRRR
5549     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
5550     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
5551 0= IF                           \ write LCD bits pattern
5552     AND.B #LCD_DB,TOS           \ 
5553     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
5554     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
5555     MOV @PSP+,TOS               \
5556     MOV @IP+,PC
5557 THEN                            \ read LCD bits pattern
5558     SUB #2,PSP
5559     MOV TOS,0(PSP)
5560     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
5561     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
5562     AND.B #LCD_DB,TOS           \
5563     MOV @IP+,PC
5564 ENDCODE
5565     \
5566
5567 CODE LCD_W                      \ byte --       write byte to LCD 
5568     SUB #2,PSP                  \
5569     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
5570     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
5571     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
5572     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
5573 COLON                           \ high level word starts here 
5574     TOP_LCD 2 20_US             \ write high nibble first
5575     TOP_LCD 2 20_US 
5576 ;
5577     \
5578
5579 CODE LCD_WrC                    \ char --         Write Char
5580     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
5581     JMP LCD_W 
5582 ENDCODE
5583     \
5584
5585 CODE LCD_WrF                    \ func --         Write Fonction
5586     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
5587     JMP LCD_W 
5588 ENDCODE
5589     \
5590
5591 : LCD_Clear 
5592     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
5593 ;
5594     \
5595
5596 : LCD_Home 
5597     $02 LCD_WrF 100 20_us 
5598 ;
5599     \
5600
5601 \ : LCD_Entry_set       $04 OR LCD_WrF ;
5602
5603 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
5604
5605 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
5606
5607 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
5608
5609 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
5610
5611 \ : LCD_Goto            $80 OR LCD_WrF ;
5612
5613 \ CODE LCD_R                      \ -- byte       read byte from LCD
5614 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
5615 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
5616 \ COLON                           \ starts a FORTH word
5617 \     TOP_LCD 2 20_us             \ -- %0000HHHH
5618 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
5619 \ HI2LO                           \ switch from FORTH to assembler
5620 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
5621 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
5622 \     MOV @RSP+,IP                \ restore IP saved by COLON
5623 \     MOV @IP+,PC                 \
5624 \ ENDCODE
5625 \     \
5626
5627 \ CODE LCD_RdS                    \ -- status       Read Status
5628 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
5629 \     JMP LCD_R
5630 \ ENDCODE
5631 \     \
5632
5633 \ CODE LCD_RdC                    \ -- char         Read Char
5634 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
5635 \     JMP LCD_R
5636 \ ENDCODE
5637 \     \
5638
5639 \ -------------+------+------+------+------++---+---+---+---+---------+
5640 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
5641 \ -------------+------+------+------+------++---+---+---+---+---------+
5642 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
5643 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
5644 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
5645 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
5646 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
5647 \ -------------+------+------+------+------++---+---+---+---+---------+
5648
5649
5650 \ ******************************\
5651 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
5652 \ ******************************\
5653 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
5654 \ ------------------------------\
5655 \ define LPM mode for ACCEPT    \
5656 \ ------------------------------\
5657 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
5658 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
5659 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
5660 BIT.B #SW2,&SW2_IN              \ test switch S2
5661 0= IF                           \ case of switch S2 pressed
5662     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
5663     U< IF
5664         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
5665     THEN
5666 ELSE
5667     BIT.B #SW1,&SW1_IN          \ test switch S1 input
5668     0= IF                       \ case of Switch S1 pressed
5669         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
5670         U>= IF                  \
5671             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
5672         THEN                    \
5673     THEN                        \
5674 THEN                            \
5675 RETI                            \ CPU is ON, GIE is OFF
5676 ENDASM                          \
5677     \
5678
5679
5680 \ ------------------------------\
5681 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
5682 \ ******************************\
5683 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
5684 \ ******************************\
5685 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
5686 \                               \       SMclock = 8|16|24 MHz
5687 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
5688 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
5689 \                               \       SR(9)=new Toggle bit memory (ADD on)
5690 \ ------------------------------\
5691 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
5692 \ ------------------------------\
5693 \ define LPM mode for ACCEPT    \
5694 \ ------------------------------\
5695 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
5696 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
5697 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
5698 \ ------------------------------\
5699 \ RC5_FirstStartBitHalfCycle:   \
5700 \ ------------------------------\
5701 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
5702 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
5703 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
5704 MOV     #1778,X                 \ RC5_Period in us
5705 MOV     #14,W                   \ count of loop
5706 BEGIN                           \
5707 \ ------------------------------\
5708 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
5709 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
5710     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
5711 \ RC5_Compute_3/4_Period:       \                   |
5712     RRUM    #1,X                \ X=1/2 cycle       |
5713     MOV     X,Y                 \ Y=1/2             ^
5714     RRUM    #1,Y                \ Y=1/4
5715     ADD     X,Y                 \ Y=3/4
5716 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
5717     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
5718     0= UNTIL                    \
5719 \ ------------------------------\
5720 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
5721 \ ------------------------------\
5722     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
5723     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
5724     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
5725     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
5726     SUB     #1,W                \ decrement count loop
5727 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
5728 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
5729 0<> WHILE                       \ ----> out of loop ----+
5730 \ RC5_compute_7/4_Time_out:     \                       |
5731     ADD     X,Y                 \                       |   out of bound = 7/4 period 
5732 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
5733     BEGIN                       \                       |
5734         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
5735         0>= IF                  \                       |   if cycle time out of bound
5736             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
5737             RETI                \                       |   then quit to do nothing
5738         THEN                    \                       |
5739 \ ------------------------------\                       |
5740         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
5741     0<> UNTIL                   \                   |   |
5742     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
5743 REPEAT                          \ ----> loop back --+   |
5744 \ ------------------------------\                       |
5745 \ RC5_SampleEndOf:              \ <---------------------+
5746 \ ------------------------------\
5747 BIC     #$30,&TA0CTL           \ stop timer_A0
5748 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
5749 \ ******************************\
5750 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
5751 \ ******************************\
5752 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
5753 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
5754 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
5755 BIT     #BIT13,X                \ X(13) = New_RC5_command
5756 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
5757 THEN                            \
5758 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
5759 \ ******************************\
5760 \ RC5_ComputeNewRC5word         \
5761 \ ******************************\
5762 SUB     #4,PSP                  \
5763 MOV     &BASE,2(PSP)            \ save variable BASE before use
5764 MOV     TOS,0(PSP)              \ save TOS before use
5765 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
5766 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
5767 \ ******************************\
5768 \ RC5_ComputeC6bit              \
5769 \ ******************************\
5770 BIT     #$4000,IP              \ test /C6 bit in IP
5771 0= IF   BIS #$40,TOS           \ set C6 bit in S
5772 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
5773 \ ******************************\
5774 \ RC5_CommandByteIsDone         \ RC5_code --
5775 \ ******************************\
5776
5777 \ ------------------------------\
5778 \ Display IR_RC5 code           \
5779 \ ------------------------------\
5780 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
5781 \ ------------------------------\
5782 LO2HI                           \ switch from assembler to FORTH
5783     ['] LCD_CLEAR IS CR         \ redirects CR
5784     ['] LCD_WrC  IS EMIT        \ redirects EMIT
5785     $10 BASE !                 \ change BASE to hexadecimal
5786     CR ." $" 2 U.R             \ print IR_RC5 code
5787     ['] (CR) IS CR              \ restore CR
5788     ['] (EMIT) IS EMIT          \ restore EMIT
5789 HI2LO                           \ switch from FORTH to assembler
5790 \ ------------------------------\
5791 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
5792 \ ------------------------------\
5793 MOV @PSP+,&BASE                 \ restore variable BASE
5794 RETI                            \ CPU is ON, GIE is OFF
5795 ENDASM                          \
5796     \ 
5797
5798 CODE START                      \
5799 \ ------------------------------\
5800 \ TB0CTL = %0000 0010 1001 0100\$3C0
5801 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
5802 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
5803 \                      --       \ID input divider \ 10 = /4
5804 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
5805 \                            -  \TBCLR TimerB Clear
5806 \                             - \TBIE
5807 \                              -\TBIFG
5808 \ --------------------------------\\
5809 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
5810 \              --                 \CM Capture Mode
5811 \                --               \CCIS
5812 \                   -             \SCS
5813 \                    --           \CLLD
5814 \                      -          \CAP
5815 \                        ---      \OUTMOD \ 011 = set/reset
5816 \                           -     \CCIE
5817 \                             -   \CCI
5818 \                              -  \OUT
5819 \                               - \COV
5820 \                                -\CCIFG
5821 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
5822 \ TB0EX0                          \$3E0 
5823 \ ------------------------------\
5824 \ set TimerB to make 50kHz PWM  \
5825 \ ------------------------------\
5826 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
5827 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
5828 \ ------------------------------\
5829 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
5830 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
5831 \ ------------------------------\
5832     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
5833     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
5834 \ ------------------------------\
5835 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
5836 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
5837 \ ------------------------------\
5838 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
5839 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
5840 \ ------------------------------\
5841     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
5842 \ ------------------------------\
5843 \ set TimerB to generate PWM for LCD_Vo
5844 \ ------------------------------\
5845     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
5846 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
5847     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
5848 \ ------------------------------\
5849     BIS.B #LCDVo,&LCDVo_DIR     \
5850     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
5851 \ ------------------------------\
5852     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
5853     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
5854 \ ------------------------------\
5855     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
5856     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
5857 \ ------------------------------\
5858 \ WDT interval init part        \
5859 \ ------------------------------\
5860     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
5861 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
5862 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
5863     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
5864 \ ------------------------------\
5865 \ init RC5_Int                  \
5866 \ ------------------------------\
5867     BIS.B #RC5,&IR_IE           \ enable RC5_Int
5868     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
5869 \ ------------------------------\
5870 \ init interrupt vectors
5871 \ ------------------------------\
5872     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
5873     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
5874 \ ------------------------------\
5875 \ define LPM mode for ACCEPT    \
5876 \ ------------------------------\
5877 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
5878 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
5879 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
5880
5881 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
5882
5883 \ ------------------------------\
5884 \ Init LCD 2x20                 \
5885 \ ------------------------------\
5886     $03E8 20_US                \ 1-  wait 20 ms
5887     $03 TOP_LCD                \ 2- send DB5=DB4=1
5888     $CD 20_US                  \ 3- wait 4,1 ms
5889     $03 TOP_LCD                \ 4- send again DB5=DB4=1
5890     $5 20_US                   \ 5- wait 0,1 ms
5891     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
5892     $2 20_US                   \    wait 40 us = LCD cycle
5893     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
5894     $2 20_US                   \    wait 40 us = LCD cycle
5895     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
5896     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
5897     LCD_Clear                   \ 10- "LCD_Clear"
5898     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
5899     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
5900     LCD_Clear                   \ 10- "LCD_Clear"
5901     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
5902     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
5903     CR ." I love you"   
5904     ['] (CR) IS CR              \ ' (CR) is CR
5905     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
5906     CR
5907     ."    RC5toLCD is running. Type STOP to quit"
5908 \    NOECHO                      \ uncomment to run this app without terminal connexion
5909     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
5910     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
5911 ;
5912     \
5913
5914 : STOP                  \ stops multitasking, must to be used before downloading app
5915     ['] (WARM) IS WARM  \ remove START app from FORTH init process
5916     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
5917 ;
5918     \
5919
5920
5921 RST_STATE   ;
5922
5923
5924 CODE MAX    \    n1 n2 -- n3       signed maximum
5925             CMP     @PSP,TOS    \ n2-n1
5926             S<      ?GOTO FW1   \ n2<n1
5927 BW1         ADD     #2,PSP
5928             MOV     @IP+,PC
5929 ENDCODE
5930     \
5931
5932 CODE MIN    \    n1 n2 -- n3       signed minimum
5933             CMP     @PSP,TOS     \ n2-n1
5934             S<      ?GOTO BW1    \ n2<n1
5935 FW1         MOV     @PSP+,TOS
5936             MOV     @IP+,PC
5937 ENDCODE
5938     \
5939
5940 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
5941   >R  <# 0 # #S #>  
5942   R> OVER - 0 MAX SPACES TYPE
5943 ;
5944     \
5945
5946 CODE 20_US                      \ n --      n * 20 us
5947 BEGIN                           \ 3 cycles loop + 6~  
5948 \    MOV     #5,W                \ 3 MCLK = 1 MHz
5949 \    MOV     #23,W               \ 3 MCLK = 4 MHz
5950     MOV     #51,W               \ 3 MCLK = 8 MHz
5951 \    MOV     #104,W              \ 3 MCLK = 16 MHz
5952 \    MOV     #158,W              \ 3 MCLK = 24 MHz
5953     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
5954         SUB #1,W                \ 1
5955     0= UNTIL                    \ 2
5956     SUB     #1,TOS              \ 1
5957 0= UNTIL                        \ 2
5958     MOV     @PSP+,TOS           \ 2
5959     MOV     @IP+,PC             \ 4
5960 ENDCODE
5961     \
5962
5963 CODE TOP_LCD                    \ LCD Sample
5964 \                               \ if write : %xxxxWWWW --
5965 \                               \ if read  : -- %0000RRRR
5966     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
5967     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
5968 0= IF                           \ write LCD bits pattern
5969     AND.B #LCD_DB,TOS           \ 
5970     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
5971     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
5972     MOV @PSP+,TOS               \
5973     MOV @IP+,PC
5974 THEN                            \ read LCD bits pattern
5975     SUB #2,PSP
5976     MOV TOS,0(PSP)
5977     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
5978     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
5979     AND.B #LCD_DB,TOS           \
5980     MOV @IP+,PC
5981 ENDCODE
5982     \
5983
5984 CODE LCD_W                      \ byte --       write byte to LCD 
5985     SUB #2,PSP                  \
5986     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
5987     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
5988     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
5989     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
5990 COLON                           \ high level word starts here 
5991     TOP_LCD 2 20_US             \ write high nibble first
5992     TOP_LCD 2 20_US 
5993 ;
5994     \
5995
5996 CODE LCD_WrC                    \ char --         Write Char
5997     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
5998     JMP LCD_W 
5999 ENDCODE
6000     \
6001
6002 CODE LCD_WrF                    \ func --         Write Fonction
6003     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
6004     JMP LCD_W 
6005 ENDCODE
6006     \
6007
6008 : LCD_Clear 
6009     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
6010 ;
6011     \
6012
6013 : LCD_Home 
6014     $02 LCD_WrF 100 20_us 
6015 ;
6016     \
6017
6018 \ : LCD_Entry_set       $04 OR LCD_WrF ;
6019
6020 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
6021
6022 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
6023
6024 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
6025
6026 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
6027
6028 \ : LCD_Goto            $80 OR LCD_WrF ;
6029
6030 \ CODE LCD_R                      \ -- byte       read byte from LCD
6031 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
6032 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
6033 \ COLON                           \ starts a FORTH word
6034 \     TOP_LCD 2 20_us             \ -- %0000HHHH
6035 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
6036 \ HI2LO                           \ switch from FORTH to assembler
6037 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
6038 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
6039 \     MOV @RSP+,IP                \ restore IP saved by COLON
6040 \     MOV @IP+,PC                 \
6041 \ ENDCODE
6042 \     \
6043
6044 \ CODE LCD_RdS                    \ -- status       Read Status
6045 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
6046 \     JMP LCD_R
6047 \ ENDCODE
6048 \     \
6049
6050 \ CODE LCD_RdC                    \ -- char         Read Char
6051 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
6052 \     JMP LCD_R
6053 \ ENDCODE
6054 \     \
6055
6056 \ -------------+------+------+------+------++---+---+---+---+---------+
6057 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
6058 \ -------------+------+------+------+------++---+---+---+---+---------+
6059 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
6060 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
6061 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
6062 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
6063 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
6064 \ -------------+------+------+------+------++---+---+---+---+---------+
6065
6066
6067 \ ******************************\
6068 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
6069 \ ******************************\
6070 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
6071 \ ------------------------------\
6072 \ define LPM mode for ACCEPT    \
6073 \ ------------------------------\
6074 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
6075 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
6076 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
6077 BIT.B #SW2,&SW2_IN              \ test switch S2
6078 0= IF                           \ case of switch S2 pressed
6079     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
6080     U< IF
6081         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
6082     THEN
6083 ELSE
6084     BIT.B #SW1,&SW1_IN          \ test switch S1 input
6085     0= IF                       \ case of Switch S1 pressed
6086         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
6087         U>= IF                  \
6088             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
6089         THEN                    \
6090     THEN                        \
6091 THEN                            \
6092 RETI                            \ CPU is ON, GIE is OFF
6093 ENDASM                          \
6094     \
6095
6096
6097 \ ------------------------------\
6098 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
6099 \ ******************************\
6100 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
6101 \ ******************************\
6102 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
6103 \                               \       SMclock = 8|16|24 MHz
6104 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
6105 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
6106 \                               \       SR(9)=new Toggle bit memory (ADD on)
6107 \ ------------------------------\
6108 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
6109 \ ------------------------------\
6110 \ define LPM mode for ACCEPT    \
6111 \ ------------------------------\
6112 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
6113 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
6114 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
6115 \ ------------------------------\
6116 \ RC5_FirstStartBitHalfCycle:   \
6117 \ ------------------------------\
6118 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
6119 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
6120 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
6121 MOV     #1778,X                 \ RC5_Period in us
6122 MOV     #14,W                   \ count of loop
6123 BEGIN                           \
6124 \ ------------------------------\
6125 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
6126 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
6127     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
6128 \ RC5_Compute_3/4_Period:       \                   |
6129     RRUM    #1,X                \ X=1/2 cycle       |
6130     MOV     X,Y                 \ Y=1/2             ^
6131     RRUM    #1,Y                \ Y=1/4
6132     ADD     X,Y                 \ Y=3/4
6133 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
6134     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
6135     0= UNTIL                    \
6136 \ ------------------------------\
6137 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
6138 \ ------------------------------\
6139     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
6140     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
6141     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
6142     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
6143     SUB     #1,W                \ decrement count loop
6144 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
6145 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
6146 0<> WHILE                       \ ----> out of loop ----+
6147 \ RC5_compute_7/4_Time_out:     \                       |
6148     ADD     X,Y                 \                       |   out of bound = 7/4 period 
6149 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
6150     BEGIN                       \                       |
6151         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
6152         0>= IF                  \                       |   if cycle time out of bound
6153             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
6154             RETI                \                       |   then quit to do nothing
6155         THEN                    \                       |
6156 \ ------------------------------\                       |
6157         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
6158     0<> UNTIL                   \                   |   |
6159     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
6160 REPEAT                          \ ----> loop back --+   |
6161 \ ------------------------------\                       |
6162 \ RC5_SampleEndOf:              \ <---------------------+
6163 \ ------------------------------\
6164 BIC     #$30,&TA0CTL           \ stop timer_A0
6165 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
6166 \ ******************************\
6167 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
6168 \ ******************************\
6169 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
6170 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
6171 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
6172 BIT     #BIT13,X                \ X(13) = New_RC5_command
6173 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
6174 THEN                            \
6175 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
6176 \ ******************************\
6177 \ RC5_ComputeNewRC5word         \
6178 \ ******************************\
6179 SUB     #4,PSP                  \
6180 MOV     &BASE,2(PSP)            \ save variable BASE before use
6181 MOV     TOS,0(PSP)              \ save TOS before use
6182 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
6183 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
6184 \ ******************************\
6185 \ RC5_ComputeC6bit              \
6186 \ ******************************\
6187 BIT     #$4000,IP              \ test /C6 bit in IP
6188 0= IF   BIS #$40,TOS           \ set C6 bit in S
6189 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
6190 \ ******************************\
6191 \ RC5_CommandByteIsDone         \ RC5_code --
6192 \ ******************************\
6193
6194 \ ------------------------------\
6195 \ Display IR_RC5 code           \
6196 \ ------------------------------\
6197 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
6198 \ ------------------------------\
6199 LO2HI                           \ switch from assembler to FORTH
6200     ['] LCD_CLEAR IS CR         \ redirects CR
6201     ['] LCD_WrC  IS EMIT        \ redirects EMIT
6202     $10 BASE !                 \ change BASE to hexadecimal
6203     CR ." $" 2 U.R             \ print IR_RC5 code
6204     ['] (CR) IS CR              \ restore CR
6205     ['] (EMIT) IS EMIT          \ restore EMIT
6206 HI2LO                           \ switch from FORTH to assembler
6207 \ ------------------------------\
6208 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
6209 \ ------------------------------\
6210 MOV @PSP+,&BASE                 \ restore variable BASE
6211 RETI                            \ CPU is ON, GIE is OFF
6212 ENDASM                          \
6213     \ 
6214
6215 CODE START                      \
6216 \ ------------------------------\
6217 \ TB0CTL = %0000 0010 1001 0100\$3C0
6218 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
6219 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
6220 \                      --       \ID input divider \ 10 = /4
6221 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
6222 \                            -  \TBCLR TimerB Clear
6223 \                             - \TBIE
6224 \                              -\TBIFG
6225 \ --------------------------------\\
6226 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
6227 \              --                 \CM Capture Mode
6228 \                --               \CCIS
6229 \                   -             \SCS
6230 \                    --           \CLLD
6231 \                      -          \CAP
6232 \                        ---      \OUTMOD \ 011 = set/reset
6233 \                           -     \CCIE
6234 \                             -   \CCI
6235 \                              -  \OUT
6236 \                               - \COV
6237 \                                -\CCIFG
6238 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
6239 \ TB0EX0                          \$3E0 
6240 \ ------------------------------\
6241 \ set TimerB to make 50kHz PWM  \
6242 \ ------------------------------\
6243 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
6244 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
6245 \ ------------------------------\
6246 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
6247 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
6248 \ ------------------------------\
6249     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
6250     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
6251 \ ------------------------------\
6252 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
6253 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
6254 \ ------------------------------\
6255 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
6256 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
6257 \ ------------------------------\
6258     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
6259 \ ------------------------------\
6260 \ set TimerB to generate PWM for LCD_Vo
6261 \ ------------------------------\
6262     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
6263 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
6264     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
6265 \ ------------------------------\
6266     BIS.B #LCDVo,&LCDVo_DIR     \
6267     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
6268 \ ------------------------------\
6269     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
6270     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
6271 \ ------------------------------\
6272     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
6273     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
6274 \ ------------------------------\
6275 \ WDT interval init part        \
6276 \ ------------------------------\
6277     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
6278 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
6279 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
6280     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
6281 \ ------------------------------\
6282 \ init RC5_Int                  \
6283 \ ------------------------------\
6284     BIS.B #RC5,&IR_IE           \ enable RC5_Int
6285     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
6286 \ ------------------------------\
6287 \ init interrupt vectors
6288 \ ------------------------------\
6289     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
6290     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
6291 \ ------------------------------\
6292 \ define LPM mode for ACCEPT    \
6293 \ ------------------------------\
6294 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
6295 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
6296 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
6297
6298 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
6299
6300 \ ------------------------------\
6301 \ Init LCD 2x20                 \
6302 \ ------------------------------\
6303     $03E8 20_US                \ 1-  wait 20 ms
6304     $03 TOP_LCD                \ 2- send DB5=DB4=1
6305     $CD 20_US                  \ 3- wait 4,1 ms
6306     $03 TOP_LCD                \ 4- send again DB5=DB4=1
6307     $5 20_US                   \ 5- wait 0,1 ms
6308     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
6309     $2 20_US                   \    wait 40 us = LCD cycle
6310     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
6311     $2 20_US                   \    wait 40 us = LCD cycle
6312     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
6313     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
6314     LCD_Clear                   \ 10- "LCD_Clear"
6315     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
6316     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
6317     LCD_Clear                   \ 10- "LCD_Clear"
6318     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
6319     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
6320     CR ." I love you"   
6321     ['] (CR) IS CR              \ ' (CR) is CR
6322     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
6323     CR
6324     ."    RC5toLCD is running. Type STOP to quit"
6325 \    NOECHO                      \ uncomment to run this app without terminal connexion
6326     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
6327     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
6328 ;
6329     \
6330
6331 : STOP                  \ stops multitasking, must to be used before downloading app
6332     ['] (WARM) IS WARM  \ remove START app from FORTH init process
6333     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
6334 ;
6335     \
6336
6337
6338 RST_STATE   ;
6339
6340
6341 CODE MAX    \    n1 n2 -- n3       signed maximum
6342             CMP     @PSP,TOS    \ n2-n1
6343             S<      ?GOTO FW1   \ n2<n1
6344 BW1         ADD     #2,PSP
6345             MOV     @IP+,PC
6346 ENDCODE
6347     \
6348
6349 CODE MIN    \    n1 n2 -- n3       signed minimum
6350             CMP     @PSP,TOS     \ n2-n1
6351             S<      ?GOTO BW1    \ n2<n1
6352 FW1         MOV     @PSP+,TOS
6353             MOV     @IP+,PC
6354 ENDCODE
6355     \
6356
6357 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
6358   >R  <# 0 # #S #>  
6359   R> OVER - 0 MAX SPACES TYPE
6360 ;
6361     \
6362
6363 CODE 20_US                      \ n --      n * 20 us
6364 BEGIN                           \ 3 cycles loop + 6~  
6365 \    MOV     #5,W                \ 3 MCLK = 1 MHz
6366 \    MOV     #23,W               \ 3 MCLK = 4 MHz
6367     MOV     #51,W               \ 3 MCLK = 8 MHz
6368 \    MOV     #104,W              \ 3 MCLK = 16 MHz
6369 \    MOV     #158,W              \ 3 MCLK = 24 MHz
6370     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
6371         SUB #1,W                \ 1
6372     0= UNTIL                    \ 2
6373     SUB     #1,TOS              \ 1
6374 0= UNTIL                        \ 2
6375     MOV     @PSP+,TOS           \ 2
6376     MOV     @IP+,PC             \ 4
6377 ENDCODE
6378     \
6379
6380 CODE TOP_LCD                    \ LCD Sample
6381 \                               \ if write : %xxxxWWWW --
6382 \                               \ if read  : -- %0000RRRR
6383     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
6384     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
6385 0= IF                           \ write LCD bits pattern
6386     AND.B #LCD_DB,TOS           \ 
6387     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
6388     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
6389     MOV @PSP+,TOS               \
6390     MOV @IP+,PC
6391 THEN                            \ read LCD bits pattern
6392     SUB #2,PSP
6393     MOV TOS,0(PSP)
6394     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
6395     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
6396     AND.B #LCD_DB,TOS           \
6397     MOV @IP+,PC
6398 ENDCODE
6399     \
6400
6401 CODE LCD_W                      \ byte --       write byte to LCD 
6402     SUB #2,PSP                  \
6403     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
6404     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
6405     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
6406     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
6407 COLON                           \ high level word starts here 
6408     TOP_LCD 2 20_US             \ write high nibble first
6409     TOP_LCD 2 20_US 
6410 ;
6411     \
6412
6413 CODE LCD_WrC                    \ char --         Write Char
6414     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
6415     JMP LCD_W 
6416 ENDCODE
6417     \
6418
6419 CODE LCD_WrF                    \ func --         Write Fonction
6420     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
6421     JMP LCD_W 
6422 ENDCODE
6423     \
6424
6425 : LCD_Clear 
6426     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
6427 ;
6428     \
6429
6430 : LCD_Home 
6431     $02 LCD_WrF 100 20_us 
6432 ;
6433     \
6434
6435 \ : LCD_Entry_set       $04 OR LCD_WrF ;
6436
6437 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
6438
6439 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
6440
6441 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
6442
6443 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
6444
6445 \ : LCD_Goto            $80 OR LCD_WrF ;
6446
6447 \ CODE LCD_R                      \ -- byte       read byte from LCD
6448 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
6449 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
6450 \ COLON                           \ starts a FORTH word
6451 \     TOP_LCD 2 20_us             \ -- %0000HHHH
6452 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
6453 \ HI2LO                           \ switch from FORTH to assembler
6454 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
6455 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
6456 \     MOV @RSP+,IP                \ restore IP saved by COLON
6457 \     MOV @IP+,PC                 \
6458 \ ENDCODE
6459 \     \
6460
6461 \ CODE LCD_RdS                    \ -- status       Read Status
6462 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
6463 \     JMP LCD_R
6464 \ ENDCODE
6465 \     \
6466
6467 \ CODE LCD_RdC                    \ -- char         Read Char
6468 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
6469 \     JMP LCD_R
6470 \ ENDCODE
6471 \     \
6472
6473 \ -------------+------+------+------+------++---+---+---+---+---------+
6474 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
6475 \ -------------+------+------+------+------++---+---+---+---+---------+
6476 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
6477 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
6478 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
6479 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
6480 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
6481 \ -------------+------+------+------+------++---+---+---+---+---------+
6482
6483
6484 \ ******************************\
6485 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
6486 \ ******************************\
6487 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
6488 \ ------------------------------\
6489 \ define LPM mode for ACCEPT    \
6490 \ ------------------------------\
6491 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
6492 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
6493 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
6494 BIT.B #SW2,&SW2_IN              \ test switch S2
6495 0= IF                           \ case of switch S2 pressed
6496     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
6497     U< IF
6498         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
6499     THEN
6500 ELSE
6501     BIT.B #SW1,&SW1_IN          \ test switch S1 input
6502     0= IF                       \ case of Switch S1 pressed
6503         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
6504         U>= IF                  \
6505             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
6506         THEN                    \
6507     THEN                        \
6508 THEN                            \
6509 RETI                            \ CPU is ON, GIE is OFF
6510 ENDASM                          \
6511     \
6512
6513
6514 \ ------------------------------\
6515 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
6516 \ ******************************\
6517 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
6518 \ ******************************\
6519 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
6520 \                               \       SMclock = 8|16|24 MHz
6521 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
6522 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
6523 \                               \       SR(9)=new Toggle bit memory (ADD on)
6524 \ ------------------------------\
6525 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
6526 \ ------------------------------\
6527 \ define LPM mode for ACCEPT    \
6528 \ ------------------------------\
6529 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
6530 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
6531 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
6532 \ ------------------------------\
6533 \ RC5_FirstStartBitHalfCycle:   \
6534 \ ------------------------------\
6535 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
6536 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
6537 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
6538 MOV     #1778,X                 \ RC5_Period in us
6539 MOV     #14,W                   \ count of loop
6540 BEGIN                           \
6541 \ ------------------------------\
6542 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
6543 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
6544     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
6545 \ RC5_Compute_3/4_Period:       \                   |
6546     RRUM    #1,X                \ X=1/2 cycle       |
6547     MOV     X,Y                 \ Y=1/2             ^
6548     RRUM    #1,Y                \ Y=1/4
6549     ADD     X,Y                 \ Y=3/4
6550 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
6551     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
6552     0= UNTIL                    \
6553 \ ------------------------------\
6554 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
6555 \ ------------------------------\
6556     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
6557     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
6558     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
6559     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
6560     SUB     #1,W                \ decrement count loop
6561 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
6562 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
6563 0<> WHILE                       \ ----> out of loop ----+
6564 \ RC5_compute_7/4_Time_out:     \                       |
6565     ADD     X,Y                 \                       |   out of bound = 7/4 period 
6566 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
6567     BEGIN                       \                       |
6568         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
6569         0>= IF                  \                       |   if cycle time out of bound
6570             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
6571             RETI                \                       |   then quit to do nothing
6572         THEN                    \                       |
6573 \ ------------------------------\                       |
6574         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
6575     0<> UNTIL                   \                   |   |
6576     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
6577 REPEAT                          \ ----> loop back --+   |
6578 \ ------------------------------\                       |
6579 \ RC5_SampleEndOf:              \ <---------------------+
6580 \ ------------------------------\
6581 BIC     #$30,&TA0CTL           \ stop timer_A0
6582 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
6583 \ ******************************\
6584 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
6585 \ ******************************\
6586 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
6587 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
6588 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
6589 BIT     #BIT13,X                \ X(13) = New_RC5_command
6590 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
6591 THEN                            \
6592 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
6593 \ ******************************\
6594 \ RC5_ComputeNewRC5word         \
6595 \ ******************************\
6596 SUB     #4,PSP                  \
6597 MOV     &BASE,2(PSP)            \ save variable BASE before use
6598 MOV     TOS,0(PSP)              \ save TOS before use
6599 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
6600 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
6601 \ ******************************\
6602 \ RC5_ComputeC6bit              \
6603 \ ******************************\
6604 BIT     #$4000,IP              \ test /C6 bit in IP
6605 0= IF   BIS #$40,TOS           \ set C6 bit in S
6606 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
6607 \ ******************************\
6608 \ RC5_CommandByteIsDone         \ RC5_code --
6609 \ ******************************\
6610
6611 \ ------------------------------\
6612 \ Display IR_RC5 code           \
6613 \ ------------------------------\
6614 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
6615 \ ------------------------------\
6616 LO2HI                           \ switch from assembler to FORTH
6617     ['] LCD_CLEAR IS CR         \ redirects CR
6618     ['] LCD_WrC  IS EMIT        \ redirects EMIT
6619     $10 BASE !                 \ change BASE to hexadecimal
6620     CR ." $" 2 U.R             \ print IR_RC5 code
6621     ['] (CR) IS CR              \ restore CR
6622     ['] (EMIT) IS EMIT          \ restore EMIT
6623 HI2LO                           \ switch from FORTH to assembler
6624 \ ------------------------------\
6625 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
6626 \ ------------------------------\
6627 MOV @PSP+,&BASE                 \ restore variable BASE
6628 RETI                            \ CPU is ON, GIE is OFF
6629 ENDASM                          \
6630     \ 
6631
6632 CODE START                      \
6633 \ ------------------------------\
6634 \ TB0CTL = %0000 0010 1001 0100\$3C0
6635 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
6636 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
6637 \                      --       \ID input divider \ 10 = /4
6638 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
6639 \                            -  \TBCLR TimerB Clear
6640 \                             - \TBIE
6641 \                              -\TBIFG
6642 \ --------------------------------\\
6643 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
6644 \              --                 \CM Capture Mode
6645 \                --               \CCIS
6646 \                   -             \SCS
6647 \                    --           \CLLD
6648 \                      -          \CAP
6649 \                        ---      \OUTMOD \ 011 = set/reset
6650 \                           -     \CCIE
6651 \                             -   \CCI
6652 \                              -  \OUT
6653 \                               - \COV
6654 \                                -\CCIFG
6655 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
6656 \ TB0EX0                          \$3E0 
6657 \ ------------------------------\
6658 \ set TimerB to make 50kHz PWM  \
6659 \ ------------------------------\
6660 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
6661 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
6662 \ ------------------------------\
6663 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
6664 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
6665 \ ------------------------------\
6666     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
6667     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
6668 \ ------------------------------\
6669 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
6670 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
6671 \ ------------------------------\
6672 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
6673 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
6674 \ ------------------------------\
6675     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
6676 \ ------------------------------\
6677 \ set TimerB to generate PWM for LCD_Vo
6678 \ ------------------------------\
6679     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
6680 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
6681     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
6682 \ ------------------------------\
6683     BIS.B #LCDVo,&LCDVo_DIR     \
6684     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
6685 \ ------------------------------\
6686     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
6687     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
6688 \ ------------------------------\
6689     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
6690     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
6691 \ ------------------------------\
6692 \ WDT interval init part        \
6693 \ ------------------------------\
6694     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
6695 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
6696 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
6697     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
6698 \ ------------------------------\
6699 \ init RC5_Int                  \
6700 \ ------------------------------\
6701     BIS.B #RC5,&IR_IE           \ enable RC5_Int
6702     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
6703 \ ------------------------------\
6704 \ init interrupt vectors
6705 \ ------------------------------\
6706     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
6707     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
6708 \ ------------------------------\
6709 \ define LPM mode for ACCEPT    \
6710 \ ------------------------------\
6711 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
6712 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
6713 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
6714
6715 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
6716
6717 \ ------------------------------\
6718 \ Init LCD 2x20                 \
6719 \ ------------------------------\
6720     $03E8 20_US                \ 1-  wait 20 ms
6721     $03 TOP_LCD                \ 2- send DB5=DB4=1
6722     $CD 20_US                  \ 3- wait 4,1 ms
6723     $03 TOP_LCD                \ 4- send again DB5=DB4=1
6724     $5 20_US                   \ 5- wait 0,1 ms
6725     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
6726     $2 20_US                   \    wait 40 us = LCD cycle
6727     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
6728     $2 20_US                   \    wait 40 us = LCD cycle
6729     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
6730     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
6731     LCD_Clear                   \ 10- "LCD_Clear"
6732     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
6733     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
6734     LCD_Clear                   \ 10- "LCD_Clear"
6735     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
6736     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
6737     CR ." I love you"   
6738     ['] (CR) IS CR              \ ' (CR) is CR
6739     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
6740     CR
6741     ."    RC5toLCD is running. Type STOP to quit"
6742 \    NOECHO                      \ uncomment to run this app without terminal connexion
6743     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
6744     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
6745 ;
6746     \
6747
6748 : STOP                  \ stops multitasking, must to be used before downloading app
6749     ['] (WARM) IS WARM  \ remove START app from FORTH init process
6750     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
6751 ;
6752     \
6753
6754
6755 RST_STATE   ;
6756
6757
6758 CODE MAX    \    n1 n2 -- n3       signed maximum
6759             CMP     @PSP,TOS    \ n2-n1
6760             S<      ?GOTO FW1   \ n2<n1
6761 BW1         ADD     #2,PSP
6762             MOV     @IP+,PC
6763 ENDCODE
6764     \
6765
6766 CODE MIN    \    n1 n2 -- n3       signed minimum
6767             CMP     @PSP,TOS     \ n2-n1
6768             S<      ?GOTO BW1    \ n2<n1
6769 FW1         MOV     @PSP+,TOS
6770             MOV     @IP+,PC
6771 ENDCODE
6772     \
6773
6774 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
6775   >R  <# 0 # #S #>  
6776   R> OVER - 0 MAX SPACES TYPE
6777 ;
6778     \
6779
6780 CODE 20_US                      \ n --      n * 20 us
6781 BEGIN                           \ 3 cycles loop + 6~  
6782 \    MOV     #5,W                \ 3 MCLK = 1 MHz
6783 \    MOV     #23,W               \ 3 MCLK = 4 MHz
6784     MOV     #51,W               \ 3 MCLK = 8 MHz
6785 \    MOV     #104,W              \ 3 MCLK = 16 MHz
6786 \    MOV     #158,W              \ 3 MCLK = 24 MHz
6787     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
6788         SUB #1,W                \ 1
6789     0= UNTIL                    \ 2
6790     SUB     #1,TOS              \ 1
6791 0= UNTIL                        \ 2
6792     MOV     @PSP+,TOS           \ 2
6793     MOV     @IP+,PC             \ 4
6794 ENDCODE
6795     \
6796
6797 CODE TOP_LCD                    \ LCD Sample
6798 \                               \ if write : %xxxxWWWW --
6799 \                               \ if read  : -- %0000RRRR
6800     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
6801     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
6802 0= IF                           \ write LCD bits pattern
6803     AND.B #LCD_DB,TOS           \ 
6804     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
6805     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
6806     MOV @PSP+,TOS               \
6807     MOV @IP+,PC
6808 THEN                            \ read LCD bits pattern
6809     SUB #2,PSP
6810     MOV TOS,0(PSP)
6811     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
6812     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
6813     AND.B #LCD_DB,TOS           \
6814     MOV @IP+,PC
6815 ENDCODE
6816     \
6817
6818 CODE LCD_W                      \ byte --       write byte to LCD 
6819     SUB #2,PSP                  \
6820     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
6821     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
6822     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
6823     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
6824 COLON                           \ high level word starts here 
6825     TOP_LCD 2 20_US             \ write high nibble first
6826     TOP_LCD 2 20_US 
6827 ;
6828     \
6829
6830 CODE LCD_WrC                    \ char --         Write Char
6831     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
6832     JMP LCD_W 
6833 ENDCODE
6834     \
6835
6836 CODE LCD_WrF                    \ func --         Write Fonction
6837     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
6838     JMP LCD_W 
6839 ENDCODE
6840     \
6841
6842 : LCD_Clear 
6843     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
6844 ;
6845     \
6846
6847 : LCD_Home 
6848     $02 LCD_WrF 100 20_us 
6849 ;
6850     \
6851
6852 \ : LCD_Entry_set       $04 OR LCD_WrF ;
6853
6854 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
6855
6856 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
6857
6858 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
6859
6860 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
6861
6862 \ : LCD_Goto            $80 OR LCD_WrF ;
6863
6864 \ CODE LCD_R                      \ -- byte       read byte from LCD
6865 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
6866 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
6867 \ COLON                           \ starts a FORTH word
6868 \     TOP_LCD 2 20_us             \ -- %0000HHHH
6869 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
6870 \ HI2LO                           \ switch from FORTH to assembler
6871 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
6872 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
6873 \     MOV @RSP+,IP                \ restore IP saved by COLON
6874 \     MOV @IP+,PC                 \
6875 \ ENDCODE
6876 \     \
6877
6878 \ CODE LCD_RdS                    \ -- status       Read Status
6879 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
6880 \     JMP LCD_R
6881 \ ENDCODE
6882 \     \
6883
6884 \ CODE LCD_RdC                    \ -- char         Read Char
6885 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
6886 \     JMP LCD_R
6887 \ ENDCODE
6888 \     \
6889
6890 \ -------------+------+------+------+------++---+---+---+---+---------+
6891 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
6892 \ -------------+------+------+------+------++---+---+---+---+---------+
6893 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
6894 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
6895 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
6896 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
6897 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
6898 \ -------------+------+------+------+------++---+---+---+---+---------+
6899
6900
6901 \ ******************************\
6902 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
6903 \ ******************************\
6904 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
6905 \ ------------------------------\
6906 \ define LPM mode for ACCEPT    \
6907 \ ------------------------------\
6908 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
6909 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
6910 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
6911 BIT.B #SW2,&SW2_IN              \ test switch S2
6912 0= IF                           \ case of switch S2 pressed
6913     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
6914     U< IF
6915         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
6916     THEN
6917 ELSE
6918     BIT.B #SW1,&SW1_IN          \ test switch S1 input
6919     0= IF                       \ case of Switch S1 pressed
6920         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
6921         U>= IF                  \
6922             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
6923         THEN                    \
6924     THEN                        \
6925 THEN                            \
6926 RETI                            \ CPU is ON, GIE is OFF
6927 ENDASM                          \
6928     \
6929
6930
6931 \ ------------------------------\
6932 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
6933 \ ******************************\
6934 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
6935 \ ******************************\
6936 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
6937 \                               \       SMclock = 8|16|24 MHz
6938 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
6939 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
6940 \                               \       SR(9)=new Toggle bit memory (ADD on)
6941 \ ------------------------------\
6942 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
6943 \ ------------------------------\
6944 \ define LPM mode for ACCEPT    \
6945 \ ------------------------------\
6946 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
6947 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
6948 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
6949 \ ------------------------------\
6950 \ RC5_FirstStartBitHalfCycle:   \
6951 \ ------------------------------\
6952 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
6953 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
6954 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
6955 MOV     #1778,X                 \ RC5_Period in us
6956 MOV     #14,W                   \ count of loop
6957 BEGIN                           \
6958 \ ------------------------------\
6959 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
6960 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
6961     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
6962 \ RC5_Compute_3/4_Period:       \                   |
6963     RRUM    #1,X                \ X=1/2 cycle       |
6964     MOV     X,Y                 \ Y=1/2             ^
6965     RRUM    #1,Y                \ Y=1/4
6966     ADD     X,Y                 \ Y=3/4
6967 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
6968     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
6969     0= UNTIL                    \
6970 \ ------------------------------\
6971 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
6972 \ ------------------------------\
6973     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
6974     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
6975     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
6976     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
6977     SUB     #1,W                \ decrement count loop
6978 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
6979 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
6980 0<> WHILE                       \ ----> out of loop ----+
6981 \ RC5_compute_7/4_Time_out:     \                       |
6982     ADD     X,Y                 \                       |   out of bound = 7/4 period 
6983 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
6984     BEGIN                       \                       |
6985         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
6986         0>= IF                  \                       |   if cycle time out of bound
6987             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
6988             RETI                \                       |   then quit to do nothing
6989         THEN                    \                       |
6990 \ ------------------------------\                       |
6991         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
6992     0<> UNTIL                   \                   |   |
6993     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
6994 REPEAT                          \ ----> loop back --+   |
6995 \ ------------------------------\                       |
6996 \ RC5_SampleEndOf:              \ <---------------------+
6997 \ ------------------------------\
6998 BIC     #$30,&TA0CTL           \ stop timer_A0
6999 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
7000 \ ******************************\
7001 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
7002 \ ******************************\
7003 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
7004 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
7005 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
7006 BIT     #BIT13,X                \ X(13) = New_RC5_command
7007 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
7008 THEN                            \
7009 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
7010 \ ******************************\
7011 \ RC5_ComputeNewRC5word         \
7012 \ ******************************\
7013 SUB     #4,PSP                  \
7014 MOV     &BASE,2(PSP)            \ save variable BASE before use
7015 MOV     TOS,0(PSP)              \ save TOS before use
7016 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
7017 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
7018 \ ******************************\
7019 \ RC5_ComputeC6bit              \
7020 \ ******************************\
7021 BIT     #$4000,IP              \ test /C6 bit in IP
7022 0= IF   BIS #$40,TOS           \ set C6 bit in S
7023 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
7024 \ ******************************\
7025 \ RC5_CommandByteIsDone         \ RC5_code --
7026 \ ******************************\
7027
7028 \ ------------------------------\
7029 \ Display IR_RC5 code           \
7030 \ ------------------------------\
7031 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
7032 \ ------------------------------\
7033 LO2HI                           \ switch from assembler to FORTH
7034     ['] LCD_CLEAR IS CR         \ redirects CR
7035     ['] LCD_WrC  IS EMIT        \ redirects EMIT
7036     $10 BASE !                 \ change BASE to hexadecimal
7037     CR ." $" 2 U.R             \ print IR_RC5 code
7038     ['] (CR) IS CR              \ restore CR
7039     ['] (EMIT) IS EMIT          \ restore EMIT
7040 HI2LO                           \ switch from FORTH to assembler
7041 \ ------------------------------\
7042 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
7043 \ ------------------------------\
7044 MOV @PSP+,&BASE                 \ restore variable BASE
7045 RETI                            \ CPU is ON, GIE is OFF
7046 ENDASM                          \
7047     \ 
7048
7049 CODE START                      \
7050 \ ------------------------------\
7051 \ TB0CTL = %0000 0010 1001 0100\$3C0
7052 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
7053 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
7054 \                      --       \ID input divider \ 10 = /4
7055 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
7056 \                            -  \TBCLR TimerB Clear
7057 \                             - \TBIE
7058 \                              -\TBIFG
7059 \ --------------------------------\\
7060 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
7061 \              --                 \CM Capture Mode
7062 \                --               \CCIS
7063 \                   -             \SCS
7064 \                    --           \CLLD
7065 \                      -          \CAP
7066 \                        ---      \OUTMOD \ 011 = set/reset
7067 \                           -     \CCIE
7068 \                             -   \CCI
7069 \                              -  \OUT
7070 \                               - \COV
7071 \                                -\CCIFG
7072 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
7073 \ TB0EX0                          \$3E0 
7074 \ ------------------------------\
7075 \ set TimerB to make 50kHz PWM  \
7076 \ ------------------------------\
7077 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
7078 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
7079 \ ------------------------------\
7080 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
7081 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
7082 \ ------------------------------\
7083     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
7084     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
7085 \ ------------------------------\
7086 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
7087 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
7088 \ ------------------------------\
7089 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
7090 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
7091 \ ------------------------------\
7092     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
7093 \ ------------------------------\
7094 \ set TimerB to generate PWM for LCD_Vo
7095 \ ------------------------------\
7096     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
7097 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
7098     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
7099 \ ------------------------------\
7100     BIS.B #LCDVo,&LCDVo_DIR     \
7101     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
7102 \ ------------------------------\
7103     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
7104     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
7105 \ ------------------------------\
7106     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
7107     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
7108 \ ------------------------------\
7109 \ WDT interval init part        \
7110 \ ------------------------------\
7111     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
7112 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
7113 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
7114     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
7115 \ ------------------------------\
7116 \ init RC5_Int                  \
7117 \ ------------------------------\
7118     BIS.B #RC5,&IR_IE           \ enable RC5_Int
7119     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
7120 \ ------------------------------\
7121 \ init interrupt vectors
7122 \ ------------------------------\
7123     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
7124     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
7125 \ ------------------------------\
7126 \ define LPM mode for ACCEPT    \
7127 \ ------------------------------\
7128 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
7129 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
7130 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
7131
7132 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
7133
7134 \ ------------------------------\
7135 \ Init LCD 2x20                 \
7136 \ ------------------------------\
7137     $03E8 20_US                \ 1-  wait 20 ms
7138     $03 TOP_LCD                \ 2- send DB5=DB4=1
7139     $CD 20_US                  \ 3- wait 4,1 ms
7140     $03 TOP_LCD                \ 4- send again DB5=DB4=1
7141     $5 20_US                   \ 5- wait 0,1 ms
7142     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
7143     $2 20_US                   \    wait 40 us = LCD cycle
7144     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
7145     $2 20_US                   \    wait 40 us = LCD cycle
7146     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
7147     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
7148     LCD_Clear                   \ 10- "LCD_Clear"
7149     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
7150     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
7151     LCD_Clear                   \ 10- "LCD_Clear"
7152     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
7153     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
7154     CR ." I love you"   
7155     ['] (CR) IS CR              \ ' (CR) is CR
7156     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
7157     CR
7158     ."    RC5toLCD is running. Type STOP to quit"
7159 \    NOECHO                      \ uncomment to run this app without terminal connexion
7160     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
7161     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
7162 ;
7163     \
7164
7165 : STOP                  \ stops multitasking, must to be used before downloading app
7166     ['] (WARM) IS WARM  \ remove START app from FORTH init process
7167     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
7168 ;
7169     \
7170
7171
7172 RST_STATE   ;
7173
7174
7175 CODE MAX    \    n1 n2 -- n3       signed maximum
7176             CMP     @PSP,TOS    \ n2-n1
7177             S<      ?GOTO FW1   \ n2<n1
7178 BW1         ADD     #2,PSP
7179             MOV     @IP+,PC
7180 ENDCODE
7181     \
7182
7183 CODE MIN    \    n1 n2 -- n3       signed minimum
7184             CMP     @PSP,TOS     \ n2-n1
7185             S<      ?GOTO BW1    \ n2<n1
7186 FW1         MOV     @PSP+,TOS
7187             MOV     @IP+,PC
7188 ENDCODE
7189     \
7190
7191 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
7192   >R  <# 0 # #S #>  
7193   R> OVER - 0 MAX SPACES TYPE
7194 ;
7195     \
7196
7197 CODE 20_US                      \ n --      n * 20 us
7198 BEGIN                           \ 3 cycles loop + 6~  
7199 \    MOV     #5,W                \ 3 MCLK = 1 MHz
7200 \    MOV     #23,W               \ 3 MCLK = 4 MHz
7201     MOV     #51,W               \ 3 MCLK = 8 MHz
7202 \    MOV     #104,W              \ 3 MCLK = 16 MHz
7203 \    MOV     #158,W              \ 3 MCLK = 24 MHz
7204     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
7205         SUB #1,W                \ 1
7206     0= UNTIL                    \ 2
7207     SUB     #1,TOS              \ 1
7208 0= UNTIL                        \ 2
7209     MOV     @PSP+,TOS           \ 2
7210     MOV     @IP+,PC             \ 4
7211 ENDCODE
7212     \
7213
7214 CODE TOP_LCD                    \ LCD Sample
7215 \                               \ if write : %xxxxWWWW --
7216 \                               \ if read  : -- %0000RRRR
7217     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
7218     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
7219 0= IF                           \ write LCD bits pattern
7220     AND.B #LCD_DB,TOS           \ 
7221     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
7222     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
7223     MOV @PSP+,TOS               \
7224     MOV @IP+,PC
7225 THEN                            \ read LCD bits pattern
7226     SUB #2,PSP
7227     MOV TOS,0(PSP)
7228     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
7229     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
7230     AND.B #LCD_DB,TOS           \
7231     MOV @IP+,PC
7232 ENDCODE
7233     \
7234
7235 CODE LCD_W                      \ byte --       write byte to LCD 
7236     SUB #2,PSP                  \
7237     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
7238     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
7239     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
7240     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
7241 COLON                           \ high level word starts here 
7242     TOP_LCD 2 20_US             \ write high nibble first
7243     TOP_LCD 2 20_US 
7244 ;
7245     \
7246
7247 CODE LCD_WrC                    \ char --         Write Char
7248     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
7249     JMP LCD_W 
7250 ENDCODE
7251     \
7252
7253 CODE LCD_WrF                    \ func --         Write Fonction
7254     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
7255     JMP LCD_W 
7256 ENDCODE
7257     \
7258
7259 : LCD_Clear 
7260     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
7261 ;
7262     \
7263
7264 : LCD_Home 
7265     $02 LCD_WrF 100 20_us 
7266 ;
7267     \
7268
7269 \ : LCD_Entry_set       $04 OR LCD_WrF ;
7270
7271 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
7272
7273 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
7274
7275 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
7276
7277 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
7278
7279 \ : LCD_Goto            $80 OR LCD_WrF ;
7280
7281 \ CODE LCD_R                      \ -- byte       read byte from LCD
7282 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
7283 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
7284 \ COLON                           \ starts a FORTH word
7285 \     TOP_LCD 2 20_us             \ -- %0000HHHH
7286 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
7287 \ HI2LO                           \ switch from FORTH to assembler
7288 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
7289 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
7290 \     MOV @RSP+,IP                \ restore IP saved by COLON
7291 \     MOV @IP+,PC                 \
7292 \ ENDCODE
7293 \     \
7294
7295 \ CODE LCD_RdS                    \ -- status       Read Status
7296 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
7297 \     JMP LCD_R
7298 \ ENDCODE
7299 \     \
7300
7301 \ CODE LCD_RdC                    \ -- char         Read Char
7302 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
7303 \     JMP LCD_R
7304 \ ENDCODE
7305 \     \
7306
7307 \ -------------+------+------+------+------++---+---+---+---+---------+
7308 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
7309 \ -------------+------+------+------+------++---+---+---+---+---------+
7310 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
7311 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
7312 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
7313 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
7314 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
7315 \ -------------+------+------+------+------++---+---+---+---+---------+
7316
7317
7318 \ ******************************\
7319 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
7320 \ ******************************\
7321 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
7322 \ ------------------------------\
7323 \ define LPM mode for ACCEPT    \
7324 \ ------------------------------\
7325 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
7326 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
7327 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
7328 BIT.B #SW2,&SW2_IN              \ test switch S2
7329 0= IF                           \ case of switch S2 pressed
7330     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
7331     U< IF
7332         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
7333     THEN
7334 ELSE
7335     BIT.B #SW1,&SW1_IN          \ test switch S1 input
7336     0= IF                       \ case of Switch S1 pressed
7337         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
7338         U>= IF                  \
7339             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
7340         THEN                    \
7341     THEN                        \
7342 THEN                            \
7343 RETI                            \ CPU is ON, GIE is OFF
7344 ENDASM                          \
7345     \
7346
7347
7348 \ ------------------------------\
7349 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
7350 \ ******************************\
7351 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
7352 \ ******************************\
7353 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
7354 \                               \       SMclock = 8|16|24 MHz
7355 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
7356 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
7357 \                               \       SR(9)=new Toggle bit memory (ADD on)
7358 \ ------------------------------\
7359 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
7360 \ ------------------------------\
7361 \ define LPM mode for ACCEPT    \
7362 \ ------------------------------\
7363 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
7364 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
7365 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
7366 \ ------------------------------\
7367 \ RC5_FirstStartBitHalfCycle:   \
7368 \ ------------------------------\
7369 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
7370 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
7371 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
7372 MOV     #1778,X                 \ RC5_Period in us
7373 MOV     #14,W                   \ count of loop
7374 BEGIN                           \
7375 \ ------------------------------\
7376 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
7377 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
7378     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
7379 \ RC5_Compute_3/4_Period:       \                   |
7380     RRUM    #1,X                \ X=1/2 cycle       |
7381     MOV     X,Y                 \ Y=1/2             ^
7382     RRUM    #1,Y                \ Y=1/4
7383     ADD     X,Y                 \ Y=3/4
7384 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
7385     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
7386     0= UNTIL                    \
7387 \ ------------------------------\
7388 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
7389 \ ------------------------------\
7390     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
7391     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
7392     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
7393     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
7394     SUB     #1,W                \ decrement count loop
7395 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
7396 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
7397 0<> WHILE                       \ ----> out of loop ----+
7398 \ RC5_compute_7/4_Time_out:     \                       |
7399     ADD     X,Y                 \                       |   out of bound = 7/4 period 
7400 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
7401     BEGIN                       \                       |
7402         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
7403         0>= IF                  \                       |   if cycle time out of bound
7404             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
7405             RETI                \                       |   then quit to do nothing
7406         THEN                    \                       |
7407 \ ------------------------------\                       |
7408         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
7409     0<> UNTIL                   \                   |   |
7410     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
7411 REPEAT                          \ ----> loop back --+   |
7412 \ ------------------------------\                       |
7413 \ RC5_SampleEndOf:              \ <---------------------+
7414 \ ------------------------------\
7415 BIC     #$30,&TA0CTL           \ stop timer_A0
7416 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
7417 \ ******************************\
7418 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
7419 \ ******************************\
7420 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
7421 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
7422 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
7423 BIT     #BIT13,X                \ X(13) = New_RC5_command
7424 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
7425 THEN                            \
7426 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
7427 \ ******************************\
7428 \ RC5_ComputeNewRC5word         \
7429 \ ******************************\
7430 SUB     #4,PSP                  \
7431 MOV     &BASE,2(PSP)            \ save variable BASE before use
7432 MOV     TOS,0(PSP)              \ save TOS before use
7433 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
7434 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
7435 \ ******************************\
7436 \ RC5_ComputeC6bit              \
7437 \ ******************************\
7438 BIT     #$4000,IP              \ test /C6 bit in IP
7439 0= IF   BIS #$40,TOS           \ set C6 bit in S
7440 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
7441 \ ******************************\
7442 \ RC5_CommandByteIsDone         \ RC5_code --
7443 \ ******************************\
7444
7445 \ ------------------------------\
7446 \ Display IR_RC5 code           \
7447 \ ------------------------------\
7448 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
7449 \ ------------------------------\
7450 LO2HI                           \ switch from assembler to FORTH
7451     ['] LCD_CLEAR IS CR         \ redirects CR
7452     ['] LCD_WrC  IS EMIT        \ redirects EMIT
7453     $10 BASE !                 \ change BASE to hexadecimal
7454     CR ." $" 2 U.R             \ print IR_RC5 code
7455     ['] (CR) IS CR              \ restore CR
7456     ['] (EMIT) IS EMIT          \ restore EMIT
7457 HI2LO                           \ switch from FORTH to assembler
7458 \ ------------------------------\
7459 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
7460 \ ------------------------------\
7461 MOV @PSP+,&BASE                 \ restore variable BASE
7462 RETI                            \ CPU is ON, GIE is OFF
7463 ENDASM                          \
7464     \ 
7465
7466 CODE START                      \
7467 \ ------------------------------\
7468 \ TB0CTL = %0000 0010 1001 0100\$3C0
7469 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
7470 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
7471 \                      --       \ID input divider \ 10 = /4
7472 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
7473 \                            -  \TBCLR TimerB Clear
7474 \                             - \TBIE
7475 \                              -\TBIFG
7476 \ --------------------------------\\
7477 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
7478 \              --                 \CM Capture Mode
7479 \                --               \CCIS
7480 \                   -             \SCS
7481 \                    --           \CLLD
7482 \                      -          \CAP
7483 \                        ---      \OUTMOD \ 011 = set/reset
7484 \                           -     \CCIE
7485 \                             -   \CCI
7486 \                              -  \OUT
7487 \                               - \COV
7488 \                                -\CCIFG
7489 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
7490 \ TB0EX0                          \$3E0 
7491 \ ------------------------------\
7492 \ set TimerB to make 50kHz PWM  \
7493 \ ------------------------------\
7494 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
7495 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
7496 \ ------------------------------\
7497 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
7498 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
7499 \ ------------------------------\
7500     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
7501     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
7502 \ ------------------------------\
7503 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
7504 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
7505 \ ------------------------------\
7506 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
7507 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
7508 \ ------------------------------\
7509     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
7510 \ ------------------------------\
7511 \ set TimerB to generate PWM for LCD_Vo
7512 \ ------------------------------\
7513     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
7514 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
7515     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
7516 \ ------------------------------\
7517     BIS.B #LCDVo,&LCDVo_DIR     \
7518     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
7519 \ ------------------------------\
7520     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
7521     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
7522 \ ------------------------------\
7523     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
7524     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
7525 \ ------------------------------\
7526 \ WDT interval init part        \
7527 \ ------------------------------\
7528     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
7529 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
7530 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
7531     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
7532 \ ------------------------------\
7533 \ init RC5_Int                  \
7534 \ ------------------------------\
7535     BIS.B #RC5,&IR_IE           \ enable RC5_Int
7536     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
7537 \ ------------------------------\
7538 \ init interrupt vectors
7539 \ ------------------------------\
7540     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
7541     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
7542 \ ------------------------------\
7543 \ define LPM mode for ACCEPT    \
7544 \ ------------------------------\
7545 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
7546 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
7547 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
7548
7549 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
7550
7551 \ ------------------------------\
7552 \ Init LCD 2x20                 \
7553 \ ------------------------------\
7554     $03E8 20_US                \ 1-  wait 20 ms
7555     $03 TOP_LCD                \ 2- send DB5=DB4=1
7556     $CD 20_US                  \ 3- wait 4,1 ms
7557     $03 TOP_LCD                \ 4- send again DB5=DB4=1
7558     $5 20_US                   \ 5- wait 0,1 ms
7559     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
7560     $2 20_US                   \    wait 40 us = LCD cycle
7561     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
7562     $2 20_US                   \    wait 40 us = LCD cycle
7563     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
7564     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
7565     LCD_Clear                   \ 10- "LCD_Clear"
7566     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
7567     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
7568     LCD_Clear                   \ 10- "LCD_Clear"
7569     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
7570     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
7571     CR ." I love you"   
7572     ['] (CR) IS CR              \ ' (CR) is CR
7573     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
7574     CR
7575     ."    RC5toLCD is running. Type STOP to quit"
7576 \    NOECHO                      \ uncomment to run this app without terminal connexion
7577     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
7578     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
7579 ;
7580     \
7581
7582 : STOP                  \ stops multitasking, must to be used before downloading app
7583     ['] (WARM) IS WARM  \ remove START app from FORTH init process
7584     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
7585 ;
7586     \
7587
7588
7589 RST_STATE   ;
7590
7591
7592 CODE MAX    \    n1 n2 -- n3       signed maximum
7593             CMP     @PSP,TOS    \ n2-n1
7594             S<      ?GOTO FW1   \ n2<n1
7595 BW1         ADD     #2,PSP
7596             MOV     @IP+,PC
7597 ENDCODE
7598     \
7599
7600 CODE MIN    \    n1 n2 -- n3       signed minimum
7601             CMP     @PSP,TOS     \ n2-n1
7602             S<      ?GOTO BW1    \ n2<n1
7603 FW1         MOV     @PSP+,TOS
7604             MOV     @IP+,PC
7605 ENDCODE
7606     \
7607
7608 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
7609   >R  <# 0 # #S #>  
7610   R> OVER - 0 MAX SPACES TYPE
7611 ;
7612     \
7613
7614 CODE 20_US                      \ n --      n * 20 us
7615 BEGIN                           \ 3 cycles loop + 6~  
7616 \    MOV     #5,W                \ 3 MCLK = 1 MHz
7617 \    MOV     #23,W               \ 3 MCLK = 4 MHz
7618     MOV     #51,W               \ 3 MCLK = 8 MHz
7619 \    MOV     #104,W              \ 3 MCLK = 16 MHz
7620 \    MOV     #158,W              \ 3 MCLK = 24 MHz
7621     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
7622         SUB #1,W                \ 1
7623     0= UNTIL                    \ 2
7624     SUB     #1,TOS              \ 1
7625 0= UNTIL                        \ 2
7626     MOV     @PSP+,TOS           \ 2
7627     MOV     @IP+,PC             \ 4
7628 ENDCODE
7629     \
7630
7631 CODE TOP_LCD                    \ LCD Sample
7632 \                               \ if write : %xxxxWWWW --
7633 \                               \ if read  : -- %0000RRRR
7634     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
7635     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
7636 0= IF                           \ write LCD bits pattern
7637     AND.B #LCD_DB,TOS           \ 
7638     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
7639     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
7640     MOV @PSP+,TOS               \
7641     MOV @IP+,PC
7642 THEN                            \ read LCD bits pattern
7643     SUB #2,PSP
7644     MOV TOS,0(PSP)
7645     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
7646     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
7647     AND.B #LCD_DB,TOS           \
7648     MOV @IP+,PC
7649 ENDCODE
7650     \
7651
7652 CODE LCD_W                      \ byte --       write byte to LCD 
7653     SUB #2,PSP                  \
7654     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
7655     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
7656     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
7657     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
7658 COLON                           \ high level word starts here 
7659     TOP_LCD 2 20_US             \ write high nibble first
7660     TOP_LCD 2 20_US 
7661 ;
7662     \
7663
7664 CODE LCD_WrC                    \ char --         Write Char
7665     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
7666     JMP LCD_W 
7667 ENDCODE
7668     \
7669
7670 CODE LCD_WrF                    \ func --         Write Fonction
7671     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
7672     JMP LCD_W 
7673 ENDCODE
7674     \
7675
7676 : LCD_Clear 
7677     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
7678 ;
7679     \
7680
7681 : LCD_Home 
7682     $02 LCD_WrF 100 20_us 
7683 ;
7684     \
7685
7686 \ : LCD_Entry_set       $04 OR LCD_WrF ;
7687
7688 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
7689
7690 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
7691
7692 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
7693
7694 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
7695
7696 \ : LCD_Goto            $80 OR LCD_WrF ;
7697
7698 \ CODE LCD_R                      \ -- byte       read byte from LCD
7699 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
7700 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
7701 \ COLON                           \ starts a FORTH word
7702 \     TOP_LCD 2 20_us             \ -- %0000HHHH
7703 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
7704 \ HI2LO                           \ switch from FORTH to assembler
7705 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
7706 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
7707 \     MOV @RSP+,IP                \ restore IP saved by COLON
7708 \     MOV @IP+,PC                 \
7709 \ ENDCODE
7710 \     \
7711
7712 \ CODE LCD_RdS                    \ -- status       Read Status
7713 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
7714 \     JMP LCD_R
7715 \ ENDCODE
7716 \     \
7717
7718 \ CODE LCD_RdC                    \ -- char         Read Char
7719 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
7720 \     JMP LCD_R
7721 \ ENDCODE
7722 \     \
7723
7724 \ -------------+------+------+------+------++---+---+---+---+---------+
7725 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
7726 \ -------------+------+------+------+------++---+---+---+---+---------+
7727 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
7728 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
7729 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
7730 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
7731 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
7732 \ -------------+------+------+------+------++---+---+---+---+---------+
7733
7734
7735 \ ******************************\
7736 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
7737 \ ******************************\
7738 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
7739 \ ------------------------------\
7740 \ define LPM mode for ACCEPT    \
7741 \ ------------------------------\
7742 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
7743 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
7744 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
7745 BIT.B #SW2,&SW2_IN              \ test switch S2
7746 0= IF                           \ case of switch S2 pressed
7747     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
7748     U< IF
7749         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
7750     THEN
7751 ELSE
7752     BIT.B #SW1,&SW1_IN          \ test switch S1 input
7753     0= IF                       \ case of Switch S1 pressed
7754         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
7755         U>= IF                  \
7756             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
7757         THEN                    \
7758     THEN                        \
7759 THEN                            \
7760 RETI                            \ CPU is ON, GIE is OFF
7761 ENDASM                          \
7762     \
7763
7764
7765 \ ------------------------------\
7766 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
7767 \ ******************************\
7768 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
7769 \ ******************************\
7770 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
7771 \                               \       SMclock = 8|16|24 MHz
7772 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
7773 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
7774 \                               \       SR(9)=new Toggle bit memory (ADD on)
7775 \ ------------------------------\
7776 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
7777 \ ------------------------------\
7778 \ define LPM mode for ACCEPT    \
7779 \ ------------------------------\
7780 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
7781 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
7782 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
7783 \ ------------------------------\
7784 \ RC5_FirstStartBitHalfCycle:   \
7785 \ ------------------------------\
7786 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
7787 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
7788 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
7789 MOV     #1778,X                 \ RC5_Period in us
7790 MOV     #14,W                   \ count of loop
7791 BEGIN                           \
7792 \ ------------------------------\
7793 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
7794 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
7795     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
7796 \ RC5_Compute_3/4_Period:       \                   |
7797     RRUM    #1,X                \ X=1/2 cycle       |
7798     MOV     X,Y                 \ Y=1/2             ^
7799     RRUM    #1,Y                \ Y=1/4
7800     ADD     X,Y                 \ Y=3/4
7801 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
7802     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
7803     0= UNTIL                    \
7804 \ ------------------------------\
7805 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
7806 \ ------------------------------\
7807     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
7808     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
7809     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
7810     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
7811     SUB     #1,W                \ decrement count loop
7812 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
7813 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
7814 0<> WHILE                       \ ----> out of loop ----+
7815 \ RC5_compute_7/4_Time_out:     \                       |
7816     ADD     X,Y                 \                       |   out of bound = 7/4 period 
7817 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
7818     BEGIN                       \                       |
7819         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
7820         0>= IF                  \                       |   if cycle time out of bound
7821             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
7822             RETI                \                       |   then quit to do nothing
7823         THEN                    \                       |
7824 \ ------------------------------\                       |
7825         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
7826     0<> UNTIL                   \                   |   |
7827     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
7828 REPEAT                          \ ----> loop back --+   |
7829 \ ------------------------------\                       |
7830 \ RC5_SampleEndOf:              \ <---------------------+
7831 \ ------------------------------\
7832 BIC     #$30,&TA0CTL           \ stop timer_A0
7833 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
7834 \ ******************************\
7835 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
7836 \ ******************************\
7837 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
7838 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
7839 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
7840 BIT     #BIT13,X                \ X(13) = New_RC5_command
7841 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
7842 THEN                            \
7843 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
7844 \ ******************************\
7845 \ RC5_ComputeNewRC5word         \
7846 \ ******************************\
7847 SUB     #4,PSP                  \
7848 MOV     &BASE,2(PSP)            \ save variable BASE before use
7849 MOV     TOS,0(PSP)              \ save TOS before use
7850 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
7851 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
7852 \ ******************************\
7853 \ RC5_ComputeC6bit              \
7854 \ ******************************\
7855 BIT     #$4000,IP              \ test /C6 bit in IP
7856 0= IF   BIS #$40,TOS           \ set C6 bit in S
7857 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
7858 \ ******************************\
7859 \ RC5_CommandByteIsDone         \ RC5_code --
7860 \ ******************************\
7861
7862 \ ------------------------------\
7863 \ Display IR_RC5 code           \
7864 \ ------------------------------\
7865 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
7866 \ ------------------------------\
7867 LO2HI                           \ switch from assembler to FORTH
7868     ['] LCD_CLEAR IS CR         \ redirects CR
7869     ['] LCD_WrC  IS EMIT        \ redirects EMIT
7870     $10 BASE !                 \ change BASE to hexadecimal
7871     CR ." $" 2 U.R             \ print IR_RC5 code
7872     ['] (CR) IS CR              \ restore CR
7873     ['] (EMIT) IS EMIT          \ restore EMIT
7874 HI2LO                           \ switch from FORTH to assembler
7875 \ ------------------------------\
7876 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
7877 \ ------------------------------\
7878 MOV @PSP+,&BASE                 \ restore variable BASE
7879 RETI                            \ CPU is ON, GIE is OFF
7880 ENDASM                          \
7881     \ 
7882
7883 CODE START                      \
7884 \ ------------------------------\
7885 \ TB0CTL = %0000 0010 1001 0100\$3C0
7886 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
7887 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
7888 \                      --       \ID input divider \ 10 = /4
7889 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
7890 \                            -  \TBCLR TimerB Clear
7891 \                             - \TBIE
7892 \                              -\TBIFG
7893 \ --------------------------------\\
7894 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
7895 \              --                 \CM Capture Mode
7896 \                --               \CCIS
7897 \                   -             \SCS
7898 \                    --           \CLLD
7899 \                      -          \CAP
7900 \                        ---      \OUTMOD \ 011 = set/reset
7901 \                           -     \CCIE
7902 \                             -   \CCI
7903 \                              -  \OUT
7904 \                               - \COV
7905 \                                -\CCIFG
7906 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
7907 \ TB0EX0                          \$3E0 
7908 \ ------------------------------\
7909 \ set TimerB to make 50kHz PWM  \
7910 \ ------------------------------\
7911 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
7912 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
7913 \ ------------------------------\
7914 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
7915 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
7916 \ ------------------------------\
7917     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
7918     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
7919 \ ------------------------------\
7920 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
7921 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
7922 \ ------------------------------\
7923 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
7924 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
7925 \ ------------------------------\
7926     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
7927 \ ------------------------------\
7928 \ set TimerB to generate PWM for LCD_Vo
7929 \ ------------------------------\
7930     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
7931 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
7932     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
7933 \ ------------------------------\
7934     BIS.B #LCDVo,&LCDVo_DIR     \
7935     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
7936 \ ------------------------------\
7937     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
7938     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
7939 \ ------------------------------\
7940     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
7941     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
7942 \ ------------------------------\
7943 \ WDT interval init part        \
7944 \ ------------------------------\
7945     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
7946 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
7947 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
7948     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
7949 \ ------------------------------\
7950 \ init RC5_Int                  \
7951 \ ------------------------------\
7952     BIS.B #RC5,&IR_IE           \ enable RC5_Int
7953     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
7954 \ ------------------------------\
7955 \ init interrupt vectors
7956 \ ------------------------------\
7957     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
7958     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
7959 \ ------------------------------\
7960 \ define LPM mode for ACCEPT    \
7961 \ ------------------------------\
7962 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
7963 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
7964 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
7965
7966 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
7967
7968 \ ------------------------------\
7969 \ Init LCD 2x20                 \
7970 \ ------------------------------\
7971     $03E8 20_US                \ 1-  wait 20 ms
7972     $03 TOP_LCD                \ 2- send DB5=DB4=1
7973     $CD 20_US                  \ 3- wait 4,1 ms
7974     $03 TOP_LCD                \ 4- send again DB5=DB4=1
7975     $5 20_US                   \ 5- wait 0,1 ms
7976     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
7977     $2 20_US                   \    wait 40 us = LCD cycle
7978     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
7979     $2 20_US                   \    wait 40 us = LCD cycle
7980     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
7981     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
7982     LCD_Clear                   \ 10- "LCD_Clear"
7983     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
7984     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
7985     LCD_Clear                   \ 10- "LCD_Clear"
7986     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
7987     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
7988     CR ." I love you"   
7989     ['] (CR) IS CR              \ ' (CR) is CR
7990     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
7991     CR
7992     ."    RC5toLCD is running. Type STOP to quit"
7993 \    NOECHO                      \ uncomment to run this app without terminal connexion
7994     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
7995     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
7996 ;
7997     \
7998
7999 : STOP                  \ stops multitasking, must to be used before downloading app
8000     ['] (WARM) IS WARM  \ remove START app from FORTH init process
8001     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
8002 ;
8003     \
8004
8005
8006 RST_STATE   ;
8007
8008
8009 CODE MAX    \    n1 n2 -- n3       signed maximum
8010             CMP     @PSP,TOS    \ n2-n1
8011             S<      ?GOTO FW1   \ n2<n1
8012 BW1         ADD     #2,PSP
8013             MOV     @IP+,PC
8014 ENDCODE
8015     \
8016
8017 CODE MIN    \    n1 n2 -- n3       signed minimum
8018             CMP     @PSP,TOS     \ n2-n1
8019             S<      ?GOTO BW1    \ n2<n1
8020 FW1         MOV     @PSP+,TOS
8021             MOV     @IP+,PC
8022 ENDCODE
8023     \
8024
8025 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
8026   >R  <# 0 # #S #>  
8027   R> OVER - 0 MAX SPACES TYPE
8028 ;
8029     \
8030
8031 CODE 20_US                      \ n --      n * 20 us
8032 BEGIN                           \ 3 cycles loop + 6~  
8033 \    MOV     #5,W                \ 3 MCLK = 1 MHz
8034 \    MOV     #23,W               \ 3 MCLK = 4 MHz
8035     MOV     #51,W               \ 3 MCLK = 8 MHz
8036 \    MOV     #104,W              \ 3 MCLK = 16 MHz
8037 \    MOV     #158,W              \ 3 MCLK = 24 MHz
8038     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
8039         SUB #1,W                \ 1
8040     0= UNTIL                    \ 2
8041     SUB     #1,TOS              \ 1
8042 0= UNTIL                        \ 2
8043     MOV     @PSP+,TOS           \ 2
8044     MOV     @IP+,PC             \ 4
8045 ENDCODE
8046     \
8047
8048 CODE TOP_LCD                    \ LCD Sample
8049 \                               \ if write : %xxxxWWWW --
8050 \                               \ if read  : -- %0000RRRR
8051     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
8052     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
8053 0= IF                           \ write LCD bits pattern
8054     AND.B #LCD_DB,TOS           \ 
8055     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
8056     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
8057     MOV @PSP+,TOS               \
8058     MOV @IP+,PC
8059 THEN                            \ read LCD bits pattern
8060     SUB #2,PSP
8061     MOV TOS,0(PSP)
8062     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
8063     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
8064     AND.B #LCD_DB,TOS           \
8065     MOV @IP+,PC
8066 ENDCODE
8067     \
8068
8069 CODE LCD_W                      \ byte --       write byte to LCD 
8070     SUB #2,PSP                  \
8071     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
8072     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
8073     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
8074     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
8075 COLON                           \ high level word starts here 
8076     TOP_LCD 2 20_US             \ write high nibble first
8077     TOP_LCD 2 20_US 
8078 ;
8079     \
8080
8081 CODE LCD_WrC                    \ char --         Write Char
8082     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
8083     JMP LCD_W 
8084 ENDCODE
8085     \
8086
8087 CODE LCD_WrF                    \ func --         Write Fonction
8088     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
8089     JMP LCD_W 
8090 ENDCODE
8091     \
8092
8093 : LCD_Clear 
8094     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
8095 ;
8096     \
8097
8098 : LCD_Home 
8099     $02 LCD_WrF 100 20_us 
8100 ;
8101     \
8102
8103 \ : LCD_Entry_set       $04 OR LCD_WrF ;
8104
8105 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
8106
8107 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
8108
8109 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
8110
8111 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
8112
8113 \ : LCD_Goto            $80 OR LCD_WrF ;
8114
8115 \ CODE LCD_R                      \ -- byte       read byte from LCD
8116 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
8117 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
8118 \ COLON                           \ starts a FORTH word
8119 \     TOP_LCD 2 20_us             \ -- %0000HHHH
8120 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
8121 \ HI2LO                           \ switch from FORTH to assembler
8122 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
8123 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
8124 \     MOV @RSP+,IP                \ restore IP saved by COLON
8125 \     MOV @IP+,PC                 \
8126 \ ENDCODE
8127 \     \
8128
8129 \ CODE LCD_RdS                    \ -- status       Read Status
8130 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
8131 \     JMP LCD_R
8132 \ ENDCODE
8133 \     \
8134
8135 \ CODE LCD_RdC                    \ -- char         Read Char
8136 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
8137 \     JMP LCD_R
8138 \ ENDCODE
8139 \     \
8140
8141 \ -------------+------+------+------+------++---+---+---+---+---------+
8142 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
8143 \ -------------+------+------+------+------++---+---+---+---+---------+
8144 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
8145 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
8146 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
8147 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
8148 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
8149 \ -------------+------+------+------+------++---+---+---+---+---------+
8150
8151
8152 \ ******************************\
8153 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
8154 \ ******************************\
8155 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
8156 \ ------------------------------\
8157 \ define LPM mode for ACCEPT    \
8158 \ ------------------------------\
8159 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
8160 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
8161 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
8162 BIT.B #SW2,&SW2_IN              \ test switch S2
8163 0= IF                           \ case of switch S2 pressed
8164     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
8165     U< IF
8166         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
8167     THEN
8168 ELSE
8169     BIT.B #SW1,&SW1_IN          \ test switch S1 input
8170     0= IF                       \ case of Switch S1 pressed
8171         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
8172         U>= IF                  \
8173             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
8174         THEN                    \
8175     THEN                        \
8176 THEN                            \
8177 RETI                            \ CPU is ON, GIE is OFF
8178 ENDASM                          \
8179     \
8180
8181
8182 \ ------------------------------\
8183 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
8184 \ ******************************\
8185 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
8186 \ ******************************\
8187 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
8188 \                               \       SMclock = 8|16|24 MHz
8189 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
8190 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
8191 \                               \       SR(9)=new Toggle bit memory (ADD on)
8192 \ ------------------------------\
8193 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
8194 \ ------------------------------\
8195 \ define LPM mode for ACCEPT    \
8196 \ ------------------------------\
8197 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
8198 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
8199 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
8200 \ ------------------------------\
8201 \ RC5_FirstStartBitHalfCycle:   \
8202 \ ------------------------------\
8203 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
8204 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
8205 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
8206 MOV     #1778,X                 \ RC5_Period in us
8207 MOV     #14,W                   \ count of loop
8208 BEGIN                           \
8209 \ ------------------------------\
8210 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
8211 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
8212     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
8213 \ RC5_Compute_3/4_Period:       \                   |
8214     RRUM    #1,X                \ X=1/2 cycle       |
8215     MOV     X,Y                 \ Y=1/2             ^
8216     RRUM    #1,Y                \ Y=1/4
8217     ADD     X,Y                 \ Y=3/4
8218 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
8219     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
8220     0= UNTIL                    \
8221 \ ------------------------------\
8222 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
8223 \ ------------------------------\
8224     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
8225     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
8226     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
8227     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
8228     SUB     #1,W                \ decrement count loop
8229 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
8230 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
8231 0<> WHILE                       \ ----> out of loop ----+
8232 \ RC5_compute_7/4_Time_out:     \                       |
8233     ADD     X,Y                 \                       |   out of bound = 7/4 period 
8234 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
8235     BEGIN                       \                       |
8236         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
8237         0>= IF                  \                       |   if cycle time out of bound
8238             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
8239             RETI                \                       |   then quit to do nothing
8240         THEN                    \                       |
8241 \ ------------------------------\                       |
8242         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
8243     0<> UNTIL                   \                   |   |
8244     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
8245 REPEAT                          \ ----> loop back --+   |
8246 \ ------------------------------\                       |
8247 \ RC5_SampleEndOf:              \ <---------------------+
8248 \ ------------------------------\
8249 BIC     #$30,&TA0CTL           \ stop timer_A0
8250 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
8251 \ ******************************\
8252 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
8253 \ ******************************\
8254 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
8255 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
8256 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
8257 BIT     #BIT13,X                \ X(13) = New_RC5_command
8258 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
8259 THEN                            \
8260 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
8261 \ ******************************\
8262 \ RC5_ComputeNewRC5word         \
8263 \ ******************************\
8264 SUB     #4,PSP                  \
8265 MOV     &BASE,2(PSP)            \ save variable BASE before use
8266 MOV     TOS,0(PSP)              \ save TOS before use
8267 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
8268 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
8269 \ ******************************\
8270 \ RC5_ComputeC6bit              \
8271 \ ******************************\
8272 BIT     #$4000,IP              \ test /C6 bit in IP
8273 0= IF   BIS #$40,TOS           \ set C6 bit in S
8274 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
8275 \ ******************************\
8276 \ RC5_CommandByteIsDone         \ RC5_code --
8277 \ ******************************\
8278
8279 \ ------------------------------\
8280 \ Display IR_RC5 code           \
8281 \ ------------------------------\
8282 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
8283 \ ------------------------------\
8284 LO2HI                           \ switch from assembler to FORTH
8285     ['] LCD_CLEAR IS CR         \ redirects CR
8286     ['] LCD_WrC  IS EMIT        \ redirects EMIT
8287     $10 BASE !                 \ change BASE to hexadecimal
8288     CR ." $" 2 U.R             \ print IR_RC5 code
8289     ['] (CR) IS CR              \ restore CR
8290     ['] (EMIT) IS EMIT          \ restore EMIT
8291 HI2LO                           \ switch from FORTH to assembler
8292 \ ------------------------------\
8293 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
8294 \ ------------------------------\
8295 MOV @PSP+,&BASE                 \ restore variable BASE
8296 RETI                            \ CPU is ON, GIE is OFF
8297 ENDASM                          \
8298     \ 
8299
8300 CODE START                      \
8301 \ ------------------------------\
8302 \ TB0CTL = %0000 0010 1001 0100\$3C0
8303 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
8304 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
8305 \                      --       \ID input divider \ 10 = /4
8306 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
8307 \                            -  \TBCLR TimerB Clear
8308 \                             - \TBIE
8309 \                              -\TBIFG
8310 \ --------------------------------\\
8311 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
8312 \              --                 \CM Capture Mode
8313 \                --               \CCIS
8314 \                   -             \SCS
8315 \                    --           \CLLD
8316 \                      -          \CAP
8317 \                        ---      \OUTMOD \ 011 = set/reset
8318 \                           -     \CCIE
8319 \                             -   \CCI
8320 \                              -  \OUT
8321 \                               - \COV
8322 \                                -\CCIFG
8323 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
8324 \ TB0EX0                          \$3E0 
8325 \ ------------------------------\
8326 \ set TimerB to make 50kHz PWM  \
8327 \ ------------------------------\
8328 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
8329 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
8330 \ ------------------------------\
8331 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
8332 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
8333 \ ------------------------------\
8334     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
8335     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
8336 \ ------------------------------\
8337 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
8338 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
8339 \ ------------------------------\
8340 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
8341 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
8342 \ ------------------------------\
8343     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
8344 \ ------------------------------\
8345 \ set TimerB to generate PWM for LCD_Vo
8346 \ ------------------------------\
8347     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
8348 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
8349     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
8350 \ ------------------------------\
8351     BIS.B #LCDVo,&LCDVo_DIR     \
8352     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
8353 \ ------------------------------\
8354     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
8355     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
8356 \ ------------------------------\
8357     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
8358     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
8359 \ ------------------------------\
8360 \ WDT interval init part        \
8361 \ ------------------------------\
8362     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
8363 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
8364 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
8365     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
8366 \ ------------------------------\
8367 \ init RC5_Int                  \
8368 \ ------------------------------\
8369     BIS.B #RC5,&IR_IE           \ enable RC5_Int
8370     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
8371 \ ------------------------------\
8372 \ init interrupt vectors
8373 \ ------------------------------\
8374     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
8375     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
8376 \ ------------------------------\
8377 \ define LPM mode for ACCEPT    \
8378 \ ------------------------------\
8379 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
8380 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
8381 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
8382
8383 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
8384
8385 \ ------------------------------\
8386 \ Init LCD 2x20                 \
8387 \ ------------------------------\
8388     $03E8 20_US                \ 1-  wait 20 ms
8389     $03 TOP_LCD                \ 2- send DB5=DB4=1
8390     $CD 20_US                  \ 3- wait 4,1 ms
8391     $03 TOP_LCD                \ 4- send again DB5=DB4=1
8392     $5 20_US                   \ 5- wait 0,1 ms
8393     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
8394     $2 20_US                   \    wait 40 us = LCD cycle
8395     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
8396     $2 20_US                   \    wait 40 us = LCD cycle
8397     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
8398     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
8399     LCD_Clear                   \ 10- "LCD_Clear"
8400     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
8401     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
8402     LCD_Clear                   \ 10- "LCD_Clear"
8403     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
8404     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
8405     CR ." I love you"   
8406     ['] (CR) IS CR              \ ' (CR) is CR
8407     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
8408     CR
8409     ."    RC5toLCD is running. Type STOP to quit"
8410 \    NOECHO                      \ uncomment to run this app without terminal connexion
8411     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
8412     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
8413 ;
8414     \
8415
8416 : STOP                  \ stops multitasking, must to be used before downloading app
8417     ['] (WARM) IS WARM  \ remove START app from FORTH init process
8418     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
8419 ;
8420     \
8421
8422
8423 RST_STATE   ;
8424
8425
8426 CODE MAX    \    n1 n2 -- n3       signed maximum
8427             CMP     @PSP,TOS    \ n2-n1
8428             S<      ?GOTO FW1   \ n2<n1
8429 BW1         ADD     #2,PSP
8430             MOV     @IP+,PC
8431 ENDCODE
8432     \
8433
8434 CODE MIN    \    n1 n2 -- n3       signed minimum
8435             CMP     @PSP,TOS     \ n2-n1
8436             S<      ?GOTO BW1    \ n2<n1
8437 FW1         MOV     @PSP+,TOS
8438             MOV     @IP+,PC
8439 ENDCODE
8440     \
8441
8442 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
8443   >R  <# 0 # #S #>  
8444   R> OVER - 0 MAX SPACES TYPE
8445 ;
8446     \
8447
8448 CODE 20_US                      \ n --      n * 20 us
8449 BEGIN                           \ 3 cycles loop + 6~  
8450 \    MOV     #5,W                \ 3 MCLK = 1 MHz
8451 \    MOV     #23,W               \ 3 MCLK = 4 MHz
8452     MOV     #51,W               \ 3 MCLK = 8 MHz
8453 \    MOV     #104,W              \ 3 MCLK = 16 MHz
8454 \    MOV     #158,W              \ 3 MCLK = 24 MHz
8455     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
8456         SUB #1,W                \ 1
8457     0= UNTIL                    \ 2
8458     SUB     #1,TOS              \ 1
8459 0= UNTIL                        \ 2
8460     MOV     @PSP+,TOS           \ 2
8461     MOV     @IP+,PC             \ 4
8462 ENDCODE
8463     \
8464
8465 CODE TOP_LCD                    \ LCD Sample
8466 \                               \ if write : %xxxxWWWW --
8467 \                               \ if read  : -- %0000RRRR
8468     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
8469     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
8470 0= IF                           \ write LCD bits pattern
8471     AND.B #LCD_DB,TOS           \ 
8472     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
8473     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
8474     MOV @PSP+,TOS               \
8475     MOV @IP+,PC
8476 THEN                            \ read LCD bits pattern
8477     SUB #2,PSP
8478     MOV TOS,0(PSP)
8479     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
8480     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
8481     AND.B #LCD_DB,TOS           \
8482     MOV @IP+,PC
8483 ENDCODE
8484     \
8485
8486 CODE LCD_W                      \ byte --       write byte to LCD 
8487     SUB #2,PSP                  \
8488     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
8489     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
8490     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
8491     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
8492 COLON                           \ high level word starts here 
8493     TOP_LCD 2 20_US             \ write high nibble first
8494     TOP_LCD 2 20_US 
8495 ;
8496     \
8497
8498 CODE LCD_WrC                    \ char --         Write Char
8499     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
8500     JMP LCD_W 
8501 ENDCODE
8502     \
8503
8504 CODE LCD_WrF                    \ func --         Write Fonction
8505     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
8506     JMP LCD_W 
8507 ENDCODE
8508     \
8509
8510 : LCD_Clear 
8511     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
8512 ;
8513     \
8514
8515 : LCD_Home 
8516     $02 LCD_WrF 100 20_us 
8517 ;
8518     \
8519
8520 \ : LCD_Entry_set       $04 OR LCD_WrF ;
8521
8522 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
8523
8524 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
8525
8526 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
8527
8528 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
8529
8530 \ : LCD_Goto            $80 OR LCD_WrF ;
8531
8532 \ CODE LCD_R                      \ -- byte       read byte from LCD
8533 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
8534 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
8535 \ COLON                           \ starts a FORTH word
8536 \     TOP_LCD 2 20_us             \ -- %0000HHHH
8537 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
8538 \ HI2LO                           \ switch from FORTH to assembler
8539 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
8540 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
8541 \     MOV @RSP+,IP                \ restore IP saved by COLON
8542 \     MOV @IP+,PC                 \
8543 \ ENDCODE
8544 \     \
8545
8546 \ CODE LCD_RdS                    \ -- status       Read Status
8547 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
8548 \     JMP LCD_R
8549 \ ENDCODE
8550 \     \
8551
8552 \ CODE LCD_RdC                    \ -- char         Read Char
8553 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
8554 \     JMP LCD_R
8555 \ ENDCODE
8556 \     \
8557
8558 \ -------------+------+------+------+------++---+---+---+---+---------+
8559 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
8560 \ -------------+------+------+------+------++---+---+---+---+---------+
8561 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
8562 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
8563 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
8564 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
8565 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
8566 \ -------------+------+------+------+------++---+---+---+---+---------+
8567
8568
8569 \ ******************************\
8570 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
8571 \ ******************************\
8572 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
8573 \ ------------------------------\
8574 \ define LPM mode for ACCEPT    \
8575 \ ------------------------------\
8576 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
8577 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
8578 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
8579 BIT.B #SW2,&SW2_IN              \ test switch S2
8580 0= IF                           \ case of switch S2 pressed
8581     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
8582     U< IF
8583         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
8584     THEN
8585 ELSE
8586     BIT.B #SW1,&SW1_IN          \ test switch S1 input
8587     0= IF                       \ case of Switch S1 pressed
8588         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
8589         U>= IF                  \
8590             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
8591         THEN                    \
8592     THEN                        \
8593 THEN                            \
8594 RETI                            \ CPU is ON, GIE is OFF
8595 ENDASM                          \
8596     \
8597
8598
8599 \ ------------------------------\
8600 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
8601 \ ******************************\
8602 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
8603 \ ******************************\
8604 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
8605 \                               \       SMclock = 8|16|24 MHz
8606 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
8607 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
8608 \                               \       SR(9)=new Toggle bit memory (ADD on)
8609 \ ------------------------------\
8610 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
8611 \ ------------------------------\
8612 \ define LPM mode for ACCEPT    \
8613 \ ------------------------------\
8614 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
8615 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
8616 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
8617 \ ------------------------------\
8618 \ RC5_FirstStartBitHalfCycle:   \
8619 \ ------------------------------\
8620 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
8621 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
8622 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
8623 MOV     #1778,X                 \ RC5_Period in us
8624 MOV     #14,W                   \ count of loop
8625 BEGIN                           \
8626 \ ------------------------------\
8627 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
8628 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
8629     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
8630 \ RC5_Compute_3/4_Period:       \                   |
8631     RRUM    #1,X                \ X=1/2 cycle       |
8632     MOV     X,Y                 \ Y=1/2             ^
8633     RRUM    #1,Y                \ Y=1/4
8634     ADD     X,Y                 \ Y=3/4
8635 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
8636     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
8637     0= UNTIL                    \
8638 \ ------------------------------\
8639 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
8640 \ ------------------------------\
8641     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
8642     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
8643     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
8644     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
8645     SUB     #1,W                \ decrement count loop
8646 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
8647 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
8648 0<> WHILE                       \ ----> out of loop ----+
8649 \ RC5_compute_7/4_Time_out:     \                       |
8650     ADD     X,Y                 \                       |   out of bound = 7/4 period 
8651 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
8652     BEGIN                       \                       |
8653         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
8654         0>= IF                  \                       |   if cycle time out of bound
8655             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
8656             RETI                \                       |   then quit to do nothing
8657         THEN                    \                       |
8658 \ ------------------------------\                       |
8659         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
8660     0<> UNTIL                   \                   |   |
8661     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
8662 REPEAT                          \ ----> loop back --+   |
8663 \ ------------------------------\                       |
8664 \ RC5_SampleEndOf:              \ <---------------------+
8665 \ ------------------------------\
8666 BIC     #$30,&TA0CTL           \ stop timer_A0
8667 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
8668 \ ******************************\
8669 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
8670 \ ******************************\
8671 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
8672 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
8673 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
8674 BIT     #BIT13,X                \ X(13) = New_RC5_command
8675 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
8676 THEN                            \
8677 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
8678 \ ******************************\
8679 \ RC5_ComputeNewRC5word         \
8680 \ ******************************\
8681 SUB     #4,PSP                  \
8682 MOV     &BASE,2(PSP)            \ save variable BASE before use
8683 MOV     TOS,0(PSP)              \ save TOS before use
8684 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
8685 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
8686 \ ******************************\
8687 \ RC5_ComputeC6bit              \
8688 \ ******************************\
8689 BIT     #$4000,IP              \ test /C6 bit in IP
8690 0= IF   BIS #$40,TOS           \ set C6 bit in S
8691 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
8692 \ ******************************\
8693 \ RC5_CommandByteIsDone         \ RC5_code --
8694 \ ******************************\
8695
8696 \ ------------------------------\
8697 \ Display IR_RC5 code           \
8698 \ ------------------------------\
8699 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
8700 \ ------------------------------\
8701 LO2HI                           \ switch from assembler to FORTH
8702     ['] LCD_CLEAR IS CR         \ redirects CR
8703     ['] LCD_WrC  IS EMIT        \ redirects EMIT
8704     $10 BASE !                 \ change BASE to hexadecimal
8705     CR ." $" 2 U.R             \ print IR_RC5 code
8706     ['] (CR) IS CR              \ restore CR
8707     ['] (EMIT) IS EMIT          \ restore EMIT
8708 HI2LO                           \ switch from FORTH to assembler
8709 \ ------------------------------\
8710 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
8711 \ ------------------------------\
8712 MOV @PSP+,&BASE                 \ restore variable BASE
8713 RETI                            \ CPU is ON, GIE is OFF
8714 ENDASM                          \
8715     \ 
8716
8717 CODE START                      \
8718 \ ------------------------------\
8719 \ TB0CTL = %0000 0010 1001 0100\$3C0
8720 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
8721 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
8722 \                      --       \ID input divider \ 10 = /4
8723 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
8724 \                            -  \TBCLR TimerB Clear
8725 \                             - \TBIE
8726 \                              -\TBIFG
8727 \ --------------------------------\\
8728 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
8729 \              --                 \CM Capture Mode
8730 \                --               \CCIS
8731 \                   -             \SCS
8732 \                    --           \CLLD
8733 \                      -          \CAP
8734 \                        ---      \OUTMOD \ 011 = set/reset
8735 \                           -     \CCIE
8736 \                             -   \CCI
8737 \                              -  \OUT
8738 \                               - \COV
8739 \                                -\CCIFG
8740 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
8741 \ TB0EX0                          \$3E0 
8742 \ ------------------------------\
8743 \ set TimerB to make 50kHz PWM  \
8744 \ ------------------------------\
8745 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
8746 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
8747 \ ------------------------------\
8748 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
8749 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
8750 \ ------------------------------\
8751     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
8752     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
8753 \ ------------------------------\
8754 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
8755 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
8756 \ ------------------------------\
8757 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
8758 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
8759 \ ------------------------------\
8760     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
8761 \ ------------------------------\
8762 \ set TimerB to generate PWM for LCD_Vo
8763 \ ------------------------------\
8764     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
8765 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
8766     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
8767 \ ------------------------------\
8768     BIS.B #LCDVo,&LCDVo_DIR     \
8769     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
8770 \ ------------------------------\
8771     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
8772     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
8773 \ ------------------------------\
8774     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
8775     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
8776 \ ------------------------------\
8777 \ WDT interval init part        \
8778 \ ------------------------------\
8779     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
8780 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
8781 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
8782     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
8783 \ ------------------------------\
8784 \ init RC5_Int                  \
8785 \ ------------------------------\
8786     BIS.B #RC5,&IR_IE           \ enable RC5_Int
8787     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
8788 \ ------------------------------\
8789 \ init interrupt vectors
8790 \ ------------------------------\
8791     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
8792     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
8793 \ ------------------------------\
8794 \ define LPM mode for ACCEPT    \
8795 \ ------------------------------\
8796 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
8797 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
8798 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
8799
8800 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
8801
8802 \ ------------------------------\
8803 \ Init LCD 2x20                 \
8804 \ ------------------------------\
8805     $03E8 20_US                \ 1-  wait 20 ms
8806     $03 TOP_LCD                \ 2- send DB5=DB4=1
8807     $CD 20_US                  \ 3- wait 4,1 ms
8808     $03 TOP_LCD                \ 4- send again DB5=DB4=1
8809     $5 20_US                   \ 5- wait 0,1 ms
8810     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
8811     $2 20_US                   \    wait 40 us = LCD cycle
8812     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
8813     $2 20_US                   \    wait 40 us = LCD cycle
8814     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
8815     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
8816     LCD_Clear                   \ 10- "LCD_Clear"
8817     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
8818     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
8819     LCD_Clear                   \ 10- "LCD_Clear"
8820     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
8821     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
8822     CR ." I love you"   
8823     ['] (CR) IS CR              \ ' (CR) is CR
8824     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
8825     CR
8826     ."    RC5toLCD is running. Type STOP to quit"
8827 \    NOECHO                      \ uncomment to run this app without terminal connexion
8828     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
8829     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
8830 ;
8831     \
8832
8833 : STOP                  \ stops multitasking, must to be used before downloading app
8834     ['] (WARM) IS WARM  \ remove START app from FORTH init process
8835     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
8836 ;
8837     \
8838
8839
8840 RST_STATE   ;
8841
8842
8843 CODE MAX    \    n1 n2 -- n3       signed maximum
8844             CMP     @PSP,TOS    \ n2-n1
8845             S<      ?GOTO FW1   \ n2<n1
8846 BW1         ADD     #2,PSP
8847             MOV     @IP+,PC
8848 ENDCODE
8849     \
8850
8851 CODE MIN    \    n1 n2 -- n3       signed minimum
8852             CMP     @PSP,TOS     \ n2-n1
8853             S<      ?GOTO BW1    \ n2<n1
8854 FW1         MOV     @PSP+,TOS
8855             MOV     @IP+,PC
8856 ENDCODE
8857     \
8858
8859 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
8860   >R  <# 0 # #S #>  
8861   R> OVER - 0 MAX SPACES TYPE
8862 ;
8863     \
8864
8865 CODE 20_US                      \ n --      n * 20 us
8866 BEGIN                           \ 3 cycles loop + 6~  
8867 \    MOV     #5,W                \ 3 MCLK = 1 MHz
8868 \    MOV     #23,W               \ 3 MCLK = 4 MHz
8869     MOV     #51,W               \ 3 MCLK = 8 MHz
8870 \    MOV     #104,W              \ 3 MCLK = 16 MHz
8871 \    MOV     #158,W              \ 3 MCLK = 24 MHz
8872     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
8873         SUB #1,W                \ 1
8874     0= UNTIL                    \ 2
8875     SUB     #1,TOS              \ 1
8876 0= UNTIL                        \ 2
8877     MOV     @PSP+,TOS           \ 2
8878     MOV     @IP+,PC             \ 4
8879 ENDCODE
8880     \
8881
8882 CODE TOP_LCD                    \ LCD Sample
8883 \                               \ if write : %xxxxWWWW --
8884 \                               \ if read  : -- %0000RRRR
8885     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
8886     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
8887 0= IF                           \ write LCD bits pattern
8888     AND.B #LCD_DB,TOS           \ 
8889     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
8890     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
8891     MOV @PSP+,TOS               \
8892     MOV @IP+,PC
8893 THEN                            \ read LCD bits pattern
8894     SUB #2,PSP
8895     MOV TOS,0(PSP)
8896     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
8897     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
8898     AND.B #LCD_DB,TOS           \
8899     MOV @IP+,PC
8900 ENDCODE
8901     \
8902
8903 CODE LCD_W                      \ byte --       write byte to LCD 
8904     SUB #2,PSP                  \
8905     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
8906     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
8907     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
8908     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
8909 COLON                           \ high level word starts here 
8910     TOP_LCD 2 20_US             \ write high nibble first
8911     TOP_LCD 2 20_US 
8912 ;
8913     \
8914
8915 CODE LCD_WrC                    \ char --         Write Char
8916     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
8917     JMP LCD_W 
8918 ENDCODE
8919     \
8920
8921 CODE LCD_WrF                    \ func --         Write Fonction
8922     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
8923     JMP LCD_W 
8924 ENDCODE
8925     \
8926
8927 : LCD_Clear 
8928     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
8929 ;
8930     \
8931
8932 : LCD_Home 
8933     $02 LCD_WrF 100 20_us 
8934 ;
8935     \
8936
8937 \ : LCD_Entry_set       $04 OR LCD_WrF ;
8938
8939 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
8940
8941 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
8942
8943 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
8944
8945 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
8946
8947 \ : LCD_Goto            $80 OR LCD_WrF ;
8948
8949 \ CODE LCD_R                      \ -- byte       read byte from LCD
8950 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
8951 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
8952 \ COLON                           \ starts a FORTH word
8953 \     TOP_LCD 2 20_us             \ -- %0000HHHH
8954 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
8955 \ HI2LO                           \ switch from FORTH to assembler
8956 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
8957 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
8958 \     MOV @RSP+,IP                \ restore IP saved by COLON
8959 \     MOV @IP+,PC                 \
8960 \ ENDCODE
8961 \     \
8962
8963 \ CODE LCD_RdS                    \ -- status       Read Status
8964 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
8965 \     JMP LCD_R
8966 \ ENDCODE
8967 \     \
8968
8969 \ CODE LCD_RdC                    \ -- char         Read Char
8970 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
8971 \     JMP LCD_R
8972 \ ENDCODE
8973 \     \
8974
8975 \ -------------+------+------+------+------++---+---+---+---+---------+
8976 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
8977 \ -------------+------+------+------+------++---+---+---+---+---------+
8978 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
8979 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
8980 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
8981 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
8982 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
8983 \ -------------+------+------+------+------++---+---+---+---+---------+
8984
8985
8986 \ ******************************\
8987 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
8988 \ ******************************\
8989 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
8990 \ ------------------------------\
8991 \ define LPM mode for ACCEPT    \
8992 \ ------------------------------\
8993 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
8994 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
8995 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
8996 BIT.B #SW2,&SW2_IN              \ test switch S2
8997 0= IF                           \ case of switch S2 pressed
8998     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
8999     U< IF
9000         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
9001     THEN
9002 ELSE
9003     BIT.B #SW1,&SW1_IN          \ test switch S1 input
9004     0= IF                       \ case of Switch S1 pressed
9005         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
9006         U>= IF                  \
9007             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
9008         THEN                    \
9009     THEN                        \
9010 THEN                            \
9011 RETI                            \ CPU is ON, GIE is OFF
9012 ENDASM                          \
9013     \
9014
9015
9016 \ ------------------------------\
9017 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
9018 \ ******************************\
9019 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
9020 \ ******************************\
9021 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
9022 \                               \       SMclock = 8|16|24 MHz
9023 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
9024 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
9025 \                               \       SR(9)=new Toggle bit memory (ADD on)
9026 \ ------------------------------\
9027 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
9028 \ ------------------------------\
9029 \ define LPM mode for ACCEPT    \
9030 \ ------------------------------\
9031 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
9032 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
9033 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
9034 \ ------------------------------\
9035 \ RC5_FirstStartBitHalfCycle:   \
9036 \ ------------------------------\
9037 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
9038 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
9039 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
9040 MOV     #1778,X                 \ RC5_Period in us
9041 MOV     #14,W                   \ count of loop
9042 BEGIN                           \
9043 \ ------------------------------\
9044 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
9045 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
9046     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
9047 \ RC5_Compute_3/4_Period:       \                   |
9048     RRUM    #1,X                \ X=1/2 cycle       |
9049     MOV     X,Y                 \ Y=1/2             ^
9050     RRUM    #1,Y                \ Y=1/4
9051     ADD     X,Y                 \ Y=3/4
9052 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
9053     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
9054     0= UNTIL                    \
9055 \ ------------------------------\
9056 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
9057 \ ------------------------------\
9058     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
9059     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
9060     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
9061     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
9062     SUB     #1,W                \ decrement count loop
9063 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
9064 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
9065 0<> WHILE                       \ ----> out of loop ----+
9066 \ RC5_compute_7/4_Time_out:     \                       |
9067     ADD     X,Y                 \                       |   out of bound = 7/4 period 
9068 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
9069     BEGIN                       \                       |
9070         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
9071         0>= IF                  \                       |   if cycle time out of bound
9072             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
9073             RETI                \                       |   then quit to do nothing
9074         THEN                    \                       |
9075 \ ------------------------------\                       |
9076         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
9077     0<> UNTIL                   \                   |   |
9078     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
9079 REPEAT                          \ ----> loop back --+   |
9080 \ ------------------------------\                       |
9081 \ RC5_SampleEndOf:              \ <---------------------+
9082 \ ------------------------------\
9083 BIC     #$30,&TA0CTL           \ stop timer_A0
9084 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
9085 \ ******************************\
9086 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
9087 \ ******************************\
9088 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
9089 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
9090 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
9091 BIT     #BIT13,X                \ X(13) = New_RC5_command
9092 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
9093 THEN                            \
9094 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
9095 \ ******************************\
9096 \ RC5_ComputeNewRC5word         \
9097 \ ******************************\
9098 SUB     #4,PSP                  \
9099 MOV     &BASE,2(PSP)            \ save variable BASE before use
9100 MOV     TOS,0(PSP)              \ save TOS before use
9101 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
9102 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
9103 \ ******************************\
9104 \ RC5_ComputeC6bit              \
9105 \ ******************************\
9106 BIT     #$4000,IP              \ test /C6 bit in IP
9107 0= IF   BIS #$40,TOS           \ set C6 bit in S
9108 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
9109 \ ******************************\
9110 \ RC5_CommandByteIsDone         \ RC5_code --
9111 \ ******************************\
9112
9113 \ ------------------------------\
9114 \ Display IR_RC5 code           \
9115 \ ------------------------------\
9116 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
9117 \ ------------------------------\
9118 LO2HI                           \ switch from assembler to FORTH
9119     ['] LCD_CLEAR IS CR         \ redirects CR
9120     ['] LCD_WrC  IS EMIT        \ redirects EMIT
9121     $10 BASE !                 \ change BASE to hexadecimal
9122     CR ." $" 2 U.R             \ print IR_RC5 code
9123     ['] (CR) IS CR              \ restore CR
9124     ['] (EMIT) IS EMIT          \ restore EMIT
9125 HI2LO                           \ switch from FORTH to assembler
9126 \ ------------------------------\
9127 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
9128 \ ------------------------------\
9129 MOV @PSP+,&BASE                 \ restore variable BASE
9130 RETI                            \ CPU is ON, GIE is OFF
9131 ENDASM                          \
9132     \ 
9133
9134 CODE START                      \
9135 \ ------------------------------\
9136 \ TB0CTL = %0000 0010 1001 0100\$3C0
9137 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
9138 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
9139 \                      --       \ID input divider \ 10 = /4
9140 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
9141 \                            -  \TBCLR TimerB Clear
9142 \                             - \TBIE
9143 \                              -\TBIFG
9144 \ --------------------------------\\
9145 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
9146 \              --                 \CM Capture Mode
9147 \                --               \CCIS
9148 \                   -             \SCS
9149 \                    --           \CLLD
9150 \                      -          \CAP
9151 \                        ---      \OUTMOD \ 011 = set/reset
9152 \                           -     \CCIE
9153 \                             -   \CCI
9154 \                              -  \OUT
9155 \                               - \COV
9156 \                                -\CCIFG
9157 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
9158 \ TB0EX0                          \$3E0 
9159 \ ------------------------------\
9160 \ set TimerB to make 50kHz PWM  \
9161 \ ------------------------------\
9162 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
9163 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
9164 \ ------------------------------\
9165 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
9166 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
9167 \ ------------------------------\
9168     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
9169     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
9170 \ ------------------------------\
9171 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
9172 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
9173 \ ------------------------------\
9174 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
9175 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
9176 \ ------------------------------\
9177     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
9178 \ ------------------------------\
9179 \ set TimerB to generate PWM for LCD_Vo
9180 \ ------------------------------\
9181     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
9182 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
9183     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
9184 \ ------------------------------\
9185     BIS.B #LCDVo,&LCDVo_DIR     \
9186     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
9187 \ ------------------------------\
9188     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
9189     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
9190 \ ------------------------------\
9191     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
9192     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
9193 \ ------------------------------\
9194 \ WDT interval init part        \
9195 \ ------------------------------\
9196     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
9197 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
9198 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
9199     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
9200 \ ------------------------------\
9201 \ init RC5_Int                  \
9202 \ ------------------------------\
9203     BIS.B #RC5,&IR_IE           \ enable RC5_Int
9204     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
9205 \ ------------------------------\
9206 \ init interrupt vectors
9207 \ ------------------------------\
9208     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
9209     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
9210 \ ------------------------------\
9211 \ define LPM mode for ACCEPT    \
9212 \ ------------------------------\
9213 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
9214 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
9215 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
9216
9217 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
9218
9219 \ ------------------------------\
9220 \ Init LCD 2x20                 \
9221 \ ------------------------------\
9222     $03E8 20_US                \ 1-  wait 20 ms
9223     $03 TOP_LCD                \ 2- send DB5=DB4=1
9224     $CD 20_US                  \ 3- wait 4,1 ms
9225     $03 TOP_LCD                \ 4- send again DB5=DB4=1
9226     $5 20_US                   \ 5- wait 0,1 ms
9227     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
9228     $2 20_US                   \    wait 40 us = LCD cycle
9229     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
9230     $2 20_US                   \    wait 40 us = LCD cycle
9231     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
9232     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
9233     LCD_Clear                   \ 10- "LCD_Clear"
9234     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
9235     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
9236     LCD_Clear                   \ 10- "LCD_Clear"
9237     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
9238     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
9239     CR ." I love you"   
9240     ['] (CR) IS CR              \ ' (CR) is CR
9241     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
9242     CR
9243     ."    RC5toLCD is running. Type STOP to quit"
9244 \    NOECHO                      \ uncomment to run this app without terminal connexion
9245     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
9246     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
9247 ;
9248     \
9249
9250 : STOP                  \ stops multitasking, must to be used before downloading app
9251     ['] (WARM) IS WARM  \ remove START app from FORTH init process
9252     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
9253 ;
9254     \
9255
9256
9257 RST_STATE   ;
9258
9259
9260 CODE MAX    \    n1 n2 -- n3       signed maximum
9261             CMP     @PSP,TOS    \ n2-n1
9262             S<      ?GOTO FW1   \ n2<n1
9263 BW1         ADD     #2,PSP
9264             MOV     @IP+,PC
9265 ENDCODE
9266     \
9267
9268 CODE MIN    \    n1 n2 -- n3       signed minimum
9269             CMP     @PSP,TOS     \ n2-n1
9270             S<      ?GOTO BW1    \ n2<n1
9271 FW1         MOV     @PSP+,TOS
9272             MOV     @IP+,PC
9273 ENDCODE
9274     \
9275
9276 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
9277   >R  <# 0 # #S #>  
9278   R> OVER - 0 MAX SPACES TYPE
9279 ;
9280     \
9281
9282 CODE 20_US                      \ n --      n * 20 us
9283 BEGIN                           \ 3 cycles loop + 6~  
9284 \    MOV     #5,W                \ 3 MCLK = 1 MHz
9285 \    MOV     #23,W               \ 3 MCLK = 4 MHz
9286     MOV     #51,W               \ 3 MCLK = 8 MHz
9287 \    MOV     #104,W              \ 3 MCLK = 16 MHz
9288 \    MOV     #158,W              \ 3 MCLK = 24 MHz
9289     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
9290         SUB #1,W                \ 1
9291     0= UNTIL                    \ 2
9292     SUB     #1,TOS              \ 1
9293 0= UNTIL                        \ 2
9294     MOV     @PSP+,TOS           \ 2
9295     MOV     @IP+,PC             \ 4
9296 ENDCODE
9297     \
9298
9299 CODE TOP_LCD                    \ LCD Sample
9300 \                               \ if write : %xxxxWWWW --
9301 \                               \ if read  : -- %0000RRRR
9302     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
9303     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
9304 0= IF                           \ write LCD bits pattern
9305     AND.B #LCD_DB,TOS           \ 
9306     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
9307     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
9308     MOV @PSP+,TOS               \
9309     MOV @IP+,PC
9310 THEN                            \ read LCD bits pattern
9311     SUB #2,PSP
9312     MOV TOS,0(PSP)
9313     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
9314     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
9315     AND.B #LCD_DB,TOS           \
9316     MOV @IP+,PC
9317 ENDCODE
9318     \
9319
9320 CODE LCD_W                      \ byte --       write byte to LCD 
9321     SUB #2,PSP                  \
9322     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
9323     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
9324     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
9325     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
9326 COLON                           \ high level word starts here 
9327     TOP_LCD 2 20_US             \ write high nibble first
9328     TOP_LCD 2 20_US 
9329 ;
9330     \
9331
9332 CODE LCD_WrC                    \ char --         Write Char
9333     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
9334     JMP LCD_W 
9335 ENDCODE
9336     \
9337
9338 CODE LCD_WrF                    \ func --         Write Fonction
9339     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
9340     JMP LCD_W 
9341 ENDCODE
9342     \
9343
9344 : LCD_Clear 
9345     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
9346 ;
9347     \
9348
9349 : LCD_Home 
9350     $02 LCD_WrF 100 20_us 
9351 ;
9352     \
9353
9354 \ : LCD_Entry_set       $04 OR LCD_WrF ;
9355
9356 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
9357
9358 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
9359
9360 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
9361
9362 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
9363
9364 \ : LCD_Goto            $80 OR LCD_WrF ;
9365
9366 \ CODE LCD_R                      \ -- byte       read byte from LCD
9367 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
9368 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
9369 \ COLON                           \ starts a FORTH word
9370 \     TOP_LCD 2 20_us             \ -- %0000HHHH
9371 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
9372 \ HI2LO                           \ switch from FORTH to assembler
9373 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
9374 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
9375 \     MOV @RSP+,IP                \ restore IP saved by COLON
9376 \     MOV @IP+,PC                 \
9377 \ ENDCODE
9378 \     \
9379
9380 \ CODE LCD_RdS                    \ -- status       Read Status
9381 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
9382 \     JMP LCD_R
9383 \ ENDCODE
9384 \     \
9385
9386 \ CODE LCD_RdC                    \ -- char         Read Char
9387 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
9388 \     JMP LCD_R
9389 \ ENDCODE
9390 \     \
9391
9392 \ -------------+------+------+------+------++---+---+---+---+---------+
9393 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
9394 \ -------------+------+------+------+------++---+---+---+---+---------+
9395 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
9396 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
9397 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
9398 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
9399 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
9400 \ -------------+------+------+------+------++---+---+---+---+---------+
9401
9402
9403 \ ******************************\
9404 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
9405 \ ******************************\
9406 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
9407 \ ------------------------------\
9408 \ define LPM mode for ACCEPT    \
9409 \ ------------------------------\
9410 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
9411 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
9412 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
9413 BIT.B #SW2,&SW2_IN              \ test switch S2
9414 0= IF                           \ case of switch S2 pressed
9415     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
9416     U< IF
9417         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
9418     THEN
9419 ELSE
9420     BIT.B #SW1,&SW1_IN          \ test switch S1 input
9421     0= IF                       \ case of Switch S1 pressed
9422         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
9423         U>= IF                  \
9424             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
9425         THEN                    \
9426     THEN                        \
9427 THEN                            \
9428 RETI                            \ CPU is ON, GIE is OFF
9429 ENDASM                          \
9430     \
9431
9432
9433 \ ------------------------------\
9434 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
9435 \ ******************************\
9436 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
9437 \ ******************************\
9438 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
9439 \                               \       SMclock = 8|16|24 MHz
9440 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
9441 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
9442 \                               \       SR(9)=new Toggle bit memory (ADD on)
9443 \ ------------------------------\
9444 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
9445 \ ------------------------------\
9446 \ define LPM mode for ACCEPT    \
9447 \ ------------------------------\
9448 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
9449 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
9450 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
9451 \ ------------------------------\
9452 \ RC5_FirstStartBitHalfCycle:   \
9453 \ ------------------------------\
9454 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
9455 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
9456 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
9457 MOV     #1778,X                 \ RC5_Period in us
9458 MOV     #14,W                   \ count of loop
9459 BEGIN                           \
9460 \ ------------------------------\
9461 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
9462 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
9463     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
9464 \ RC5_Compute_3/4_Period:       \                   |
9465     RRUM    #1,X                \ X=1/2 cycle       |
9466     MOV     X,Y                 \ Y=1/2             ^
9467     RRUM    #1,Y                \ Y=1/4
9468     ADD     X,Y                 \ Y=3/4
9469 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
9470     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
9471     0= UNTIL                    \
9472 \ ------------------------------\
9473 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
9474 \ ------------------------------\
9475     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
9476     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
9477     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
9478     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
9479     SUB     #1,W                \ decrement count loop
9480 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
9481 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
9482 0<> WHILE                       \ ----> out of loop ----+
9483 \ RC5_compute_7/4_Time_out:     \                       |
9484     ADD     X,Y                 \                       |   out of bound = 7/4 period 
9485 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
9486     BEGIN                       \                       |
9487         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
9488         0>= IF                  \                       |   if cycle time out of bound
9489             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
9490             RETI                \                       |   then quit to do nothing
9491         THEN                    \                       |
9492 \ ------------------------------\                       |
9493         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
9494     0<> UNTIL                   \                   |   |
9495     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
9496 REPEAT                          \ ----> loop back --+   |
9497 \ ------------------------------\                       |
9498 \ RC5_SampleEndOf:              \ <---------------------+
9499 \ ------------------------------\
9500 BIC     #$30,&TA0CTL           \ stop timer_A0
9501 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
9502 \ ******************************\
9503 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
9504 \ ******************************\
9505 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
9506 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
9507 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
9508 BIT     #BIT13,X                \ X(13) = New_RC5_command
9509 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
9510 THEN                            \
9511 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
9512 \ ******************************\
9513 \ RC5_ComputeNewRC5word         \
9514 \ ******************************\
9515 SUB     #4,PSP                  \
9516 MOV     &BASE,2(PSP)            \ save variable BASE before use
9517 MOV     TOS,0(PSP)              \ save TOS before use
9518 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
9519 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
9520 \ ******************************\
9521 \ RC5_ComputeC6bit              \
9522 \ ******************************\
9523 BIT     #$4000,IP              \ test /C6 bit in IP
9524 0= IF   BIS #$40,TOS           \ set C6 bit in S
9525 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
9526 \ ******************************\
9527 \ RC5_CommandByteIsDone         \ RC5_code --
9528 \ ******************************\
9529
9530 \ ------------------------------\
9531 \ Display IR_RC5 code           \
9532 \ ------------------------------\
9533 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
9534 \ ------------------------------\
9535 LO2HI                           \ switch from assembler to FORTH
9536     ['] LCD_CLEAR IS CR         \ redirects CR
9537     ['] LCD_WrC  IS EMIT        \ redirects EMIT
9538     $10 BASE !                 \ change BASE to hexadecimal
9539     CR ." $" 2 U.R             \ print IR_RC5 code
9540     ['] (CR) IS CR              \ restore CR
9541     ['] (EMIT) IS EMIT          \ restore EMIT
9542 HI2LO                           \ switch from FORTH to assembler
9543 \ ------------------------------\
9544 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
9545 \ ------------------------------\
9546 MOV @PSP+,&BASE                 \ restore variable BASE
9547 RETI                            \ CPU is ON, GIE is OFF
9548 ENDASM                          \
9549     \ 
9550
9551 CODE START                      \
9552 \ ------------------------------\
9553 \ TB0CTL = %0000 0010 1001 0100\$3C0
9554 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
9555 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
9556 \                      --       \ID input divider \ 10 = /4
9557 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
9558 \                            -  \TBCLR TimerB Clear
9559 \                             - \TBIE
9560 \                              -\TBIFG
9561 \ --------------------------------\\
9562 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
9563 \              --                 \CM Capture Mode
9564 \                --               \CCIS
9565 \                   -             \SCS
9566 \                    --           \CLLD
9567 \                      -          \CAP
9568 \                        ---      \OUTMOD \ 011 = set/reset
9569 \                           -     \CCIE
9570 \                             -   \CCI
9571 \                              -  \OUT
9572 \                               - \COV
9573 \                                -\CCIFG
9574 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
9575 \ TB0EX0                          \$3E0 
9576 \ ------------------------------\
9577 \ set TimerB to make 50kHz PWM  \
9578 \ ------------------------------\
9579 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
9580 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
9581 \ ------------------------------\
9582 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
9583 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
9584 \ ------------------------------\
9585     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
9586     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
9587 \ ------------------------------\
9588 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
9589 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
9590 \ ------------------------------\
9591 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
9592 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
9593 \ ------------------------------\
9594     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
9595 \ ------------------------------\
9596 \ set TimerB to generate PWM for LCD_Vo
9597 \ ------------------------------\
9598     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
9599 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
9600     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
9601 \ ------------------------------\
9602     BIS.B #LCDVo,&LCDVo_DIR     \
9603     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
9604 \ ------------------------------\
9605     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
9606     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
9607 \ ------------------------------\
9608     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
9609     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
9610 \ ------------------------------\
9611 \ WDT interval init part        \
9612 \ ------------------------------\
9613     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
9614 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
9615 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
9616     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
9617 \ ------------------------------\
9618 \ init RC5_Int                  \
9619 \ ------------------------------\
9620     BIS.B #RC5,&IR_IE           \ enable RC5_Int
9621     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
9622 \ ------------------------------\
9623 \ init interrupt vectors
9624 \ ------------------------------\
9625     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
9626     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
9627 \ ------------------------------\
9628 \ define LPM mode for ACCEPT    \
9629 \ ------------------------------\
9630 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
9631 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
9632 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
9633
9634 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
9635
9636 \ ------------------------------\
9637 \ Init LCD 2x20                 \
9638 \ ------------------------------\
9639     $03E8 20_US                \ 1-  wait 20 ms
9640     $03 TOP_LCD                \ 2- send DB5=DB4=1
9641     $CD 20_US                  \ 3- wait 4,1 ms
9642     $03 TOP_LCD                \ 4- send again DB5=DB4=1
9643     $5 20_US                   \ 5- wait 0,1 ms
9644     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
9645     $2 20_US                   \    wait 40 us = LCD cycle
9646     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
9647     $2 20_US                   \    wait 40 us = LCD cycle
9648     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
9649     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
9650     LCD_Clear                   \ 10- "LCD_Clear"
9651     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
9652     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
9653     LCD_Clear                   \ 10- "LCD_Clear"
9654     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
9655     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
9656     CR ." I love you"   
9657     ['] (CR) IS CR              \ ' (CR) is CR
9658     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
9659     CR
9660     ."    RC5toLCD is running. Type STOP to quit"
9661 \    NOECHO                      \ uncomment to run this app without terminal connexion
9662     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
9663     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
9664 ;
9665     \
9666
9667 : STOP                  \ stops multitasking, must to be used before downloading app
9668     ['] (WARM) IS WARM  \ remove START app from FORTH init process
9669     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
9670 ;
9671     \
9672
9673
9674 RST_STATE   ;
9675
9676
9677 CODE MAX    \    n1 n2 -- n3       signed maximum
9678             CMP     @PSP,TOS    \ n2-n1
9679             S<      ?GOTO FW1   \ n2<n1
9680 BW1         ADD     #2,PSP
9681             MOV     @IP+,PC
9682 ENDCODE
9683     \
9684
9685 CODE MIN    \    n1 n2 -- n3       signed minimum
9686             CMP     @PSP,TOS     \ n2-n1
9687             S<      ?GOTO BW1    \ n2<n1
9688 FW1         MOV     @PSP+,TOS
9689             MOV     @IP+,PC
9690 ENDCODE
9691     \
9692
9693 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
9694   >R  <# 0 # #S #>  
9695   R> OVER - 0 MAX SPACES TYPE
9696 ;
9697     \
9698
9699 CODE 20_US                      \ n --      n * 20 us
9700 BEGIN                           \ 3 cycles loop + 6~  
9701 \    MOV     #5,W                \ 3 MCLK = 1 MHz
9702 \    MOV     #23,W               \ 3 MCLK = 4 MHz
9703     MOV     #51,W               \ 3 MCLK = 8 MHz
9704 \    MOV     #104,W              \ 3 MCLK = 16 MHz
9705 \    MOV     #158,W              \ 3 MCLK = 24 MHz
9706     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
9707         SUB #1,W                \ 1
9708     0= UNTIL                    \ 2
9709     SUB     #1,TOS              \ 1
9710 0= UNTIL                        \ 2
9711     MOV     @PSP+,TOS           \ 2
9712     MOV     @IP+,PC             \ 4
9713 ENDCODE
9714     \
9715
9716 CODE TOP_LCD                    \ LCD Sample
9717 \                               \ if write : %xxxxWWWW --
9718 \                               \ if read  : -- %0000RRRR
9719     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
9720     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
9721 0= IF                           \ write LCD bits pattern
9722     AND.B #LCD_DB,TOS           \ 
9723     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
9724     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
9725     MOV @PSP+,TOS               \
9726     MOV @IP+,PC
9727 THEN                            \ read LCD bits pattern
9728     SUB #2,PSP
9729     MOV TOS,0(PSP)
9730     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
9731     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
9732     AND.B #LCD_DB,TOS           \
9733     MOV @IP+,PC
9734 ENDCODE
9735     \
9736
9737 CODE LCD_W                      \ byte --       write byte to LCD 
9738     SUB #2,PSP                  \
9739     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
9740     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
9741     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
9742     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
9743 COLON                           \ high level word starts here 
9744     TOP_LCD 2 20_US             \ write high nibble first
9745     TOP_LCD 2 20_US 
9746 ;
9747     \
9748
9749 CODE LCD_WrC                    \ char --         Write Char
9750     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
9751     JMP LCD_W 
9752 ENDCODE
9753     \
9754
9755 CODE LCD_WrF                    \ func --         Write Fonction
9756     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
9757     JMP LCD_W 
9758 ENDCODE
9759     \
9760
9761 : LCD_Clear 
9762     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
9763 ;
9764     \
9765
9766 : LCD_Home 
9767     $02 LCD_WrF 100 20_us 
9768 ;
9769     \
9770
9771 \ : LCD_Entry_set       $04 OR LCD_WrF ;
9772
9773 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
9774
9775 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
9776
9777 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
9778
9779 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
9780
9781 \ : LCD_Goto            $80 OR LCD_WrF ;
9782
9783 \ CODE LCD_R                      \ -- byte       read byte from LCD
9784 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
9785 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
9786 \ COLON                           \ starts a FORTH word
9787 \     TOP_LCD 2 20_us             \ -- %0000HHHH
9788 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
9789 \ HI2LO                           \ switch from FORTH to assembler
9790 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
9791 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
9792 \     MOV @RSP+,IP                \ restore IP saved by COLON
9793 \     MOV @IP+,PC                 \
9794 \ ENDCODE
9795 \     \
9796
9797 \ CODE LCD_RdS                    \ -- status       Read Status
9798 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
9799 \     JMP LCD_R
9800 \ ENDCODE
9801 \     \
9802
9803 \ CODE LCD_RdC                    \ -- char         Read Char
9804 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
9805 \     JMP LCD_R
9806 \ ENDCODE
9807 \     \
9808
9809 \ -------------+------+------+------+------++---+---+---+---+---------+
9810 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
9811 \ -------------+------+------+------+------++---+---+---+---+---------+
9812 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
9813 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
9814 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
9815 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
9816 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
9817 \ -------------+------+------+------+------++---+---+---+---+---------+
9818
9819
9820 \ ******************************\
9821 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
9822 \ ******************************\
9823 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
9824 \ ------------------------------\
9825 \ define LPM mode for ACCEPT    \
9826 \ ------------------------------\
9827 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
9828 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
9829 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
9830 BIT.B #SW2,&SW2_IN              \ test switch S2
9831 0= IF                           \ case of switch S2 pressed
9832     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
9833     U< IF
9834         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
9835     THEN
9836 ELSE
9837     BIT.B #SW1,&SW1_IN          \ test switch S1 input
9838     0= IF                       \ case of Switch S1 pressed
9839         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
9840         U>= IF                  \
9841             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
9842         THEN                    \
9843     THEN                        \
9844 THEN                            \
9845 RETI                            \ CPU is ON, GIE is OFF
9846 ENDASM                          \
9847     \
9848
9849
9850 \ ------------------------------\
9851 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
9852 \ ******************************\
9853 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
9854 \ ******************************\
9855 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
9856 \                               \       SMclock = 8|16|24 MHz
9857 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
9858 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
9859 \                               \       SR(9)=new Toggle bit memory (ADD on)
9860 \ ------------------------------\
9861 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
9862 \ ------------------------------\
9863 \ define LPM mode for ACCEPT    \
9864 \ ------------------------------\
9865 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
9866 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
9867 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
9868 \ ------------------------------\
9869 \ RC5_FirstStartBitHalfCycle:   \
9870 \ ------------------------------\
9871 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
9872 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
9873 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
9874 MOV     #1778,X                 \ RC5_Period in us
9875 MOV     #14,W                   \ count of loop
9876 BEGIN                           \
9877 \ ------------------------------\
9878 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
9879 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
9880     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
9881 \ RC5_Compute_3/4_Period:       \                   |
9882     RRUM    #1,X                \ X=1/2 cycle       |
9883     MOV     X,Y                 \ Y=1/2             ^
9884     RRUM    #1,Y                \ Y=1/4
9885     ADD     X,Y                 \ Y=3/4
9886 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
9887     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
9888     0= UNTIL                    \
9889 \ ------------------------------\
9890 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
9891 \ ------------------------------\
9892     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
9893     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
9894     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
9895     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
9896     SUB     #1,W                \ decrement count loop
9897 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
9898 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
9899 0<> WHILE                       \ ----> out of loop ----+
9900 \ RC5_compute_7/4_Time_out:     \                       |
9901     ADD     X,Y                 \                       |   out of bound = 7/4 period 
9902 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
9903     BEGIN                       \                       |
9904         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
9905         0>= IF                  \                       |   if cycle time out of bound
9906             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
9907             RETI                \                       |   then quit to do nothing
9908         THEN                    \                       |
9909 \ ------------------------------\                       |
9910         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
9911     0<> UNTIL                   \                   |   |
9912     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
9913 REPEAT                          \ ----> loop back --+   |
9914 \ ------------------------------\                       |
9915 \ RC5_SampleEndOf:              \ <---------------------+
9916 \ ------------------------------\
9917 BIC     #$30,&TA0CTL           \ stop timer_A0
9918 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
9919 \ ******************************\
9920 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
9921 \ ******************************\
9922 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
9923 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
9924 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
9925 BIT     #BIT13,X                \ X(13) = New_RC5_command
9926 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
9927 THEN                            \
9928 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
9929 \ ******************************\
9930 \ RC5_ComputeNewRC5word         \
9931 \ ******************************\
9932 SUB     #4,PSP                  \
9933 MOV     &BASE,2(PSP)            \ save variable BASE before use
9934 MOV     TOS,0(PSP)              \ save TOS before use
9935 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
9936 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
9937 \ ******************************\
9938 \ RC5_ComputeC6bit              \
9939 \ ******************************\
9940 BIT     #$4000,IP              \ test /C6 bit in IP
9941 0= IF   BIS #$40,TOS           \ set C6 bit in S
9942 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
9943 \ ******************************\
9944 \ RC5_CommandByteIsDone         \ RC5_code --
9945 \ ******************************\
9946
9947 \ ------------------------------\
9948 \ Display IR_RC5 code           \
9949 \ ------------------------------\
9950 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
9951 \ ------------------------------\
9952 LO2HI                           \ switch from assembler to FORTH
9953     ['] LCD_CLEAR IS CR         \ redirects CR
9954     ['] LCD_WrC  IS EMIT        \ redirects EMIT
9955     $10 BASE !                 \ change BASE to hexadecimal
9956     CR ." $" 2 U.R             \ print IR_RC5 code
9957     ['] (CR) IS CR              \ restore CR
9958     ['] (EMIT) IS EMIT          \ restore EMIT
9959 HI2LO                           \ switch from FORTH to assembler
9960 \ ------------------------------\
9961 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
9962 \ ------------------------------\
9963 MOV @PSP+,&BASE                 \ restore variable BASE
9964 RETI                            \ CPU is ON, GIE is OFF
9965 ENDASM                          \
9966     \ 
9967
9968 CODE START                      \
9969 \ ------------------------------\
9970 \ TB0CTL = %0000 0010 1001 0100\$3C0
9971 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
9972 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
9973 \                      --       \ID input divider \ 10 = /4
9974 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
9975 \                            -  \TBCLR TimerB Clear
9976 \                             - \TBIE
9977 \                              -\TBIFG
9978 \ --------------------------------\\
9979 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
9980 \              --                 \CM Capture Mode
9981 \                --               \CCIS
9982 \                   -             \SCS
9983 \                    --           \CLLD
9984 \                      -          \CAP
9985 \                        ---      \OUTMOD \ 011 = set/reset
9986 \                           -     \CCIE
9987 \                             -   \CCI
9988 \                              -  \OUT
9989 \                               - \COV
9990 \                                -\CCIFG
9991 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
9992 \ TB0EX0                          \$3E0 
9993 \ ------------------------------\
9994 \ set TimerB to make 50kHz PWM  \
9995 \ ------------------------------\
9996 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
9997 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
9998 \ ------------------------------\
9999 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
10000 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
10001 \ ------------------------------\
10002     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
10003     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
10004 \ ------------------------------\
10005 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
10006 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
10007 \ ------------------------------\
10008 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
10009 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
10010 \ ------------------------------\
10011     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
10012 \ ------------------------------\
10013 \ set TimerB to generate PWM for LCD_Vo
10014 \ ------------------------------\
10015     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
10016 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
10017     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
10018 \ ------------------------------\
10019     BIS.B #LCDVo,&LCDVo_DIR     \
10020     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
10021 \ ------------------------------\
10022     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
10023     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
10024 \ ------------------------------\
10025     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
10026     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
10027 \ ------------------------------\
10028 \ WDT interval init part        \
10029 \ ------------------------------\
10030     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
10031 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
10032 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
10033     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
10034 \ ------------------------------\
10035 \ init RC5_Int                  \
10036 \ ------------------------------\
10037     BIS.B #RC5,&IR_IE           \ enable RC5_Int
10038     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
10039 \ ------------------------------\
10040 \ init interrupt vectors
10041 \ ------------------------------\
10042     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
10043     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
10044 \ ------------------------------\
10045 \ define LPM mode for ACCEPT    \
10046 \ ------------------------------\
10047 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
10048 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
10049 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
10050
10051 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
10052
10053 \ ------------------------------\
10054 \ Init LCD 2x20                 \
10055 \ ------------------------------\
10056     $03E8 20_US                \ 1-  wait 20 ms
10057     $03 TOP_LCD                \ 2- send DB5=DB4=1
10058     $CD 20_US                  \ 3- wait 4,1 ms
10059     $03 TOP_LCD                \ 4- send again DB5=DB4=1
10060     $5 20_US                   \ 5- wait 0,1 ms
10061     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
10062     $2 20_US                   \    wait 40 us = LCD cycle
10063     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
10064     $2 20_US                   \    wait 40 us = LCD cycle
10065     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
10066     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
10067     LCD_Clear                   \ 10- "LCD_Clear"
10068     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
10069     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
10070     LCD_Clear                   \ 10- "LCD_Clear"
10071     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
10072     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
10073     CR ." I love you"   
10074     ['] (CR) IS CR              \ ' (CR) is CR
10075     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
10076     CR
10077     ."    RC5toLCD is running. Type STOP to quit"
10078 \    NOECHO                      \ uncomment to run this app without terminal connexion
10079     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
10080     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
10081 ;
10082     \
10083
10084 : STOP                  \ stops multitasking, must to be used before downloading app
10085     ['] (WARM) IS WARM  \ remove START app from FORTH init process
10086     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
10087 ;
10088     \
10089
10090
10091 RST_STATE   ;
10092
10093
10094 CODE MAX    \    n1 n2 -- n3       signed maximum
10095             CMP     @PSP,TOS    \ n2-n1
10096             S<      ?GOTO FW1   \ n2<n1
10097 BW1         ADD     #2,PSP
10098             MOV     @IP+,PC
10099 ENDCODE
10100     \
10101
10102 CODE MIN    \    n1 n2 -- n3       signed minimum
10103             CMP     @PSP,TOS     \ n2-n1
10104             S<      ?GOTO BW1    \ n2<n1
10105 FW1         MOV     @PSP+,TOS
10106             MOV     @IP+,PC
10107 ENDCODE
10108     \
10109
10110 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
10111   >R  <# 0 # #S #>  
10112   R> OVER - 0 MAX SPACES TYPE
10113 ;
10114     \
10115
10116 CODE 20_US                      \ n --      n * 20 us
10117 BEGIN                           \ 3 cycles loop + 6~  
10118 \    MOV     #5,W                \ 3 MCLK = 1 MHz
10119 \    MOV     #23,W               \ 3 MCLK = 4 MHz
10120     MOV     #51,W               \ 3 MCLK = 8 MHz
10121 \    MOV     #104,W              \ 3 MCLK = 16 MHz
10122 \    MOV     #158,W              \ 3 MCLK = 24 MHz
10123     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
10124         SUB #1,W                \ 1
10125     0= UNTIL                    \ 2
10126     SUB     #1,TOS              \ 1
10127 0= UNTIL                        \ 2
10128     MOV     @PSP+,TOS           \ 2
10129     MOV     @IP+,PC             \ 4
10130 ENDCODE
10131     \
10132
10133 CODE TOP_LCD                    \ LCD Sample
10134 \                               \ if write : %xxxxWWWW --
10135 \                               \ if read  : -- %0000RRRR
10136     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
10137     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
10138 0= IF                           \ write LCD bits pattern
10139     AND.B #LCD_DB,TOS           \ 
10140     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
10141     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
10142     MOV @PSP+,TOS               \
10143     MOV @IP+,PC
10144 THEN                            \ read LCD bits pattern
10145     SUB #2,PSP
10146     MOV TOS,0(PSP)
10147     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
10148     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
10149     AND.B #LCD_DB,TOS           \
10150     MOV @IP+,PC
10151 ENDCODE
10152     \
10153
10154 CODE LCD_W                      \ byte --       write byte to LCD 
10155     SUB #2,PSP                  \
10156     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
10157     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
10158     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
10159     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
10160 COLON                           \ high level word starts here 
10161     TOP_LCD 2 20_US             \ write high nibble first
10162     TOP_LCD 2 20_US 
10163 ;
10164     \
10165
10166 CODE LCD_WrC                    \ char --         Write Char
10167     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
10168     JMP LCD_W 
10169 ENDCODE
10170     \
10171
10172 CODE LCD_WrF                    \ func --         Write Fonction
10173     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
10174     JMP LCD_W 
10175 ENDCODE
10176     \
10177
10178 : LCD_Clear 
10179     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
10180 ;
10181     \
10182
10183 : LCD_Home 
10184     $02 LCD_WrF 100 20_us 
10185 ;
10186     \
10187
10188 \ : LCD_Entry_set       $04 OR LCD_WrF ;
10189
10190 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
10191
10192 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
10193
10194 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
10195
10196 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
10197
10198 \ : LCD_Goto            $80 OR LCD_WrF ;
10199
10200 \ CODE LCD_R                      \ -- byte       read byte from LCD
10201 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
10202 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
10203 \ COLON                           \ starts a FORTH word
10204 \     TOP_LCD 2 20_us             \ -- %0000HHHH
10205 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
10206 \ HI2LO                           \ switch from FORTH to assembler
10207 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
10208 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
10209 \     MOV @RSP+,IP                \ restore IP saved by COLON
10210 \     MOV @IP+,PC                 \
10211 \ ENDCODE
10212 \     \
10213
10214 \ CODE LCD_RdS                    \ -- status       Read Status
10215 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
10216 \     JMP LCD_R
10217 \ ENDCODE
10218 \     \
10219
10220 \ CODE LCD_RdC                    \ -- char         Read Char
10221 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
10222 \     JMP LCD_R
10223 \ ENDCODE
10224 \     \
10225
10226 \ -------------+------+------+------+------++---+---+---+---+---------+
10227 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
10228 \ -------------+------+------+------+------++---+---+---+---+---------+
10229 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
10230 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
10231 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
10232 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
10233 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
10234 \ -------------+------+------+------+------++---+---+---+---+---------+
10235
10236
10237 \ ******************************\
10238 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
10239 \ ******************************\
10240 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
10241 \ ------------------------------\
10242 \ define LPM mode for ACCEPT    \
10243 \ ------------------------------\
10244 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
10245 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
10246 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
10247 BIT.B #SW2,&SW2_IN              \ test switch S2
10248 0= IF                           \ case of switch S2 pressed
10249     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
10250     U< IF
10251         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
10252     THEN
10253 ELSE
10254     BIT.B #SW1,&SW1_IN          \ test switch S1 input
10255     0= IF                       \ case of Switch S1 pressed
10256         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
10257         U>= IF                  \
10258             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
10259         THEN                    \
10260     THEN                        \
10261 THEN                            \
10262 RETI                            \ CPU is ON, GIE is OFF
10263 ENDASM                          \
10264     \
10265
10266
10267 \ ------------------------------\
10268 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
10269 \ ******************************\
10270 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
10271 \ ******************************\
10272 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
10273 \                               \       SMclock = 8|16|24 MHz
10274 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
10275 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
10276 \                               \       SR(9)=new Toggle bit memory (ADD on)
10277 \ ------------------------------\
10278 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
10279 \ ------------------------------\
10280 \ define LPM mode for ACCEPT    \
10281 \ ------------------------------\
10282 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
10283 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
10284 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
10285 \ ------------------------------\
10286 \ RC5_FirstStartBitHalfCycle:   \
10287 \ ------------------------------\
10288 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
10289 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
10290 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
10291 MOV     #1778,X                 \ RC5_Period in us
10292 MOV     #14,W                   \ count of loop
10293 BEGIN                           \
10294 \ ------------------------------\
10295 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
10296 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
10297     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
10298 \ RC5_Compute_3/4_Period:       \                   |
10299     RRUM    #1,X                \ X=1/2 cycle       |
10300     MOV     X,Y                 \ Y=1/2             ^
10301     RRUM    #1,Y                \ Y=1/4
10302     ADD     X,Y                 \ Y=3/4
10303 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
10304     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
10305     0= UNTIL                    \
10306 \ ------------------------------\
10307 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
10308 \ ------------------------------\
10309     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
10310     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
10311     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
10312     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
10313     SUB     #1,W                \ decrement count loop
10314 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
10315 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
10316 0<> WHILE                       \ ----> out of loop ----+
10317 \ RC5_compute_7/4_Time_out:     \                       |
10318     ADD     X,Y                 \                       |   out of bound = 7/4 period 
10319 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
10320     BEGIN                       \                       |
10321         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
10322         0>= IF                  \                       |   if cycle time out of bound
10323             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
10324             RETI                \                       |   then quit to do nothing
10325         THEN                    \                       |
10326 \ ------------------------------\                       |
10327         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
10328     0<> UNTIL                   \                   |   |
10329     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
10330 REPEAT                          \ ----> loop back --+   |
10331 \ ------------------------------\                       |
10332 \ RC5_SampleEndOf:              \ <---------------------+
10333 \ ------------------------------\
10334 BIC     #$30,&TA0CTL           \ stop timer_A0
10335 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
10336 \ ******************************\
10337 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
10338 \ ******************************\
10339 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
10340 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
10341 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
10342 BIT     #BIT13,X                \ X(13) = New_RC5_command
10343 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
10344 THEN                            \
10345 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
10346 \ ******************************\
10347 \ RC5_ComputeNewRC5word         \
10348 \ ******************************\
10349 SUB     #4,PSP                  \
10350 MOV     &BASE,2(PSP)            \ save variable BASE before use
10351 MOV     TOS,0(PSP)              \ save TOS before use
10352 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
10353 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
10354 \ ******************************\
10355 \ RC5_ComputeC6bit              \
10356 \ ******************************\
10357 BIT     #$4000,IP              \ test /C6 bit in IP
10358 0= IF   BIS #$40,TOS           \ set C6 bit in S
10359 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
10360 \ ******************************\
10361 \ RC5_CommandByteIsDone         \ RC5_code --
10362 \ ******************************\
10363
10364 \ ------------------------------\
10365 \ Display IR_RC5 code           \
10366 \ ------------------------------\
10367 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
10368 \ ------------------------------\
10369 LO2HI                           \ switch from assembler to FORTH
10370     ['] LCD_CLEAR IS CR         \ redirects CR
10371     ['] LCD_WrC  IS EMIT        \ redirects EMIT
10372     $10 BASE !                 \ change BASE to hexadecimal
10373     CR ." $" 2 U.R             \ print IR_RC5 code
10374     ['] (CR) IS CR              \ restore CR
10375     ['] (EMIT) IS EMIT          \ restore EMIT
10376 HI2LO                           \ switch from FORTH to assembler
10377 \ ------------------------------\
10378 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
10379 \ ------------------------------\
10380 MOV @PSP+,&BASE                 \ restore variable BASE
10381 RETI                            \ CPU is ON, GIE is OFF
10382 ENDASM                          \
10383     \ 
10384
10385 CODE START                      \
10386 \ ------------------------------\
10387 \ TB0CTL = %0000 0010 1001 0100\$3C0
10388 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
10389 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
10390 \                      --       \ID input divider \ 10 = /4
10391 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
10392 \                            -  \TBCLR TimerB Clear
10393 \                             - \TBIE
10394 \                              -\TBIFG
10395 \ --------------------------------\\
10396 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
10397 \              --                 \CM Capture Mode
10398 \                --               \CCIS
10399 \                   -             \SCS
10400 \                    --           \CLLD
10401 \                      -          \CAP
10402 \                        ---      \OUTMOD \ 011 = set/reset
10403 \                           -     \CCIE
10404 \                             -   \CCI
10405 \                              -  \OUT
10406 \                               - \COV
10407 \                                -\CCIFG
10408 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
10409 \ TB0EX0                          \$3E0 
10410 \ ------------------------------\
10411 \ set TimerB to make 50kHz PWM  \
10412 \ ------------------------------\
10413 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
10414 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
10415 \ ------------------------------\
10416 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
10417 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
10418 \ ------------------------------\
10419     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
10420     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
10421 \ ------------------------------\
10422 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
10423 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
10424 \ ------------------------------\
10425 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
10426 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
10427 \ ------------------------------\
10428     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
10429 \ ------------------------------\
10430 \ set TimerB to generate PWM for LCD_Vo
10431 \ ------------------------------\
10432     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
10433 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
10434     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
10435 \ ------------------------------\
10436     BIS.B #LCDVo,&LCDVo_DIR     \
10437     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
10438 \ ------------------------------\
10439     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
10440     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
10441 \ ------------------------------\
10442     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
10443     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
10444 \ ------------------------------\
10445 \ WDT interval init part        \
10446 \ ------------------------------\
10447     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
10448 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
10449 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
10450     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
10451 \ ------------------------------\
10452 \ init RC5_Int                  \
10453 \ ------------------------------\
10454     BIS.B #RC5,&IR_IE           \ enable RC5_Int
10455     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
10456 \ ------------------------------\
10457 \ init interrupt vectors
10458 \ ------------------------------\
10459     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
10460     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
10461 \ ------------------------------\
10462 \ define LPM mode for ACCEPT    \
10463 \ ------------------------------\
10464 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
10465 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
10466 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
10467
10468 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
10469
10470 \ ------------------------------\
10471 \ Init LCD 2x20                 \
10472 \ ------------------------------\
10473     $03E8 20_US                \ 1-  wait 20 ms
10474     $03 TOP_LCD                \ 2- send DB5=DB4=1
10475     $CD 20_US                  \ 3- wait 4,1 ms
10476     $03 TOP_LCD                \ 4- send again DB5=DB4=1
10477     $5 20_US                   \ 5- wait 0,1 ms
10478     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
10479     $2 20_US                   \    wait 40 us = LCD cycle
10480     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
10481     $2 20_US                   \    wait 40 us = LCD cycle
10482     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
10483     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
10484     LCD_Clear                   \ 10- "LCD_Clear"
10485     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
10486     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
10487     LCD_Clear                   \ 10- "LCD_Clear"
10488     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
10489     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
10490     CR ." I love you"   
10491     ['] (CR) IS CR              \ ' (CR) is CR
10492     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
10493     CR
10494     ."    RC5toLCD is running. Type STOP to quit"
10495 \    NOECHO                      \ uncomment to run this app without terminal connexion
10496     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
10497     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
10498 ;
10499     \
10500
10501 : STOP                  \ stops multitasking, must to be used before downloading app
10502     ['] (WARM) IS WARM  \ remove START app from FORTH init process
10503     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
10504 ;
10505     \
10506
10507
10508 RST_STATE   ;
10509
10510
10511 CODE MAX    \    n1 n2 -- n3       signed maximum
10512             CMP     @PSP,TOS    \ n2-n1
10513             S<      ?GOTO FW1   \ n2<n1
10514 BW1         ADD     #2,PSP
10515             MOV     @IP+,PC
10516 ENDCODE
10517     \
10518
10519 CODE MIN    \    n1 n2 -- n3       signed minimum
10520             CMP     @PSP,TOS     \ n2-n1
10521             S<      ?GOTO BW1    \ n2<n1
10522 FW1         MOV     @PSP+,TOS
10523             MOV     @IP+,PC
10524 ENDCODE
10525     \
10526
10527 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
10528   >R  <# 0 # #S #>  
10529   R> OVER - 0 MAX SPACES TYPE
10530 ;
10531     \
10532
10533 CODE 20_US                      \ n --      n * 20 us
10534 BEGIN                           \ 3 cycles loop + 6~  
10535 \    MOV     #5,W                \ 3 MCLK = 1 MHz
10536 \    MOV     #23,W               \ 3 MCLK = 4 MHz
10537     MOV     #51,W               \ 3 MCLK = 8 MHz
10538 \    MOV     #104,W              \ 3 MCLK = 16 MHz
10539 \    MOV     #158,W              \ 3 MCLK = 24 MHz
10540     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
10541         SUB #1,W                \ 1
10542     0= UNTIL                    \ 2
10543     SUB     #1,TOS              \ 1
10544 0= UNTIL                        \ 2
10545     MOV     @PSP+,TOS           \ 2
10546     MOV     @IP+,PC             \ 4
10547 ENDCODE
10548     \
10549
10550 CODE TOP_LCD                    \ LCD Sample
10551 \                               \ if write : %xxxxWWWW --
10552 \                               \ if read  : -- %0000RRRR
10553     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
10554     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
10555 0= IF                           \ write LCD bits pattern
10556     AND.B #LCD_DB,TOS           \ 
10557     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
10558     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
10559     MOV @PSP+,TOS               \
10560     MOV @IP+,PC
10561 THEN                            \ read LCD bits pattern
10562     SUB #2,PSP
10563     MOV TOS,0(PSP)
10564     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
10565     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
10566     AND.B #LCD_DB,TOS           \
10567     MOV @IP+,PC
10568 ENDCODE
10569     \
10570
10571 CODE LCD_W                      \ byte --       write byte to LCD 
10572     SUB #2,PSP                  \
10573     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
10574     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
10575     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
10576     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
10577 COLON                           \ high level word starts here 
10578     TOP_LCD 2 20_US             \ write high nibble first
10579     TOP_LCD 2 20_US 
10580 ;
10581     \
10582
10583 CODE LCD_WrC                    \ char --         Write Char
10584     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
10585     JMP LCD_W 
10586 ENDCODE
10587     \
10588
10589 CODE LCD_WrF                    \ func --         Write Fonction
10590     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
10591     JMP LCD_W 
10592 ENDCODE
10593     \
10594
10595 : LCD_Clear 
10596     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
10597 ;
10598     \
10599
10600 : LCD_Home 
10601     $02 LCD_WrF 100 20_us 
10602 ;
10603     \
10604
10605 \ : LCD_Entry_set       $04 OR LCD_WrF ;
10606
10607 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
10608
10609 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
10610
10611 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
10612
10613 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
10614
10615 \ : LCD_Goto            $80 OR LCD_WrF ;
10616
10617 \ CODE LCD_R                      \ -- byte       read byte from LCD
10618 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
10619 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
10620 \ COLON                           \ starts a FORTH word
10621 \     TOP_LCD 2 20_us             \ -- %0000HHHH
10622 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
10623 \ HI2LO                           \ switch from FORTH to assembler
10624 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
10625 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
10626 \     MOV @RSP+,IP                \ restore IP saved by COLON
10627 \     MOV @IP+,PC                 \
10628 \ ENDCODE
10629 \     \
10630
10631 \ CODE LCD_RdS                    \ -- status       Read Status
10632 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
10633 \     JMP LCD_R
10634 \ ENDCODE
10635 \     \
10636
10637 \ CODE LCD_RdC                    \ -- char         Read Char
10638 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
10639 \     JMP LCD_R
10640 \ ENDCODE
10641 \     \
10642
10643 \ -------------+------+------+------+------++---+---+---+---+---------+
10644 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
10645 \ -------------+------+------+------+------++---+---+---+---+---------+
10646 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
10647 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
10648 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
10649 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
10650 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
10651 \ -------------+------+------+------+------++---+---+---+---+---------+
10652
10653
10654 \ ******************************\
10655 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
10656 \ ******************************\
10657 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
10658 \ ------------------------------\
10659 \ define LPM mode for ACCEPT    \
10660 \ ------------------------------\
10661 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
10662 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
10663 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
10664 BIT.B #SW2,&SW2_IN              \ test switch S2
10665 0= IF                           \ case of switch S2 pressed
10666     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
10667     U< IF
10668         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
10669     THEN
10670 ELSE
10671     BIT.B #SW1,&SW1_IN          \ test switch S1 input
10672     0= IF                       \ case of Switch S1 pressed
10673         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
10674         U>= IF                  \
10675             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
10676         THEN                    \
10677     THEN                        \
10678 THEN                            \
10679 RETI                            \ CPU is ON, GIE is OFF
10680 ENDASM                          \
10681     \
10682
10683
10684 \ ------------------------------\
10685 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
10686 \ ******************************\
10687 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
10688 \ ******************************\
10689 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
10690 \                               \       SMclock = 8|16|24 MHz
10691 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
10692 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
10693 \                               \       SR(9)=new Toggle bit memory (ADD on)
10694 \ ------------------------------\
10695 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
10696 \ ------------------------------\
10697 \ define LPM mode for ACCEPT    \
10698 \ ------------------------------\
10699 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
10700 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
10701 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
10702 \ ------------------------------\
10703 \ RC5_FirstStartBitHalfCycle:   \
10704 \ ------------------------------\
10705 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
10706 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
10707 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
10708 MOV     #1778,X                 \ RC5_Period in us
10709 MOV     #14,W                   \ count of loop
10710 BEGIN                           \
10711 \ ------------------------------\
10712 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
10713 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
10714     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
10715 \ RC5_Compute_3/4_Period:       \                   |
10716     RRUM    #1,X                \ X=1/2 cycle       |
10717     MOV     X,Y                 \ Y=1/2             ^
10718     RRUM    #1,Y                \ Y=1/4
10719     ADD     X,Y                 \ Y=3/4
10720 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
10721     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
10722     0= UNTIL                    \
10723 \ ------------------------------\
10724 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
10725 \ ------------------------------\
10726     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
10727     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
10728     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
10729     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
10730     SUB     #1,W                \ decrement count loop
10731 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
10732 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
10733 0<> WHILE                       \ ----> out of loop ----+
10734 \ RC5_compute_7/4_Time_out:     \                       |
10735     ADD     X,Y                 \                       |   out of bound = 7/4 period 
10736 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
10737     BEGIN                       \                       |
10738         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
10739         0>= IF                  \                       |   if cycle time out of bound
10740             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
10741             RETI                \                       |   then quit to do nothing
10742         THEN                    \                       |
10743 \ ------------------------------\                       |
10744         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
10745     0<> UNTIL                   \                   |   |
10746     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
10747 REPEAT                          \ ----> loop back --+   |
10748 \ ------------------------------\                       |
10749 \ RC5_SampleEndOf:              \ <---------------------+
10750 \ ------------------------------\
10751 BIC     #$30,&TA0CTL           \ stop timer_A0
10752 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
10753 \ ******************************\
10754 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
10755 \ ******************************\
10756 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
10757 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
10758 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
10759 BIT     #BIT13,X                \ X(13) = New_RC5_command
10760 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
10761 THEN                            \
10762 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
10763 \ ******************************\
10764 \ RC5_ComputeNewRC5word         \
10765 \ ******************************\
10766 SUB     #4,PSP                  \
10767 MOV     &BASE,2(PSP)            \ save variable BASE before use
10768 MOV     TOS,0(PSP)              \ save TOS before use
10769 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
10770 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
10771 \ ******************************\
10772 \ RC5_ComputeC6bit              \
10773 \ ******************************\
10774 BIT     #$4000,IP              \ test /C6 bit in IP
10775 0= IF   BIS #$40,TOS           \ set C6 bit in S
10776 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
10777 \ ******************************\
10778 \ RC5_CommandByteIsDone         \ RC5_code --
10779 \ ******************************\
10780
10781 \ ------------------------------\
10782 \ Display IR_RC5 code           \
10783 \ ------------------------------\
10784 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
10785 \ ------------------------------\
10786 LO2HI                           \ switch from assembler to FORTH
10787     ['] LCD_CLEAR IS CR         \ redirects CR
10788     ['] LCD_WrC  IS EMIT        \ redirects EMIT
10789     $10 BASE !                 \ change BASE to hexadecimal
10790     CR ." $" 2 U.R             \ print IR_RC5 code
10791     ['] (CR) IS CR              \ restore CR
10792     ['] (EMIT) IS EMIT          \ restore EMIT
10793 HI2LO                           \ switch from FORTH to assembler
10794 \ ------------------------------\
10795 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
10796 \ ------------------------------\
10797 MOV @PSP+,&BASE                 \ restore variable BASE
10798 RETI                            \ CPU is ON, GIE is OFF
10799 ENDASM                          \
10800     \ 
10801
10802 CODE START                      \
10803 \ ------------------------------\
10804 \ TB0CTL = %0000 0010 1001 0100\$3C0
10805 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
10806 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
10807 \                      --       \ID input divider \ 10 = /4
10808 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
10809 \                            -  \TBCLR TimerB Clear
10810 \                             - \TBIE
10811 \                              -\TBIFG
10812 \ --------------------------------\\
10813 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
10814 \              --                 \CM Capture Mode
10815 \                --               \CCIS
10816 \                   -             \SCS
10817 \                    --           \CLLD
10818 \                      -          \CAP
10819 \                        ---      \OUTMOD \ 011 = set/reset
10820 \                           -     \CCIE
10821 \                             -   \CCI
10822 \                              -  \OUT
10823 \                               - \COV
10824 \                                -\CCIFG
10825 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
10826 \ TB0EX0                          \$3E0 
10827 \ ------------------------------\
10828 \ set TimerB to make 50kHz PWM  \
10829 \ ------------------------------\
10830 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
10831 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
10832 \ ------------------------------\
10833 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
10834 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
10835 \ ------------------------------\
10836     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
10837     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
10838 \ ------------------------------\
10839 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
10840 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
10841 \ ------------------------------\
10842 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
10843 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
10844 \ ------------------------------\
10845     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
10846 \ ------------------------------\
10847 \ set TimerB to generate PWM for LCD_Vo
10848 \ ------------------------------\
10849     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
10850 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
10851     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
10852 \ ------------------------------\
10853     BIS.B #LCDVo,&LCDVo_DIR     \
10854     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
10855 \ ------------------------------\
10856     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
10857     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
10858 \ ------------------------------\
10859     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
10860     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
10861 \ ------------------------------\
10862 \ WDT interval init part        \
10863 \ ------------------------------\
10864     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
10865 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
10866 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
10867     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
10868 \ ------------------------------\
10869 \ init RC5_Int                  \
10870 \ ------------------------------\
10871     BIS.B #RC5,&IR_IE           \ enable RC5_Int
10872     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
10873 \ ------------------------------\
10874 \ init interrupt vectors
10875 \ ------------------------------\
10876     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
10877     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
10878 \ ------------------------------\
10879 \ define LPM mode for ACCEPT    \
10880 \ ------------------------------\
10881 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
10882 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
10883 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
10884
10885 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
10886
10887 \ ------------------------------\
10888 \ Init LCD 2x20                 \
10889 \ ------------------------------\
10890     $03E8 20_US                \ 1-  wait 20 ms
10891     $03 TOP_LCD                \ 2- send DB5=DB4=1
10892     $CD 20_US                  \ 3- wait 4,1 ms
10893     $03 TOP_LCD                \ 4- send again DB5=DB4=1
10894     $5 20_US                   \ 5- wait 0,1 ms
10895     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
10896     $2 20_US                   \    wait 40 us = LCD cycle
10897     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
10898     $2 20_US                   \    wait 40 us = LCD cycle
10899     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
10900     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
10901     LCD_Clear                   \ 10- "LCD_Clear"
10902     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
10903     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
10904     LCD_Clear                   \ 10- "LCD_Clear"
10905     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
10906     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
10907     CR ." I love you"   
10908     ['] (CR) IS CR              \ ' (CR) is CR
10909     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
10910     CR
10911     ."    RC5toLCD is running. Type STOP to quit"
10912 \    NOECHO                      \ uncomment to run this app without terminal connexion
10913     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
10914     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
10915 ;
10916     \
10917
10918 : STOP                  \ stops multitasking, must to be used before downloading app
10919     ['] (WARM) IS WARM  \ remove START app from FORTH init process
10920     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
10921 ;
10922     \
10923
10924
10925 RST_STATE   ;
10926
10927
10928 CODE MAX    \    n1 n2 -- n3       signed maximum
10929             CMP     @PSP,TOS    \ n2-n1
10930             S<      ?GOTO FW1   \ n2<n1
10931 BW1         ADD     #2,PSP
10932             MOV     @IP+,PC
10933 ENDCODE
10934     \
10935
10936 CODE MIN    \    n1 n2 -- n3       signed minimum
10937             CMP     @PSP,TOS     \ n2-n1
10938             S<      ?GOTO BW1    \ n2<n1
10939 FW1         MOV     @PSP+,TOS
10940             MOV     @IP+,PC
10941 ENDCODE
10942     \
10943
10944 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
10945   >R  <# 0 # #S #>  
10946   R> OVER - 0 MAX SPACES TYPE
10947 ;
10948     \
10949
10950 CODE 20_US                      \ n --      n * 20 us
10951 BEGIN                           \ 3 cycles loop + 6~  
10952 \    MOV     #5,W                \ 3 MCLK = 1 MHz
10953 \    MOV     #23,W               \ 3 MCLK = 4 MHz
10954     MOV     #51,W               \ 3 MCLK = 8 MHz
10955 \    MOV     #104,W              \ 3 MCLK = 16 MHz
10956 \    MOV     #158,W              \ 3 MCLK = 24 MHz
10957     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
10958         SUB #1,W                \ 1
10959     0= UNTIL                    \ 2
10960     SUB     #1,TOS              \ 1
10961 0= UNTIL                        \ 2
10962     MOV     @PSP+,TOS           \ 2
10963     MOV     @IP+,PC             \ 4
10964 ENDCODE
10965     \
10966
10967 CODE TOP_LCD                    \ LCD Sample
10968 \                               \ if write : %xxxxWWWW --
10969 \                               \ if read  : -- %0000RRRR
10970     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
10971     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
10972 0= IF                           \ write LCD bits pattern
10973     AND.B #LCD_DB,TOS           \ 
10974     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
10975     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
10976     MOV @PSP+,TOS               \
10977     MOV @IP+,PC
10978 THEN                            \ read LCD bits pattern
10979     SUB #2,PSP
10980     MOV TOS,0(PSP)
10981     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
10982     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
10983     AND.B #LCD_DB,TOS           \
10984     MOV @IP+,PC
10985 ENDCODE
10986     \
10987
10988 CODE LCD_W                      \ byte --       write byte to LCD 
10989     SUB #2,PSP                  \
10990     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
10991     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
10992     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
10993     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
10994 COLON                           \ high level word starts here 
10995     TOP_LCD 2 20_US             \ write high nibble first
10996     TOP_LCD 2 20_US 
10997 ;
10998     \
10999
11000 CODE LCD_WrC                    \ char --         Write Char
11001     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
11002     JMP LCD_W 
11003 ENDCODE
11004     \
11005
11006 CODE LCD_WrF                    \ func --         Write Fonction
11007     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
11008     JMP LCD_W 
11009 ENDCODE
11010     \
11011
11012 : LCD_Clear 
11013     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
11014 ;
11015     \
11016
11017 : LCD_Home 
11018     $02 LCD_WrF 100 20_us 
11019 ;
11020     \
11021
11022 \ : LCD_Entry_set       $04 OR LCD_WrF ;
11023
11024 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
11025
11026 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
11027
11028 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
11029
11030 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
11031
11032 \ : LCD_Goto            $80 OR LCD_WrF ;
11033
11034 \ CODE LCD_R                      \ -- byte       read byte from LCD
11035 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
11036 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
11037 \ COLON                           \ starts a FORTH word
11038 \     TOP_LCD 2 20_us             \ -- %0000HHHH
11039 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
11040 \ HI2LO                           \ switch from FORTH to assembler
11041 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
11042 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
11043 \     MOV @RSP+,IP                \ restore IP saved by COLON
11044 \     MOV @IP+,PC                 \
11045 \ ENDCODE
11046 \     \
11047
11048 \ CODE LCD_RdS                    \ -- status       Read Status
11049 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
11050 \     JMP LCD_R
11051 \ ENDCODE
11052 \     \
11053
11054 \ CODE LCD_RdC                    \ -- char         Read Char
11055 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
11056 \     JMP LCD_R
11057 \ ENDCODE
11058 \     \
11059
11060 \ -------------+------+------+------+------++---+---+---+---+---------+
11061 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
11062 \ -------------+------+------+------+------++---+---+---+---+---------+
11063 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
11064 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
11065 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
11066 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
11067 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
11068 \ -------------+------+------+------+------++---+---+---+---+---------+
11069
11070
11071 \ ******************************\
11072 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
11073 \ ******************************\
11074 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
11075 \ ------------------------------\
11076 \ define LPM mode for ACCEPT    \
11077 \ ------------------------------\
11078 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
11079 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
11080 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
11081 BIT.B #SW2,&SW2_IN              \ test switch S2
11082 0= IF                           \ case of switch S2 pressed
11083     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
11084     U< IF
11085         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
11086     THEN
11087 ELSE
11088     BIT.B #SW1,&SW1_IN          \ test switch S1 input
11089     0= IF                       \ case of Switch S1 pressed
11090         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
11091         U>= IF                  \
11092             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
11093         THEN                    \
11094     THEN                        \
11095 THEN                            \
11096 RETI                            \ CPU is ON, GIE is OFF
11097 ENDASM                          \
11098     \
11099
11100
11101 \ ------------------------------\
11102 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
11103 \ ******************************\
11104 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
11105 \ ******************************\
11106 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
11107 \                               \       SMclock = 8|16|24 MHz
11108 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
11109 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
11110 \                               \       SR(9)=new Toggle bit memory (ADD on)
11111 \ ------------------------------\
11112 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
11113 \ ------------------------------\
11114 \ define LPM mode for ACCEPT    \
11115 \ ------------------------------\
11116 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
11117 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
11118 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
11119 \ ------------------------------\
11120 \ RC5_FirstStartBitHalfCycle:   \
11121 \ ------------------------------\
11122 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
11123 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
11124 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
11125 MOV     #1778,X                 \ RC5_Period in us
11126 MOV     #14,W                   \ count of loop
11127 BEGIN                           \
11128 \ ------------------------------\
11129 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
11130 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
11131     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
11132 \ RC5_Compute_3/4_Period:       \                   |
11133     RRUM    #1,X                \ X=1/2 cycle       |
11134     MOV     X,Y                 \ Y=1/2             ^
11135     RRUM    #1,Y                \ Y=1/4
11136     ADD     X,Y                 \ Y=3/4
11137 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
11138     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
11139     0= UNTIL                    \
11140 \ ------------------------------\
11141 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
11142 \ ------------------------------\
11143     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
11144     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
11145     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
11146     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
11147     SUB     #1,W                \ decrement count loop
11148 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
11149 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
11150 0<> WHILE                       \ ----> out of loop ----+
11151 \ RC5_compute_7/4_Time_out:     \                       |
11152     ADD     X,Y                 \                       |   out of bound = 7/4 period 
11153 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
11154     BEGIN                       \                       |
11155         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
11156         0>= IF                  \                       |   if cycle time out of bound
11157             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
11158             RETI                \                       |   then quit to do nothing
11159         THEN                    \                       |
11160 \ ------------------------------\                       |
11161         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
11162     0<> UNTIL                   \                   |   |
11163     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
11164 REPEAT                          \ ----> loop back --+   |
11165 \ ------------------------------\                       |
11166 \ RC5_SampleEndOf:              \ <---------------------+
11167 \ ------------------------------\
11168 BIC     #$30,&TA0CTL           \ stop timer_A0
11169 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
11170 \ ******************************\
11171 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
11172 \ ******************************\
11173 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
11174 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
11175 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
11176 BIT     #BIT13,X                \ X(13) = New_RC5_command
11177 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
11178 THEN                            \
11179 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
11180 \ ******************************\
11181 \ RC5_ComputeNewRC5word         \
11182 \ ******************************\
11183 SUB     #4,PSP                  \
11184 MOV     &BASE,2(PSP)            \ save variable BASE before use
11185 MOV     TOS,0(PSP)              \ save TOS before use
11186 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
11187 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
11188 \ ******************************\
11189 \ RC5_ComputeC6bit              \
11190 \ ******************************\
11191 BIT     #$4000,IP              \ test /C6 bit in IP
11192 0= IF   BIS #$40,TOS           \ set C6 bit in S
11193 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
11194 \ ******************************\
11195 \ RC5_CommandByteIsDone         \ RC5_code --
11196 \ ******************************\
11197
11198 \ ------------------------------\
11199 \ Display IR_RC5 code           \
11200 \ ------------------------------\
11201 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
11202 \ ------------------------------\
11203 LO2HI                           \ switch from assembler to FORTH
11204     ['] LCD_CLEAR IS CR         \ redirects CR
11205     ['] LCD_WrC  IS EMIT        \ redirects EMIT
11206     $10 BASE !                 \ change BASE to hexadecimal
11207     CR ." $" 2 U.R             \ print IR_RC5 code
11208     ['] (CR) IS CR              \ restore CR
11209     ['] (EMIT) IS EMIT          \ restore EMIT
11210 HI2LO                           \ switch from FORTH to assembler
11211 \ ------------------------------\
11212 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
11213 \ ------------------------------\
11214 MOV @PSP+,&BASE                 \ restore variable BASE
11215 RETI                            \ CPU is ON, GIE is OFF
11216 ENDASM                          \
11217     \ 
11218
11219 CODE START                      \
11220 \ ------------------------------\
11221 \ TB0CTL = %0000 0010 1001 0100\$3C0
11222 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
11223 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
11224 \                      --       \ID input divider \ 10 = /4
11225 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
11226 \                            -  \TBCLR TimerB Clear
11227 \                             - \TBIE
11228 \                              -\TBIFG
11229 \ --------------------------------\\
11230 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
11231 \              --                 \CM Capture Mode
11232 \                --               \CCIS
11233 \                   -             \SCS
11234 \                    --           \CLLD
11235 \                      -          \CAP
11236 \                        ---      \OUTMOD \ 011 = set/reset
11237 \                           -     \CCIE
11238 \                             -   \CCI
11239 \                              -  \OUT
11240 \                               - \COV
11241 \                                -\CCIFG
11242 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
11243 \ TB0EX0                          \$3E0 
11244 \ ------------------------------\
11245 \ set TimerB to make 50kHz PWM  \
11246 \ ------------------------------\
11247 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
11248 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
11249 \ ------------------------------\
11250 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
11251 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
11252 \ ------------------------------\
11253     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
11254     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
11255 \ ------------------------------\
11256 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
11257 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
11258 \ ------------------------------\
11259 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
11260 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
11261 \ ------------------------------\
11262     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
11263 \ ------------------------------\
11264 \ set TimerB to generate PWM for LCD_Vo
11265 \ ------------------------------\
11266     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
11267 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
11268     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
11269 \ ------------------------------\
11270     BIS.B #LCDVo,&LCDVo_DIR     \
11271     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
11272 \ ------------------------------\
11273     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
11274     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
11275 \ ------------------------------\
11276     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
11277     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
11278 \ ------------------------------\
11279 \ WDT interval init part        \
11280 \ ------------------------------\
11281     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
11282 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
11283 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
11284     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
11285 \ ------------------------------\
11286 \ init RC5_Int                  \
11287 \ ------------------------------\
11288     BIS.B #RC5,&IR_IE           \ enable RC5_Int
11289     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
11290 \ ------------------------------\
11291 \ init interrupt vectors
11292 \ ------------------------------\
11293     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
11294     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
11295 \ ------------------------------\
11296 \ define LPM mode for ACCEPT    \
11297 \ ------------------------------\
11298 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
11299 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
11300 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
11301
11302 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
11303
11304 \ ------------------------------\
11305 \ Init LCD 2x20                 \
11306 \ ------------------------------\
11307     $03E8 20_US                \ 1-  wait 20 ms
11308     $03 TOP_LCD                \ 2- send DB5=DB4=1
11309     $CD 20_US                  \ 3- wait 4,1 ms
11310     $03 TOP_LCD                \ 4- send again DB5=DB4=1
11311     $5 20_US                   \ 5- wait 0,1 ms
11312     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
11313     $2 20_US                   \    wait 40 us = LCD cycle
11314     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
11315     $2 20_US                   \    wait 40 us = LCD cycle
11316     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
11317     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
11318     LCD_Clear                   \ 10- "LCD_Clear"
11319     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
11320     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
11321     LCD_Clear                   \ 10- "LCD_Clear"
11322     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
11323     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
11324     CR ." I love you"   
11325     ['] (CR) IS CR              \ ' (CR) is CR
11326     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
11327     CR
11328     ."    RC5toLCD is running. Type STOP to quit"
11329 \    NOECHO                      \ uncomment to run this app without terminal connexion
11330     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
11331     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
11332 ;
11333     \
11334
11335 : STOP                  \ stops multitasking, must to be used before downloading app
11336     ['] (WARM) IS WARM  \ remove START app from FORTH init process
11337     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
11338 ;
11339     \
11340
11341
11342 RST_STATE   ;
11343
11344
11345 CODE MAX    \    n1 n2 -- n3       signed maximum
11346             CMP     @PSP,TOS    \ n2-n1
11347             S<      ?GOTO FW1   \ n2<n1
11348 BW1         ADD     #2,PSP
11349             MOV     @IP+,PC
11350 ENDCODE
11351     \
11352
11353 CODE MIN    \    n1 n2 -- n3       signed minimum
11354             CMP     @PSP,TOS     \ n2-n1
11355             S<      ?GOTO BW1    \ n2<n1
11356 FW1         MOV     @PSP+,TOS
11357             MOV     @IP+,PC
11358 ENDCODE
11359     \
11360
11361 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
11362   >R  <# 0 # #S #>  
11363   R> OVER - 0 MAX SPACES TYPE
11364 ;
11365     \
11366
11367 CODE 20_US                      \ n --      n * 20 us
11368 BEGIN                           \ 3 cycles loop + 6~  
11369 \    MOV     #5,W                \ 3 MCLK = 1 MHz
11370 \    MOV     #23,W               \ 3 MCLK = 4 MHz
11371     MOV     #51,W               \ 3 MCLK = 8 MHz
11372 \    MOV     #104,W              \ 3 MCLK = 16 MHz
11373 \    MOV     #158,W              \ 3 MCLK = 24 MHz
11374     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
11375         SUB #1,W                \ 1
11376     0= UNTIL                    \ 2
11377     SUB     #1,TOS              \ 1
11378 0= UNTIL                        \ 2
11379     MOV     @PSP+,TOS           \ 2
11380     MOV     @IP+,PC             \ 4
11381 ENDCODE
11382     \
11383
11384 CODE TOP_LCD                    \ LCD Sample
11385 \                               \ if write : %xxxxWWWW --
11386 \                               \ if read  : -- %0000RRRR
11387     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
11388     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
11389 0= IF                           \ write LCD bits pattern
11390     AND.B #LCD_DB,TOS           \ 
11391     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
11392     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
11393     MOV @PSP+,TOS               \
11394     MOV @IP+,PC
11395 THEN                            \ read LCD bits pattern
11396     SUB #2,PSP
11397     MOV TOS,0(PSP)
11398     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
11399     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
11400     AND.B #LCD_DB,TOS           \
11401     MOV @IP+,PC
11402 ENDCODE
11403     \
11404
11405 CODE LCD_W                      \ byte --       write byte to LCD 
11406     SUB #2,PSP                  \
11407     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
11408     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
11409     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
11410     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
11411 COLON                           \ high level word starts here 
11412     TOP_LCD 2 20_US             \ write high nibble first
11413     TOP_LCD 2 20_US 
11414 ;
11415     \
11416
11417 CODE LCD_WrC                    \ char --         Write Char
11418     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
11419     JMP LCD_W 
11420 ENDCODE
11421     \
11422
11423 CODE LCD_WrF                    \ func --         Write Fonction
11424     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
11425     JMP LCD_W 
11426 ENDCODE
11427     \
11428
11429 : LCD_Clear 
11430     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
11431 ;
11432     \
11433
11434 : LCD_Home 
11435     $02 LCD_WrF 100 20_us 
11436 ;
11437     \
11438
11439 \ : LCD_Entry_set       $04 OR LCD_WrF ;
11440
11441 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
11442
11443 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
11444
11445 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
11446
11447 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
11448
11449 \ : LCD_Goto            $80 OR LCD_WrF ;
11450
11451 \ CODE LCD_R                      \ -- byte       read byte from LCD
11452 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
11453 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
11454 \ COLON                           \ starts a FORTH word
11455 \     TOP_LCD 2 20_us             \ -- %0000HHHH
11456 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
11457 \ HI2LO                           \ switch from FORTH to assembler
11458 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
11459 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
11460 \     MOV @RSP+,IP                \ restore IP saved by COLON
11461 \     MOV @IP+,PC                 \
11462 \ ENDCODE
11463 \     \
11464
11465 \ CODE LCD_RdS                    \ -- status       Read Status
11466 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
11467 \     JMP LCD_R
11468 \ ENDCODE
11469 \     \
11470
11471 \ CODE LCD_RdC                    \ -- char         Read Char
11472 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
11473 \     JMP LCD_R
11474 \ ENDCODE
11475 \     \
11476
11477 \ -------------+------+------+------+------++---+---+---+---+---------+
11478 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
11479 \ -------------+------+------+------+------++---+---+---+---+---------+
11480 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
11481 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
11482 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
11483 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
11484 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
11485 \ -------------+------+------+------+------++---+---+---+---+---------+
11486
11487
11488 \ ******************************\
11489 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
11490 \ ******************************\
11491 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
11492 \ ------------------------------\
11493 \ define LPM mode for ACCEPT    \
11494 \ ------------------------------\
11495 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
11496 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
11497 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
11498 BIT.B #SW2,&SW2_IN              \ test switch S2
11499 0= IF                           \ case of switch S2 pressed
11500     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
11501     U< IF
11502         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
11503     THEN
11504 ELSE
11505     BIT.B #SW1,&SW1_IN          \ test switch S1 input
11506     0= IF                       \ case of Switch S1 pressed
11507         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
11508         U>= IF                  \
11509             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
11510         THEN                    \
11511     THEN                        \
11512 THEN                            \
11513 RETI                            \ CPU is ON, GIE is OFF
11514 ENDASM                          \
11515     \
11516
11517
11518 \ ------------------------------\
11519 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
11520 \ ******************************\
11521 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
11522 \ ******************************\
11523 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
11524 \                               \       SMclock = 8|16|24 MHz
11525 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
11526 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
11527 \                               \       SR(9)=new Toggle bit memory (ADD on)
11528 \ ------------------------------\
11529 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
11530 \ ------------------------------\
11531 \ define LPM mode for ACCEPT    \
11532 \ ------------------------------\
11533 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
11534 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
11535 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
11536 \ ------------------------------\
11537 \ RC5_FirstStartBitHalfCycle:   \
11538 \ ------------------------------\
11539 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
11540 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
11541 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
11542 MOV     #1778,X                 \ RC5_Period in us
11543 MOV     #14,W                   \ count of loop
11544 BEGIN                           \
11545 \ ------------------------------\
11546 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
11547 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
11548     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
11549 \ RC5_Compute_3/4_Period:       \                   |
11550     RRUM    #1,X                \ X=1/2 cycle       |
11551     MOV     X,Y                 \ Y=1/2             ^
11552     RRUM    #1,Y                \ Y=1/4
11553     ADD     X,Y                 \ Y=3/4
11554 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
11555     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
11556     0= UNTIL                    \
11557 \ ------------------------------\
11558 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
11559 \ ------------------------------\
11560     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
11561     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
11562     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
11563     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
11564     SUB     #1,W                \ decrement count loop
11565 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
11566 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
11567 0<> WHILE                       \ ----> out of loop ----+
11568 \ RC5_compute_7/4_Time_out:     \                       |
11569     ADD     X,Y                 \                       |   out of bound = 7/4 period 
11570 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
11571     BEGIN                       \                       |
11572         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
11573         0>= IF                  \                       |   if cycle time out of bound
11574             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
11575             RETI                \                       |   then quit to do nothing
11576         THEN                    \                       |
11577 \ ------------------------------\                       |
11578         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
11579     0<> UNTIL                   \                   |   |
11580     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
11581 REPEAT                          \ ----> loop back --+   |
11582 \ ------------------------------\                       |
11583 \ RC5_SampleEndOf:              \ <---------------------+
11584 \ ------------------------------\
11585 BIC     #$30,&TA0CTL           \ stop timer_A0
11586 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
11587 \ ******************************\
11588 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
11589 \ ******************************\
11590 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
11591 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
11592 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
11593 BIT     #BIT13,X                \ X(13) = New_RC5_command
11594 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
11595 THEN                            \
11596 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
11597 \ ******************************\
11598 \ RC5_ComputeNewRC5word         \
11599 \ ******************************\
11600 SUB     #4,PSP                  \
11601 MOV     &BASE,2(PSP)            \ save variable BASE before use
11602 MOV     TOS,0(PSP)              \ save TOS before use
11603 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
11604 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
11605 \ ******************************\
11606 \ RC5_ComputeC6bit              \
11607 \ ******************************\
11608 BIT     #$4000,IP              \ test /C6 bit in IP
11609 0= IF   BIS #$40,TOS           \ set C6 bit in S
11610 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
11611 \ ******************************\
11612 \ RC5_CommandByteIsDone         \ RC5_code --
11613 \ ******************************\
11614
11615 \ ------------------------------\
11616 \ Display IR_RC5 code           \
11617 \ ------------------------------\
11618 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
11619 \ ------------------------------\
11620 LO2HI                           \ switch from assembler to FORTH
11621     ['] LCD_CLEAR IS CR         \ redirects CR
11622     ['] LCD_WrC  IS EMIT        \ redirects EMIT
11623     $10 BASE !                 \ change BASE to hexadecimal
11624     CR ." $" 2 U.R             \ print IR_RC5 code
11625     ['] (CR) IS CR              \ restore CR
11626     ['] (EMIT) IS EMIT          \ restore EMIT
11627 HI2LO                           \ switch from FORTH to assembler
11628 \ ------------------------------\
11629 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
11630 \ ------------------------------\
11631 MOV @PSP+,&BASE                 \ restore variable BASE
11632 RETI                            \ CPU is ON, GIE is OFF
11633 ENDASM                          \
11634     \ 
11635
11636 CODE START                      \
11637 \ ------------------------------\
11638 \ TB0CTL = %0000 0010 1001 0100\$3C0
11639 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
11640 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
11641 \                      --       \ID input divider \ 10 = /4
11642 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
11643 \                            -  \TBCLR TimerB Clear
11644 \                             - \TBIE
11645 \                              -\TBIFG
11646 \ --------------------------------\\
11647 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
11648 \              --                 \CM Capture Mode
11649 \                --               \CCIS
11650 \                   -             \SCS
11651 \                    --           \CLLD
11652 \                      -          \CAP
11653 \                        ---      \OUTMOD \ 011 = set/reset
11654 \                           -     \CCIE
11655 \                             -   \CCI
11656 \                              -  \OUT
11657 \                               - \COV
11658 \                                -\CCIFG
11659 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
11660 \ TB0EX0                          \$3E0 
11661 \ ------------------------------\
11662 \ set TimerB to make 50kHz PWM  \
11663 \ ------------------------------\
11664 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
11665 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
11666 \ ------------------------------\
11667 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
11668 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
11669 \ ------------------------------\
11670     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
11671     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
11672 \ ------------------------------\
11673 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
11674 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
11675 \ ------------------------------\
11676 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
11677 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
11678 \ ------------------------------\
11679     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
11680 \ ------------------------------\
11681 \ set TimerB to generate PWM for LCD_Vo
11682 \ ------------------------------\
11683     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
11684 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
11685     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
11686 \ ------------------------------\
11687     BIS.B #LCDVo,&LCDVo_DIR     \
11688     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
11689 \ ------------------------------\
11690     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
11691     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
11692 \ ------------------------------\
11693     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
11694     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
11695 \ ------------------------------\
11696 \ WDT interval init part        \
11697 \ ------------------------------\
11698     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
11699 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
11700 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
11701     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
11702 \ ------------------------------\
11703 \ init RC5_Int                  \
11704 \ ------------------------------\
11705     BIS.B #RC5,&IR_IE           \ enable RC5_Int
11706     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
11707 \ ------------------------------\
11708 \ init interrupt vectors
11709 \ ------------------------------\
11710     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
11711     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
11712 \ ------------------------------\
11713 \ define LPM mode for ACCEPT    \
11714 \ ------------------------------\
11715 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
11716 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
11717 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
11718
11719 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
11720
11721 \ ------------------------------\
11722 \ Init LCD 2x20                 \
11723 \ ------------------------------\
11724     $03E8 20_US                \ 1-  wait 20 ms
11725     $03 TOP_LCD                \ 2- send DB5=DB4=1
11726     $CD 20_US                  \ 3- wait 4,1 ms
11727     $03 TOP_LCD                \ 4- send again DB5=DB4=1
11728     $5 20_US                   \ 5- wait 0,1 ms
11729     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
11730     $2 20_US                   \    wait 40 us = LCD cycle
11731     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
11732     $2 20_US                   \    wait 40 us = LCD cycle
11733     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
11734     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
11735     LCD_Clear                   \ 10- "LCD_Clear"
11736     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
11737     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
11738     LCD_Clear                   \ 10- "LCD_Clear"
11739     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
11740     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
11741     CR ." I love you"   
11742     ['] (CR) IS CR              \ ' (CR) is CR
11743     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
11744     CR
11745     ."    RC5toLCD is running. Type STOP to quit"
11746 \    NOECHO                      \ uncomment to run this app without terminal connexion
11747     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
11748     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
11749 ;
11750     \
11751
11752 : STOP                  \ stops multitasking, must to be used before downloading app
11753     ['] (WARM) IS WARM  \ remove START app from FORTH init process
11754     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
11755 ;
11756     \
11757
11758
11759 RST_STATE   ;
11760
11761
11762 CODE MAX    \    n1 n2 -- n3       signed maximum
11763             CMP     @PSP,TOS    \ n2-n1
11764             S<      ?GOTO FW1   \ n2<n1
11765 BW1         ADD     #2,PSP
11766             MOV     @IP+,PC
11767 ENDCODE
11768     \
11769
11770 CODE MIN    \    n1 n2 -- n3       signed minimum
11771             CMP     @PSP,TOS     \ n2-n1
11772             S<      ?GOTO BW1    \ n2<n1
11773 FW1         MOV     @PSP+,TOS
11774             MOV     @IP+,PC
11775 ENDCODE
11776     \
11777
11778 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
11779   >R  <# 0 # #S #>  
11780   R> OVER - 0 MAX SPACES TYPE
11781 ;
11782     \
11783
11784 CODE 20_US                      \ n --      n * 20 us
11785 BEGIN                           \ 3 cycles loop + 6~  
11786 \    MOV     #5,W                \ 3 MCLK = 1 MHz
11787 \    MOV     #23,W               \ 3 MCLK = 4 MHz
11788     MOV     #51,W               \ 3 MCLK = 8 MHz
11789 \    MOV     #104,W              \ 3 MCLK = 16 MHz
11790 \    MOV     #158,W              \ 3 MCLK = 24 MHz
11791     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
11792         SUB #1,W                \ 1
11793     0= UNTIL                    \ 2
11794     SUB     #1,TOS              \ 1
11795 0= UNTIL                        \ 2
11796     MOV     @PSP+,TOS           \ 2
11797     MOV     @IP+,PC             \ 4
11798 ENDCODE
11799     \
11800
11801 CODE TOP_LCD                    \ LCD Sample
11802 \                               \ if write : %xxxxWWWW --
11803 \                               \ if read  : -- %0000RRRR
11804     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
11805     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
11806 0= IF                           \ write LCD bits pattern
11807     AND.B #LCD_DB,TOS           \ 
11808     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
11809     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
11810     MOV @PSP+,TOS               \
11811     MOV @IP+,PC
11812 THEN                            \ read LCD bits pattern
11813     SUB #2,PSP
11814     MOV TOS,0(PSP)
11815     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
11816     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
11817     AND.B #LCD_DB,TOS           \
11818     MOV @IP+,PC
11819 ENDCODE
11820     \
11821
11822 CODE LCD_W                      \ byte --       write byte to LCD 
11823     SUB #2,PSP                  \
11824     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
11825     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
11826     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
11827     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
11828 COLON                           \ high level word starts here 
11829     TOP_LCD 2 20_US             \ write high nibble first
11830     TOP_LCD 2 20_US 
11831 ;
11832     \
11833
11834 CODE LCD_WrC                    \ char --         Write Char
11835     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
11836     JMP LCD_W 
11837 ENDCODE
11838     \
11839
11840 CODE LCD_WrF                    \ func --         Write Fonction
11841     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
11842     JMP LCD_W 
11843 ENDCODE
11844     \
11845
11846 : LCD_Clear 
11847     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
11848 ;
11849     \
11850
11851 : LCD_Home 
11852     $02 LCD_WrF 100 20_us 
11853 ;
11854     \
11855
11856 \ : LCD_Entry_set       $04 OR LCD_WrF ;
11857
11858 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
11859
11860 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
11861
11862 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
11863
11864 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
11865
11866 \ : LCD_Goto            $80 OR LCD_WrF ;
11867
11868 \ CODE LCD_R                      \ -- byte       read byte from LCD
11869 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
11870 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
11871 \ COLON                           \ starts a FORTH word
11872 \     TOP_LCD 2 20_us             \ -- %0000HHHH
11873 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
11874 \ HI2LO                           \ switch from FORTH to assembler
11875 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
11876 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
11877 \     MOV @RSP+,IP                \ restore IP saved by COLON
11878 \     MOV @IP+,PC                 \
11879 \ ENDCODE
11880 \     \
11881
11882 \ CODE LCD_RdS                    \ -- status       Read Status
11883 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
11884 \     JMP LCD_R
11885 \ ENDCODE
11886 \     \
11887
11888 \ CODE LCD_RdC                    \ -- char         Read Char
11889 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
11890 \     JMP LCD_R
11891 \ ENDCODE
11892 \     \
11893
11894 \ -------------+------+------+------+------++---+---+---+---+---------+
11895 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
11896 \ -------------+------+------+------+------++---+---+---+---+---------+
11897 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
11898 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
11899 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
11900 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
11901 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
11902 \ -------------+------+------+------+------++---+---+---+---+---------+
11903
11904
11905 \ ******************************\
11906 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
11907 \ ******************************\
11908 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
11909 \ ------------------------------\
11910 \ define LPM mode for ACCEPT    \
11911 \ ------------------------------\
11912 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
11913 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
11914 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
11915 BIT.B #SW2,&SW2_IN              \ test switch S2
11916 0= IF                           \ case of switch S2 pressed
11917     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
11918     U< IF
11919         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
11920     THEN
11921 ELSE
11922     BIT.B #SW1,&SW1_IN          \ test switch S1 input
11923     0= IF                       \ case of Switch S1 pressed
11924         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
11925         U>= IF                  \
11926             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
11927         THEN                    \
11928     THEN                        \
11929 THEN                            \
11930 RETI                            \ CPU is ON, GIE is OFF
11931 ENDASM                          \
11932     \
11933
11934
11935 \ ------------------------------\
11936 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
11937 \ ******************************\
11938 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
11939 \ ******************************\
11940 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
11941 \                               \       SMclock = 8|16|24 MHz
11942 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
11943 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
11944 \                               \       SR(9)=new Toggle bit memory (ADD on)
11945 \ ------------------------------\
11946 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
11947 \ ------------------------------\
11948 \ define LPM mode for ACCEPT    \
11949 \ ------------------------------\
11950 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
11951 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
11952 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
11953 \ ------------------------------\
11954 \ RC5_FirstStartBitHalfCycle:   \
11955 \ ------------------------------\
11956 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
11957 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
11958 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
11959 MOV     #1778,X                 \ RC5_Period in us
11960 MOV     #14,W                   \ count of loop
11961 BEGIN                           \
11962 \ ------------------------------\
11963 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
11964 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
11965     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
11966 \ RC5_Compute_3/4_Period:       \                   |
11967     RRUM    #1,X                \ X=1/2 cycle       |
11968     MOV     X,Y                 \ Y=1/2             ^
11969     RRUM    #1,Y                \ Y=1/4
11970     ADD     X,Y                 \ Y=3/4
11971 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
11972     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
11973     0= UNTIL                    \
11974 \ ------------------------------\
11975 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
11976 \ ------------------------------\
11977     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
11978     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
11979     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
11980     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
11981     SUB     #1,W                \ decrement count loop
11982 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
11983 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
11984 0<> WHILE                       \ ----> out of loop ----+
11985 \ RC5_compute_7/4_Time_out:     \                       |
11986     ADD     X,Y                 \                       |   out of bound = 7/4 period 
11987 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
11988     BEGIN                       \                       |
11989         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
11990         0>= IF                  \                       |   if cycle time out of bound
11991             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
11992             RETI                \                       |   then quit to do nothing
11993         THEN                    \                       |
11994 \ ------------------------------\                       |
11995         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
11996     0<> UNTIL                   \                   |   |
11997     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
11998 REPEAT                          \ ----> loop back --+   |
11999 \ ------------------------------\                       |
12000 \ RC5_SampleEndOf:              \ <---------------------+
12001 \ ------------------------------\
12002 BIC     #$30,&TA0CTL           \ stop timer_A0
12003 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
12004 \ ******************************\
12005 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
12006 \ ******************************\
12007 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
12008 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
12009 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
12010 BIT     #BIT13,X                \ X(13) = New_RC5_command
12011 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
12012 THEN                            \
12013 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
12014 \ ******************************\
12015 \ RC5_ComputeNewRC5word         \
12016 \ ******************************\
12017 SUB     #4,PSP                  \
12018 MOV     &BASE,2(PSP)            \ save variable BASE before use
12019 MOV     TOS,0(PSP)              \ save TOS before use
12020 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
12021 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
12022 \ ******************************\
12023 \ RC5_ComputeC6bit              \
12024 \ ******************************\
12025 BIT     #$4000,IP              \ test /C6 bit in IP
12026 0= IF   BIS #$40,TOS           \ set C6 bit in S
12027 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
12028 \ ******************************\
12029 \ RC5_CommandByteIsDone         \ RC5_code --
12030 \ ******************************\
12031
12032 \ ------------------------------\
12033 \ Display IR_RC5 code           \
12034 \ ------------------------------\
12035 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
12036 \ ------------------------------\
12037 LO2HI                           \ switch from assembler to FORTH
12038     ['] LCD_CLEAR IS CR         \ redirects CR
12039     ['] LCD_WrC  IS EMIT        \ redirects EMIT
12040     $10 BASE !                 \ change BASE to hexadecimal
12041     CR ." $" 2 U.R             \ print IR_RC5 code
12042     ['] (CR) IS CR              \ restore CR
12043     ['] (EMIT) IS EMIT          \ restore EMIT
12044 HI2LO                           \ switch from FORTH to assembler
12045 \ ------------------------------\
12046 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
12047 \ ------------------------------\
12048 MOV @PSP+,&BASE                 \ restore variable BASE
12049 RETI                            \ CPU is ON, GIE is OFF
12050 ENDASM                          \
12051     \ 
12052
12053 CODE START                      \
12054 \ ------------------------------\
12055 \ TB0CTL = %0000 0010 1001 0100\$3C0
12056 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
12057 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
12058 \                      --       \ID input divider \ 10 = /4
12059 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
12060 \                            -  \TBCLR TimerB Clear
12061 \                             - \TBIE
12062 \                              -\TBIFG
12063 \ --------------------------------\\
12064 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
12065 \              --                 \CM Capture Mode
12066 \                --               \CCIS
12067 \                   -             \SCS
12068 \                    --           \CLLD
12069 \                      -          \CAP
12070 \                        ---      \OUTMOD \ 011 = set/reset
12071 \                           -     \CCIE
12072 \                             -   \CCI
12073 \                              -  \OUT
12074 \                               - \COV
12075 \                                -\CCIFG
12076 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
12077 \ TB0EX0                          \$3E0 
12078 \ ------------------------------\
12079 \ set TimerB to make 50kHz PWM  \
12080 \ ------------------------------\
12081 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
12082 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
12083 \ ------------------------------\
12084 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
12085 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
12086 \ ------------------------------\
12087     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
12088     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
12089 \ ------------------------------\
12090 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
12091 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
12092 \ ------------------------------\
12093 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
12094 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
12095 \ ------------------------------\
12096     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
12097 \ ------------------------------\
12098 \ set TimerB to generate PWM for LCD_Vo
12099 \ ------------------------------\
12100     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
12101 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
12102     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
12103 \ ------------------------------\
12104     BIS.B #LCDVo,&LCDVo_DIR     \
12105     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
12106 \ ------------------------------\
12107     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
12108     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
12109 \ ------------------------------\
12110     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
12111     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
12112 \ ------------------------------\
12113 \ WDT interval init part        \
12114 \ ------------------------------\
12115     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
12116 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
12117 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
12118     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
12119 \ ------------------------------\
12120 \ init RC5_Int                  \
12121 \ ------------------------------\
12122     BIS.B #RC5,&IR_IE           \ enable RC5_Int
12123     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
12124 \ ------------------------------\
12125 \ init interrupt vectors
12126 \ ------------------------------\
12127     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
12128     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
12129 \ ------------------------------\
12130 \ define LPM mode for ACCEPT    \
12131 \ ------------------------------\
12132 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
12133 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
12134 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
12135
12136 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
12137
12138 \ ------------------------------\
12139 \ Init LCD 2x20                 \
12140 \ ------------------------------\
12141     $03E8 20_US                \ 1-  wait 20 ms
12142     $03 TOP_LCD                \ 2- send DB5=DB4=1
12143     $CD 20_US                  \ 3- wait 4,1 ms
12144     $03 TOP_LCD                \ 4- send again DB5=DB4=1
12145     $5 20_US                   \ 5- wait 0,1 ms
12146     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
12147     $2 20_US                   \    wait 40 us = LCD cycle
12148     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
12149     $2 20_US                   \    wait 40 us = LCD cycle
12150     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
12151     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
12152     LCD_Clear                   \ 10- "LCD_Clear"
12153     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
12154     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
12155     LCD_Clear                   \ 10- "LCD_Clear"
12156     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
12157     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
12158     CR ." I love you"   
12159     ['] (CR) IS CR              \ ' (CR) is CR
12160     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
12161     CR
12162     ."    RC5toLCD is running. Type STOP to quit"
12163 \    NOECHO                      \ uncomment to run this app without terminal connexion
12164     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
12165     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
12166 ;
12167     \
12168
12169 : STOP                  \ stops multitasking, must to be used before downloading app
12170     ['] (WARM) IS WARM  \ remove START app from FORTH init process
12171     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
12172 ;
12173     \
12174
12175
12176 RST_STATE   ;
12177
12178
12179 CODE MAX    \    n1 n2 -- n3       signed maximum
12180             CMP     @PSP,TOS    \ n2-n1
12181             S<      ?GOTO FW1   \ n2<n1
12182 BW1         ADD     #2,PSP
12183             MOV     @IP+,PC
12184 ENDCODE
12185     \
12186
12187 CODE MIN    \    n1 n2 -- n3       signed minimum
12188             CMP     @PSP,TOS     \ n2-n1
12189             S<      ?GOTO BW1    \ n2<n1
12190 FW1         MOV     @PSP+,TOS
12191             MOV     @IP+,PC
12192 ENDCODE
12193     \
12194
12195 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
12196   >R  <# 0 # #S #>  
12197   R> OVER - 0 MAX SPACES TYPE
12198 ;
12199     \
12200
12201 CODE 20_US                      \ n --      n * 20 us
12202 BEGIN                           \ 3 cycles loop + 6~  
12203 \    MOV     #5,W                \ 3 MCLK = 1 MHz
12204 \    MOV     #23,W               \ 3 MCLK = 4 MHz
12205     MOV     #51,W               \ 3 MCLK = 8 MHz
12206 \    MOV     #104,W              \ 3 MCLK = 16 MHz
12207 \    MOV     #158,W              \ 3 MCLK = 24 MHz
12208     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
12209         SUB #1,W                \ 1
12210     0= UNTIL                    \ 2
12211     SUB     #1,TOS              \ 1
12212 0= UNTIL                        \ 2
12213     MOV     @PSP+,TOS           \ 2
12214     MOV     @IP+,PC             \ 4
12215 ENDCODE
12216     \
12217
12218 CODE TOP_LCD                    \ LCD Sample
12219 \                               \ if write : %xxxxWWWW --
12220 \                               \ if read  : -- %0000RRRR
12221     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
12222     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
12223 0= IF                           \ write LCD bits pattern
12224     AND.B #LCD_DB,TOS           \ 
12225     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
12226     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
12227     MOV @PSP+,TOS               \
12228     MOV @IP+,PC
12229 THEN                            \ read LCD bits pattern
12230     SUB #2,PSP
12231     MOV TOS,0(PSP)
12232     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
12233     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
12234     AND.B #LCD_DB,TOS           \
12235     MOV @IP+,PC
12236 ENDCODE
12237     \
12238
12239 CODE LCD_W                      \ byte --       write byte to LCD 
12240     SUB #2,PSP                  \
12241     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
12242     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
12243     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
12244     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
12245 COLON                           \ high level word starts here 
12246     TOP_LCD 2 20_US             \ write high nibble first
12247     TOP_LCD 2 20_US 
12248 ;
12249     \
12250
12251 CODE LCD_WrC                    \ char --         Write Char
12252     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
12253     JMP LCD_W 
12254 ENDCODE
12255     \
12256
12257 CODE LCD_WrF                    \ func --         Write Fonction
12258     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
12259     JMP LCD_W 
12260 ENDCODE
12261     \
12262
12263 : LCD_Clear 
12264     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
12265 ;
12266     \
12267
12268 : LCD_Home 
12269     $02 LCD_WrF 100 20_us 
12270 ;
12271     \
12272
12273 \ : LCD_Entry_set       $04 OR LCD_WrF ;
12274
12275 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
12276
12277 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
12278
12279 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
12280
12281 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
12282
12283 \ : LCD_Goto            $80 OR LCD_WrF ;
12284
12285 \ CODE LCD_R                      \ -- byte       read byte from LCD
12286 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
12287 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
12288 \ COLON                           \ starts a FORTH word
12289 \     TOP_LCD 2 20_us             \ -- %0000HHHH
12290 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
12291 \ HI2LO                           \ switch from FORTH to assembler
12292 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
12293 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
12294 \     MOV @RSP+,IP                \ restore IP saved by COLON
12295 \     MOV @IP+,PC                 \
12296 \ ENDCODE
12297 \     \
12298
12299 \ CODE LCD_RdS                    \ -- status       Read Status
12300 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
12301 \     JMP LCD_R
12302 \ ENDCODE
12303 \     \
12304
12305 \ CODE LCD_RdC                    \ -- char         Read Char
12306 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
12307 \     JMP LCD_R
12308 \ ENDCODE
12309 \     \
12310
12311 \ -------------+------+------+------+------++---+---+---+---+---------+
12312 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
12313 \ -------------+------+------+------+------++---+---+---+---+---------+
12314 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
12315 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
12316 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
12317 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
12318 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
12319 \ -------------+------+------+------+------++---+---+---+---+---------+
12320
12321
12322 \ ******************************\
12323 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
12324 \ ******************************\
12325 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
12326 \ ------------------------------\
12327 \ define LPM mode for ACCEPT    \
12328 \ ------------------------------\
12329 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
12330 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
12331 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
12332 BIT.B #SW2,&SW2_IN              \ test switch S2
12333 0= IF                           \ case of switch S2 pressed
12334     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
12335     U< IF
12336         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
12337     THEN
12338 ELSE
12339     BIT.B #SW1,&SW1_IN          \ test switch S1 input
12340     0= IF                       \ case of Switch S1 pressed
12341         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
12342         U>= IF                  \
12343             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
12344         THEN                    \
12345     THEN                        \
12346 THEN                            \
12347 RETI                            \ CPU is ON, GIE is OFF
12348 ENDASM                          \
12349     \
12350
12351
12352 \ ------------------------------\
12353 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
12354 \ ******************************\
12355 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
12356 \ ******************************\
12357 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
12358 \                               \       SMclock = 8|16|24 MHz
12359 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
12360 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
12361 \                               \       SR(9)=new Toggle bit memory (ADD on)
12362 \ ------------------------------\
12363 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
12364 \ ------------------------------\
12365 \ define LPM mode for ACCEPT    \
12366 \ ------------------------------\
12367 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
12368 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
12369 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
12370 \ ------------------------------\
12371 \ RC5_FirstStartBitHalfCycle:   \
12372 \ ------------------------------\
12373 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
12374 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
12375 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
12376 MOV     #1778,X                 \ RC5_Period in us
12377 MOV     #14,W                   \ count of loop
12378 BEGIN                           \
12379 \ ------------------------------\
12380 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
12381 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
12382     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
12383 \ RC5_Compute_3/4_Period:       \                   |
12384     RRUM    #1,X                \ X=1/2 cycle       |
12385     MOV     X,Y                 \ Y=1/2             ^
12386     RRUM    #1,Y                \ Y=1/4
12387     ADD     X,Y                 \ Y=3/4
12388 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
12389     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
12390     0= UNTIL                    \
12391 \ ------------------------------\
12392 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
12393 \ ------------------------------\
12394     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
12395     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
12396     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
12397     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
12398     SUB     #1,W                \ decrement count loop
12399 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
12400 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
12401 0<> WHILE                       \ ----> out of loop ----+
12402 \ RC5_compute_7/4_Time_out:     \                       |
12403     ADD     X,Y                 \                       |   out of bound = 7/4 period 
12404 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
12405     BEGIN                       \                       |
12406         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
12407         0>= IF                  \                       |   if cycle time out of bound
12408             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
12409             RETI                \                       |   then quit to do nothing
12410         THEN                    \                       |
12411 \ ------------------------------\                       |
12412         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
12413     0<> UNTIL                   \                   |   |
12414     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
12415 REPEAT                          \ ----> loop back --+   |
12416 \ ------------------------------\                       |
12417 \ RC5_SampleEndOf:              \ <---------------------+
12418 \ ------------------------------\
12419 BIC     #$30,&TA0CTL           \ stop timer_A0
12420 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
12421 \ ******************************\
12422 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
12423 \ ******************************\
12424 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
12425 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
12426 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
12427 BIT     #BIT13,X                \ X(13) = New_RC5_command
12428 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
12429 THEN                            \
12430 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
12431 \ ******************************\
12432 \ RC5_ComputeNewRC5word         \
12433 \ ******************************\
12434 SUB     #4,PSP                  \
12435 MOV     &BASE,2(PSP)            \ save variable BASE before use
12436 MOV     TOS,0(PSP)              \ save TOS before use
12437 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
12438 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
12439 \ ******************************\
12440 \ RC5_ComputeC6bit              \
12441 \ ******************************\
12442 BIT     #$4000,IP              \ test /C6 bit in IP
12443 0= IF   BIS #$40,TOS           \ set C6 bit in S
12444 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
12445 \ ******************************\
12446 \ RC5_CommandByteIsDone         \ RC5_code --
12447 \ ******************************\
12448
12449 \ ------------------------------\
12450 \ Display IR_RC5 code           \
12451 \ ------------------------------\
12452 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
12453 \ ------------------------------\
12454 LO2HI                           \ switch from assembler to FORTH
12455     ['] LCD_CLEAR IS CR         \ redirects CR
12456     ['] LCD_WrC  IS EMIT        \ redirects EMIT
12457     $10 BASE !                 \ change BASE to hexadecimal
12458     CR ." $" 2 U.R             \ print IR_RC5 code
12459     ['] (CR) IS CR              \ restore CR
12460     ['] (EMIT) IS EMIT          \ restore EMIT
12461 HI2LO                           \ switch from FORTH to assembler
12462 \ ------------------------------\
12463 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
12464 \ ------------------------------\
12465 MOV @PSP+,&BASE                 \ restore variable BASE
12466 RETI                            \ CPU is ON, GIE is OFF
12467 ENDASM                          \
12468     \ 
12469
12470 CODE START                      \
12471 \ ------------------------------\
12472 \ TB0CTL = %0000 0010 1001 0100\$3C0
12473 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
12474 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
12475 \                      --       \ID input divider \ 10 = /4
12476 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
12477 \                            -  \TBCLR TimerB Clear
12478 \                             - \TBIE
12479 \                              -\TBIFG
12480 \ --------------------------------\\
12481 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
12482 \              --                 \CM Capture Mode
12483 \                --               \CCIS
12484 \                   -             \SCS
12485 \                    --           \CLLD
12486 \                      -          \CAP
12487 \                        ---      \OUTMOD \ 011 = set/reset
12488 \                           -     \CCIE
12489 \                             -   \CCI
12490 \                              -  \OUT
12491 \                               - \COV
12492 \                                -\CCIFG
12493 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
12494 \ TB0EX0                          \$3E0 
12495 \ ------------------------------\
12496 \ set TimerB to make 50kHz PWM  \
12497 \ ------------------------------\
12498 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
12499 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
12500 \ ------------------------------\
12501 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
12502 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
12503 \ ------------------------------\
12504     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
12505     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
12506 \ ------------------------------\
12507 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
12508 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
12509 \ ------------------------------\
12510 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
12511 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
12512 \ ------------------------------\
12513     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
12514 \ ------------------------------\
12515 \ set TimerB to generate PWM for LCD_Vo
12516 \ ------------------------------\
12517     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
12518 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
12519     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
12520 \ ------------------------------\
12521     BIS.B #LCDVo,&LCDVo_DIR     \
12522     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
12523 \ ------------------------------\
12524     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
12525     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
12526 \ ------------------------------\
12527     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
12528     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
12529 \ ------------------------------\
12530 \ WDT interval init part        \
12531 \ ------------------------------\
12532     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
12533 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
12534 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
12535     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
12536 \ ------------------------------\
12537 \ init RC5_Int                  \
12538 \ ------------------------------\
12539     BIS.B #RC5,&IR_IE           \ enable RC5_Int
12540     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
12541 \ ------------------------------\
12542 \ init interrupt vectors
12543 \ ------------------------------\
12544     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
12545     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
12546 \ ------------------------------\
12547 \ define LPM mode for ACCEPT    \
12548 \ ------------------------------\
12549 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
12550 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
12551 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
12552
12553 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
12554
12555 \ ------------------------------\
12556 \ Init LCD 2x20                 \
12557 \ ------------------------------\
12558     $03E8 20_US                \ 1-  wait 20 ms
12559     $03 TOP_LCD                \ 2- send DB5=DB4=1
12560     $CD 20_US                  \ 3- wait 4,1 ms
12561     $03 TOP_LCD                \ 4- send again DB5=DB4=1
12562     $5 20_US                   \ 5- wait 0,1 ms
12563     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
12564     $2 20_US                   \    wait 40 us = LCD cycle
12565     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
12566     $2 20_US                   \    wait 40 us = LCD cycle
12567     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
12568     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
12569     LCD_Clear                   \ 10- "LCD_Clear"
12570     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
12571     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
12572     LCD_Clear                   \ 10- "LCD_Clear"
12573     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
12574     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
12575     CR ." I love you"   
12576     ['] (CR) IS CR              \ ' (CR) is CR
12577     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
12578     CR
12579     ."    RC5toLCD is running. Type STOP to quit"
12580 \    NOECHO                      \ uncomment to run this app without terminal connexion
12581     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
12582     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
12583 ;
12584     \
12585
12586 : STOP                  \ stops multitasking, must to be used before downloading app
12587     ['] (WARM) IS WARM  \ remove START app from FORTH init process
12588     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
12589 ;
12590     \
12591
12592
12593 RST_STATE   ;
12594
12595
12596 CODE MAX    \    n1 n2 -- n3       signed maximum
12597             CMP     @PSP,TOS    \ n2-n1
12598             S<      ?GOTO FW1   \ n2<n1
12599 BW1         ADD     #2,PSP
12600             MOV     @IP+,PC
12601 ENDCODE
12602     \
12603
12604 CODE MIN    \    n1 n2 -- n3       signed minimum
12605             CMP     @PSP,TOS     \ n2-n1
12606             S<      ?GOTO BW1    \ n2<n1
12607 FW1         MOV     @PSP+,TOS
12608             MOV     @IP+,PC
12609 ENDCODE
12610     \
12611
12612 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
12613   >R  <# 0 # #S #>  
12614   R> OVER - 0 MAX SPACES TYPE
12615 ;
12616     \
12617
12618 CODE 20_US                      \ n --      n * 20 us
12619 BEGIN                           \ 3 cycles loop + 6~  
12620 \    MOV     #5,W                \ 3 MCLK = 1 MHz
12621 \    MOV     #23,W               \ 3 MCLK = 4 MHz
12622     MOV     #51,W               \ 3 MCLK = 8 MHz
12623 \    MOV     #104,W              \ 3 MCLK = 16 MHz
12624 \    MOV     #158,W              \ 3 MCLK = 24 MHz
12625     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
12626         SUB #1,W                \ 1
12627     0= UNTIL                    \ 2
12628     SUB     #1,TOS              \ 1
12629 0= UNTIL                        \ 2
12630     MOV     @PSP+,TOS           \ 2
12631     MOV     @IP+,PC             \ 4
12632 ENDCODE
12633     \
12634
12635 CODE TOP_LCD                    \ LCD Sample
12636 \                               \ if write : %xxxxWWWW --
12637 \                               \ if read  : -- %0000RRRR
12638     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
12639     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
12640 0= IF                           \ write LCD bits pattern
12641     AND.B #LCD_DB,TOS           \ 
12642     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
12643     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
12644     MOV @PSP+,TOS               \
12645     MOV @IP+,PC
12646 THEN                            \ read LCD bits pattern
12647     SUB #2,PSP
12648     MOV TOS,0(PSP)
12649     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
12650     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
12651     AND.B #LCD_DB,TOS           \
12652     MOV @IP+,PC
12653 ENDCODE
12654     \
12655
12656 CODE LCD_W                      \ byte --       write byte to LCD 
12657     SUB #2,PSP                  \
12658     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
12659     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
12660     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
12661     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
12662 COLON                           \ high level word starts here 
12663     TOP_LCD 2 20_US             \ write high nibble first
12664     TOP_LCD 2 20_US 
12665 ;
12666     \
12667
12668 CODE LCD_WrC                    \ char --         Write Char
12669     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
12670     JMP LCD_W 
12671 ENDCODE
12672     \
12673
12674 CODE LCD_WrF                    \ func --         Write Fonction
12675     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
12676     JMP LCD_W 
12677 ENDCODE
12678     \
12679
12680 : LCD_Clear 
12681     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
12682 ;
12683     \
12684
12685 : LCD_Home 
12686     $02 LCD_WrF 100 20_us 
12687 ;
12688     \
12689
12690 \ : LCD_Entry_set       $04 OR LCD_WrF ;
12691
12692 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
12693
12694 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
12695
12696 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
12697
12698 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
12699
12700 \ : LCD_Goto            $80 OR LCD_WrF ;
12701
12702 \ CODE LCD_R                      \ -- byte       read byte from LCD
12703 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
12704 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
12705 \ COLON                           \ starts a FORTH word
12706 \     TOP_LCD 2 20_us             \ -- %0000HHHH
12707 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
12708 \ HI2LO                           \ switch from FORTH to assembler
12709 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
12710 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
12711 \     MOV @RSP+,IP                \ restore IP saved by COLON
12712 \     MOV @IP+,PC                 \
12713 \ ENDCODE
12714 \     \
12715
12716 \ CODE LCD_RdS                    \ -- status       Read Status
12717 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
12718 \     JMP LCD_R
12719 \ ENDCODE
12720 \     \
12721
12722 \ CODE LCD_RdC                    \ -- char         Read Char
12723 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
12724 \     JMP LCD_R
12725 \ ENDCODE
12726 \     \
12727
12728 \ -------------+------+------+------+------++---+---+---+---+---------+
12729 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
12730 \ -------------+------+------+------+------++---+---+---+---+---------+
12731 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
12732 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
12733 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
12734 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
12735 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
12736 \ -------------+------+------+------+------++---+---+---+---+---------+
12737
12738
12739 \ ******************************\
12740 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
12741 \ ******************************\
12742 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
12743 \ ------------------------------\
12744 \ define LPM mode for ACCEPT    \
12745 \ ------------------------------\
12746 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
12747 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
12748 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
12749 BIT.B #SW2,&SW2_IN              \ test switch S2
12750 0= IF                           \ case of switch S2 pressed
12751     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
12752     U< IF
12753         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
12754     THEN
12755 ELSE
12756     BIT.B #SW1,&SW1_IN          \ test switch S1 input
12757     0= IF                       \ case of Switch S1 pressed
12758         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
12759         U>= IF                  \
12760             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
12761         THEN                    \
12762     THEN                        \
12763 THEN                            \
12764 RETI                            \ CPU is ON, GIE is OFF
12765 ENDASM                          \
12766     \
12767
12768
12769 \ ------------------------------\
12770 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
12771 \ ******************************\
12772 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
12773 \ ******************************\
12774 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
12775 \                               \       SMclock = 8|16|24 MHz
12776 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
12777 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
12778 \                               \       SR(9)=new Toggle bit memory (ADD on)
12779 \ ------------------------------\
12780 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
12781 \ ------------------------------\
12782 \ define LPM mode for ACCEPT    \
12783 \ ------------------------------\
12784 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
12785 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
12786 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
12787 \ ------------------------------\
12788 \ RC5_FirstStartBitHalfCycle:   \
12789 \ ------------------------------\
12790 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
12791 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
12792 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
12793 MOV     #1778,X                 \ RC5_Period in us
12794 MOV     #14,W                   \ count of loop
12795 BEGIN                           \
12796 \ ------------------------------\
12797 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
12798 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
12799     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
12800 \ RC5_Compute_3/4_Period:       \                   |
12801     RRUM    #1,X                \ X=1/2 cycle       |
12802     MOV     X,Y                 \ Y=1/2             ^
12803     RRUM    #1,Y                \ Y=1/4
12804     ADD     X,Y                 \ Y=3/4
12805 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
12806     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
12807     0= UNTIL                    \
12808 \ ------------------------------\
12809 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
12810 \ ------------------------------\
12811     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
12812     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
12813     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
12814     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
12815     SUB     #1,W                \ decrement count loop
12816 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
12817 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
12818 0<> WHILE                       \ ----> out of loop ----+
12819 \ RC5_compute_7/4_Time_out:     \                       |
12820     ADD     X,Y                 \                       |   out of bound = 7/4 period 
12821 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
12822     BEGIN                       \                       |
12823         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
12824         0>= IF                  \                       |   if cycle time out of bound
12825             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
12826             RETI                \                       |   then quit to do nothing
12827         THEN                    \                       |
12828 \ ------------------------------\                       |
12829         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
12830     0<> UNTIL                   \                   |   |
12831     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
12832 REPEAT                          \ ----> loop back --+   |
12833 \ ------------------------------\                       |
12834 \ RC5_SampleEndOf:              \ <---------------------+
12835 \ ------------------------------\
12836 BIC     #$30,&TA0CTL           \ stop timer_A0
12837 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
12838 \ ******************************\
12839 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
12840 \ ******************************\
12841 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
12842 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
12843 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
12844 BIT     #BIT13,X                \ X(13) = New_RC5_command
12845 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
12846 THEN                            \
12847 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
12848 \ ******************************\
12849 \ RC5_ComputeNewRC5word         \
12850 \ ******************************\
12851 SUB     #4,PSP                  \
12852 MOV     &BASE,2(PSP)            \ save variable BASE before use
12853 MOV     TOS,0(PSP)              \ save TOS before use
12854 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
12855 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
12856 \ ******************************\
12857 \ RC5_ComputeC6bit              \
12858 \ ******************************\
12859 BIT     #$4000,IP              \ test /C6 bit in IP
12860 0= IF   BIS #$40,TOS           \ set C6 bit in S
12861 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
12862 \ ******************************\
12863 \ RC5_CommandByteIsDone         \ RC5_code --
12864 \ ******************************\
12865
12866 \ ------------------------------\
12867 \ Display IR_RC5 code           \
12868 \ ------------------------------\
12869 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
12870 \ ------------------------------\
12871 LO2HI                           \ switch from assembler to FORTH
12872     ['] LCD_CLEAR IS CR         \ redirects CR
12873     ['] LCD_WrC  IS EMIT        \ redirects EMIT
12874     $10 BASE !                 \ change BASE to hexadecimal
12875     CR ." $" 2 U.R             \ print IR_RC5 code
12876     ['] (CR) IS CR              \ restore CR
12877     ['] (EMIT) IS EMIT          \ restore EMIT
12878 HI2LO                           \ switch from FORTH to assembler
12879 \ ------------------------------\
12880 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
12881 \ ------------------------------\
12882 MOV @PSP+,&BASE                 \ restore variable BASE
12883 RETI                            \ CPU is ON, GIE is OFF
12884 ENDASM                          \
12885     \ 
12886
12887 CODE START                      \
12888 \ ------------------------------\
12889 \ TB0CTL = %0000 0010 1001 0100\$3C0
12890 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
12891 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
12892 \                      --       \ID input divider \ 10 = /4
12893 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
12894 \                            -  \TBCLR TimerB Clear
12895 \                             - \TBIE
12896 \                              -\TBIFG
12897 \ --------------------------------\\
12898 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
12899 \              --                 \CM Capture Mode
12900 \                --               \CCIS
12901 \                   -             \SCS
12902 \                    --           \CLLD
12903 \                      -          \CAP
12904 \                        ---      \OUTMOD \ 011 = set/reset
12905 \                           -     \CCIE
12906 \                             -   \CCI
12907 \                              -  \OUT
12908 \                               - \COV
12909 \                                -\CCIFG
12910 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
12911 \ TB0EX0                          \$3E0 
12912 \ ------------------------------\
12913 \ set TimerB to make 50kHz PWM  \
12914 \ ------------------------------\
12915 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
12916 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
12917 \ ------------------------------\
12918 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
12919 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
12920 \ ------------------------------\
12921     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
12922     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
12923 \ ------------------------------\
12924 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
12925 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
12926 \ ------------------------------\
12927 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
12928 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
12929 \ ------------------------------\
12930     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
12931 \ ------------------------------\
12932 \ set TimerB to generate PWM for LCD_Vo
12933 \ ------------------------------\
12934     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
12935 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
12936     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
12937 \ ------------------------------\
12938     BIS.B #LCDVo,&LCDVo_DIR     \
12939     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
12940 \ ------------------------------\
12941     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
12942     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
12943 \ ------------------------------\
12944     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
12945     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
12946 \ ------------------------------\
12947 \ WDT interval init part        \
12948 \ ------------------------------\
12949     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
12950 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
12951 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
12952     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
12953 \ ------------------------------\
12954 \ init RC5_Int                  \
12955 \ ------------------------------\
12956     BIS.B #RC5,&IR_IE           \ enable RC5_Int
12957     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
12958 \ ------------------------------\
12959 \ init interrupt vectors
12960 \ ------------------------------\
12961     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
12962     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
12963 \ ------------------------------\
12964 \ define LPM mode for ACCEPT    \
12965 \ ------------------------------\
12966 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
12967 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
12968 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
12969
12970 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
12971
12972 \ ------------------------------\
12973 \ Init LCD 2x20                 \
12974 \ ------------------------------\
12975     $03E8 20_US                \ 1-  wait 20 ms
12976     $03 TOP_LCD                \ 2- send DB5=DB4=1
12977     $CD 20_US                  \ 3- wait 4,1 ms
12978     $03 TOP_LCD                \ 4- send again DB5=DB4=1
12979     $5 20_US                   \ 5- wait 0,1 ms
12980     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
12981     $2 20_US                   \    wait 40 us = LCD cycle
12982     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
12983     $2 20_US                   \    wait 40 us = LCD cycle
12984     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
12985     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
12986     LCD_Clear                   \ 10- "LCD_Clear"
12987     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
12988     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
12989     LCD_Clear                   \ 10- "LCD_Clear"
12990     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
12991     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
12992     CR ." I love you"   
12993     ['] (CR) IS CR              \ ' (CR) is CR
12994     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
12995     CR
12996     ."    RC5toLCD is running. Type STOP to quit"
12997 \    NOECHO                      \ uncomment to run this app without terminal connexion
12998     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
12999     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
13000 ;
13001     \
13002
13003 : STOP                  \ stops multitasking, must to be used before downloading app
13004     ['] (WARM) IS WARM  \ remove START app from FORTH init process
13005     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
13006 ;
13007     \
13008
13009
13010 RST_STATE   ;
13011
13012
13013 CODE MAX    \    n1 n2 -- n3       signed maximum
13014             CMP     @PSP,TOS    \ n2-n1
13015             S<      ?GOTO FW1   \ n2<n1
13016 BW1         ADD     #2,PSP
13017             MOV     @IP+,PC
13018 ENDCODE
13019     \
13020
13021 CODE MIN    \    n1 n2 -- n3       signed minimum
13022             CMP     @PSP,TOS     \ n2-n1
13023             S<      ?GOTO BW1    \ n2<n1
13024 FW1         MOV     @PSP+,TOS
13025             MOV     @IP+,PC
13026 ENDCODE
13027     \
13028
13029 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
13030   >R  <# 0 # #S #>  
13031   R> OVER - 0 MAX SPACES TYPE
13032 ;
13033     \
13034
13035 CODE 20_US                      \ n --      n * 20 us
13036 BEGIN                           \ 3 cycles loop + 6~  
13037 \    MOV     #5,W                \ 3 MCLK = 1 MHz
13038 \    MOV     #23,W               \ 3 MCLK = 4 MHz
13039     MOV     #51,W               \ 3 MCLK = 8 MHz
13040 \    MOV     #104,W              \ 3 MCLK = 16 MHz
13041 \    MOV     #158,W              \ 3 MCLK = 24 MHz
13042     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
13043         SUB #1,W                \ 1
13044     0= UNTIL                    \ 2
13045     SUB     #1,TOS              \ 1
13046 0= UNTIL                        \ 2
13047     MOV     @PSP+,TOS           \ 2
13048     MOV     @IP+,PC             \ 4
13049 ENDCODE
13050     \
13051
13052 CODE TOP_LCD                    \ LCD Sample
13053 \                               \ if write : %xxxxWWWW --
13054 \                               \ if read  : -- %0000RRRR
13055     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
13056     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
13057 0= IF                           \ write LCD bits pattern
13058     AND.B #LCD_DB,TOS           \ 
13059     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
13060     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
13061     MOV @PSP+,TOS               \
13062     MOV @IP+,PC
13063 THEN                            \ read LCD bits pattern
13064     SUB #2,PSP
13065     MOV TOS,0(PSP)
13066     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
13067     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
13068     AND.B #LCD_DB,TOS           \
13069     MOV @IP+,PC
13070 ENDCODE
13071     \
13072
13073 CODE LCD_W                      \ byte --       write byte to LCD 
13074     SUB #2,PSP                  \
13075     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
13076     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
13077     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
13078     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
13079 COLON                           \ high level word starts here 
13080     TOP_LCD 2 20_US             \ write high nibble first
13081     TOP_LCD 2 20_US 
13082 ;
13083     \
13084
13085 CODE LCD_WrC                    \ char --         Write Char
13086     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
13087     JMP LCD_W 
13088 ENDCODE
13089     \
13090
13091 CODE LCD_WrF                    \ func --         Write Fonction
13092     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
13093     JMP LCD_W 
13094 ENDCODE
13095     \
13096
13097 : LCD_Clear 
13098     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
13099 ;
13100     \
13101
13102 : LCD_Home 
13103     $02 LCD_WrF 100 20_us 
13104 ;
13105     \
13106
13107 \ : LCD_Entry_set       $04 OR LCD_WrF ;
13108
13109 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
13110
13111 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
13112
13113 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
13114
13115 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
13116
13117 \ : LCD_Goto            $80 OR LCD_WrF ;
13118
13119 \ CODE LCD_R                      \ -- byte       read byte from LCD
13120 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
13121 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
13122 \ COLON                           \ starts a FORTH word
13123 \     TOP_LCD 2 20_us             \ -- %0000HHHH
13124 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
13125 \ HI2LO                           \ switch from FORTH to assembler
13126 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
13127 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
13128 \     MOV @RSP+,IP                \ restore IP saved by COLON
13129 \     MOV @IP+,PC                 \
13130 \ ENDCODE
13131 \     \
13132
13133 \ CODE LCD_RdS                    \ -- status       Read Status
13134 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
13135 \     JMP LCD_R
13136 \ ENDCODE
13137 \     \
13138
13139 \ CODE LCD_RdC                    \ -- char         Read Char
13140 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
13141 \     JMP LCD_R
13142 \ ENDCODE
13143 \     \
13144
13145 \ -------------+------+------+------+------++---+---+---+---+---------+
13146 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
13147 \ -------------+------+------+------+------++---+---+---+---+---------+
13148 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
13149 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
13150 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
13151 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
13152 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
13153 \ -------------+------+------+------+------++---+---+---+---+---------+
13154
13155
13156 \ ******************************\
13157 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
13158 \ ******************************\
13159 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
13160 \ ------------------------------\
13161 \ define LPM mode for ACCEPT    \
13162 \ ------------------------------\
13163 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
13164 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
13165 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
13166 BIT.B #SW2,&SW2_IN              \ test switch S2
13167 0= IF                           \ case of switch S2 pressed
13168     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
13169     U< IF
13170         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
13171     THEN
13172 ELSE
13173     BIT.B #SW1,&SW1_IN          \ test switch S1 input
13174     0= IF                       \ case of Switch S1 pressed
13175         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
13176         U>= IF                  \
13177             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
13178         THEN                    \
13179     THEN                        \
13180 THEN                            \
13181 RETI                            \ CPU is ON, GIE is OFF
13182 ENDASM                          \
13183     \
13184
13185
13186 \ ------------------------------\
13187 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
13188 \ ******************************\
13189 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
13190 \ ******************************\
13191 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
13192 \                               \       SMclock = 8|16|24 MHz
13193 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
13194 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
13195 \                               \       SR(9)=new Toggle bit memory (ADD on)
13196 \ ------------------------------\
13197 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
13198 \ ------------------------------\
13199 \ define LPM mode for ACCEPT    \
13200 \ ------------------------------\
13201 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
13202 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
13203 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
13204 \ ------------------------------\
13205 \ RC5_FirstStartBitHalfCycle:   \
13206 \ ------------------------------\
13207 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
13208 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
13209 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
13210 MOV     #1778,X                 \ RC5_Period in us
13211 MOV     #14,W                   \ count of loop
13212 BEGIN                           \
13213 \ ------------------------------\
13214 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
13215 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
13216     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
13217 \ RC5_Compute_3/4_Period:       \                   |
13218     RRUM    #1,X                \ X=1/2 cycle       |
13219     MOV     X,Y                 \ Y=1/2             ^
13220     RRUM    #1,Y                \ Y=1/4
13221     ADD     X,Y                 \ Y=3/4
13222 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
13223     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
13224     0= UNTIL                    \
13225 \ ------------------------------\
13226 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
13227 \ ------------------------------\
13228     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
13229     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
13230     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
13231     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
13232     SUB     #1,W                \ decrement count loop
13233 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
13234 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
13235 0<> WHILE                       \ ----> out of loop ----+
13236 \ RC5_compute_7/4_Time_out:     \                       |
13237     ADD     X,Y                 \                       |   out of bound = 7/4 period 
13238 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
13239     BEGIN                       \                       |
13240         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
13241         0>= IF                  \                       |   if cycle time out of bound
13242             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
13243             RETI                \                       |   then quit to do nothing
13244         THEN                    \                       |
13245 \ ------------------------------\                       |
13246         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
13247     0<> UNTIL                   \                   |   |
13248     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
13249 REPEAT                          \ ----> loop back --+   |
13250 \ ------------------------------\                       |
13251 \ RC5_SampleEndOf:              \ <---------------------+
13252 \ ------------------------------\
13253 BIC     #$30,&TA0CTL           \ stop timer_A0
13254 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
13255 \ ******************************\
13256 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
13257 \ ******************************\
13258 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
13259 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
13260 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
13261 BIT     #BIT13,X                \ X(13) = New_RC5_command
13262 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
13263 THEN                            \
13264 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
13265 \ ******************************\
13266 \ RC5_ComputeNewRC5word         \
13267 \ ******************************\
13268 SUB     #4,PSP                  \
13269 MOV     &BASE,2(PSP)            \ save variable BASE before use
13270 MOV     TOS,0(PSP)              \ save TOS before use
13271 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
13272 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
13273 \ ******************************\
13274 \ RC5_ComputeC6bit              \
13275 \ ******************************\
13276 BIT     #$4000,IP              \ test /C6 bit in IP
13277 0= IF   BIS #$40,TOS           \ set C6 bit in S
13278 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
13279 \ ******************************\
13280 \ RC5_CommandByteIsDone         \ RC5_code --
13281 \ ******************************\
13282
13283 \ ------------------------------\
13284 \ Display IR_RC5 code           \
13285 \ ------------------------------\
13286 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
13287 \ ------------------------------\
13288 LO2HI                           \ switch from assembler to FORTH
13289     ['] LCD_CLEAR IS CR         \ redirects CR
13290     ['] LCD_WrC  IS EMIT        \ redirects EMIT
13291     $10 BASE !                 \ change BASE to hexadecimal
13292     CR ." $" 2 U.R             \ print IR_RC5 code
13293     ['] (CR) IS CR              \ restore CR
13294     ['] (EMIT) IS EMIT          \ restore EMIT
13295 HI2LO                           \ switch from FORTH to assembler
13296 \ ------------------------------\
13297 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
13298 \ ------------------------------\
13299 MOV @PSP+,&BASE                 \ restore variable BASE
13300 RETI                            \ CPU is ON, GIE is OFF
13301 ENDASM                          \
13302     \ 
13303
13304 CODE START                      \
13305 \ ------------------------------\
13306 \ TB0CTL = %0000 0010 1001 0100\$3C0
13307 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
13308 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
13309 \                      --       \ID input divider \ 10 = /4
13310 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
13311 \                            -  \TBCLR TimerB Clear
13312 \                             - \TBIE
13313 \                              -\TBIFG
13314 \ --------------------------------\\
13315 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
13316 \              --                 \CM Capture Mode
13317 \                --               \CCIS
13318 \                   -             \SCS
13319 \                    --           \CLLD
13320 \                      -          \CAP
13321 \                        ---      \OUTMOD \ 011 = set/reset
13322 \                           -     \CCIE
13323 \                             -   \CCI
13324 \                              -  \OUT
13325 \                               - \COV
13326 \                                -\CCIFG
13327 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
13328 \ TB0EX0                          \$3E0 
13329 \ ------------------------------\
13330 \ set TimerB to make 50kHz PWM  \
13331 \ ------------------------------\
13332 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
13333 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
13334 \ ------------------------------\
13335 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
13336 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
13337 \ ------------------------------\
13338     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
13339     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
13340 \ ------------------------------\
13341 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
13342 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
13343 \ ------------------------------\
13344 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
13345 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
13346 \ ------------------------------\
13347     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
13348 \ ------------------------------\
13349 \ set TimerB to generate PWM for LCD_Vo
13350 \ ------------------------------\
13351     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
13352 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
13353     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
13354 \ ------------------------------\
13355     BIS.B #LCDVo,&LCDVo_DIR     \
13356     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
13357 \ ------------------------------\
13358     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
13359     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
13360 \ ------------------------------\
13361     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
13362     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
13363 \ ------------------------------\
13364 \ WDT interval init part        \
13365 \ ------------------------------\
13366     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
13367 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
13368 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
13369     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
13370 \ ------------------------------\
13371 \ init RC5_Int                  \
13372 \ ------------------------------\
13373     BIS.B #RC5,&IR_IE           \ enable RC5_Int
13374     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
13375 \ ------------------------------\
13376 \ init interrupt vectors
13377 \ ------------------------------\
13378     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
13379     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
13380 \ ------------------------------\
13381 \ define LPM mode for ACCEPT    \
13382 \ ------------------------------\
13383 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
13384 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
13385 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
13386
13387 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
13388
13389 \ ------------------------------\
13390 \ Init LCD 2x20                 \
13391 \ ------------------------------\
13392     $03E8 20_US                \ 1-  wait 20 ms
13393     $03 TOP_LCD                \ 2- send DB5=DB4=1
13394     $CD 20_US                  \ 3- wait 4,1 ms
13395     $03 TOP_LCD                \ 4- send again DB5=DB4=1
13396     $5 20_US                   \ 5- wait 0,1 ms
13397     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
13398     $2 20_US                   \    wait 40 us = LCD cycle
13399     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
13400     $2 20_US                   \    wait 40 us = LCD cycle
13401     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
13402     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
13403     LCD_Clear                   \ 10- "LCD_Clear"
13404     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
13405     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
13406     LCD_Clear                   \ 10- "LCD_Clear"
13407     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
13408     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
13409     CR ." I love you"   
13410     ['] (CR) IS CR              \ ' (CR) is CR
13411     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
13412     CR
13413     ."    RC5toLCD is running. Type STOP to quit"
13414 \    NOECHO                      \ uncomment to run this app without terminal connexion
13415     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
13416     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
13417 ;
13418     \
13419
13420 : STOP                  \ stops multitasking, must to be used before downloading app
13421     ['] (WARM) IS WARM  \ remove START app from FORTH init process
13422     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
13423 ;
13424     \
13425
13426
13427 RST_STATE   ;
13428
13429
13430 CODE MAX    \    n1 n2 -- n3       signed maximum
13431             CMP     @PSP,TOS    \ n2-n1
13432             S<      ?GOTO FW1   \ n2<n1
13433 BW1         ADD     #2,PSP
13434             MOV     @IP+,PC
13435 ENDCODE
13436     \
13437
13438 CODE MIN    \    n1 n2 -- n3       signed minimum
13439             CMP     @PSP,TOS     \ n2-n1
13440             S<      ?GOTO BW1    \ n2<n1
13441 FW1         MOV     @PSP+,TOS
13442             MOV     @IP+,PC
13443 ENDCODE
13444     \
13445
13446 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
13447   >R  <# 0 # #S #>  
13448   R> OVER - 0 MAX SPACES TYPE
13449 ;
13450     \
13451
13452 CODE 20_US                      \ n --      n * 20 us
13453 BEGIN                           \ 3 cycles loop + 6~  
13454 \    MOV     #5,W                \ 3 MCLK = 1 MHz
13455 \    MOV     #23,W               \ 3 MCLK = 4 MHz
13456     MOV     #51,W               \ 3 MCLK = 8 MHz
13457 \    MOV     #104,W              \ 3 MCLK = 16 MHz
13458 \    MOV     #158,W              \ 3 MCLK = 24 MHz
13459     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
13460         SUB #1,W                \ 1
13461     0= UNTIL                    \ 2
13462     SUB     #1,TOS              \ 1
13463 0= UNTIL                        \ 2
13464     MOV     @PSP+,TOS           \ 2
13465     MOV     @IP+,PC             \ 4
13466 ENDCODE
13467     \
13468
13469 CODE TOP_LCD                    \ LCD Sample
13470 \                               \ if write : %xxxxWWWW --
13471 \                               \ if read  : -- %0000RRRR
13472     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
13473     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
13474 0= IF                           \ write LCD bits pattern
13475     AND.B #LCD_DB,TOS           \ 
13476     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
13477     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
13478     MOV @PSP+,TOS               \
13479     MOV @IP+,PC
13480 THEN                            \ read LCD bits pattern
13481     SUB #2,PSP
13482     MOV TOS,0(PSP)
13483     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
13484     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
13485     AND.B #LCD_DB,TOS           \
13486     MOV @IP+,PC
13487 ENDCODE
13488     \
13489
13490 CODE LCD_W                      \ byte --       write byte to LCD 
13491     SUB #2,PSP                  \
13492     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
13493     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
13494     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
13495     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
13496 COLON                           \ high level word starts here 
13497     TOP_LCD 2 20_US             \ write high nibble first
13498     TOP_LCD 2 20_US 
13499 ;
13500     \
13501
13502 CODE LCD_WrC                    \ char --         Write Char
13503     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
13504     JMP LCD_W 
13505 ENDCODE
13506     \
13507
13508 CODE LCD_WrF                    \ func --         Write Fonction
13509     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
13510     JMP LCD_W 
13511 ENDCODE
13512     \
13513
13514 : LCD_Clear 
13515     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
13516 ;
13517     \
13518
13519 : LCD_Home 
13520     $02 LCD_WrF 100 20_us 
13521 ;
13522     \
13523
13524 \ : LCD_Entry_set       $04 OR LCD_WrF ;
13525
13526 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
13527
13528 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
13529
13530 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
13531
13532 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
13533
13534 \ : LCD_Goto            $80 OR LCD_WrF ;
13535
13536 \ CODE LCD_R                      \ -- byte       read byte from LCD
13537 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
13538 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
13539 \ COLON                           \ starts a FORTH word
13540 \     TOP_LCD 2 20_us             \ -- %0000HHHH
13541 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
13542 \ HI2LO                           \ switch from FORTH to assembler
13543 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
13544 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
13545 \     MOV @RSP+,IP                \ restore IP saved by COLON
13546 \     MOV @IP+,PC                 \
13547 \ ENDCODE
13548 \     \
13549
13550 \ CODE LCD_RdS                    \ -- status       Read Status
13551 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
13552 \     JMP LCD_R
13553 \ ENDCODE
13554 \     \
13555
13556 \ CODE LCD_RdC                    \ -- char         Read Char
13557 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
13558 \     JMP LCD_R
13559 \ ENDCODE
13560 \     \
13561
13562 \ -------------+------+------+------+------++---+---+---+---+---------+
13563 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
13564 \ -------------+------+------+------+------++---+---+---+---+---------+
13565 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
13566 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
13567 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
13568 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
13569 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
13570 \ -------------+------+------+------+------++---+---+---+---+---------+
13571
13572
13573 \ ******************************\
13574 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
13575 \ ******************************\
13576 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
13577 \ ------------------------------\
13578 \ define LPM mode for ACCEPT    \
13579 \ ------------------------------\
13580 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
13581 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
13582 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
13583 BIT.B #SW2,&SW2_IN              \ test switch S2
13584 0= IF                           \ case of switch S2 pressed
13585     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
13586     U< IF
13587         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
13588     THEN
13589 ELSE
13590     BIT.B #SW1,&SW1_IN          \ test switch S1 input
13591     0= IF                       \ case of Switch S1 pressed
13592         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
13593         U>= IF                  \
13594             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
13595         THEN                    \
13596     THEN                        \
13597 THEN                            \
13598 RETI                            \ CPU is ON, GIE is OFF
13599 ENDASM                          \
13600     \
13601
13602
13603 \ ------------------------------\
13604 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
13605 \ ******************************\
13606 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
13607 \ ******************************\
13608 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
13609 \                               \       SMclock = 8|16|24 MHz
13610 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
13611 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
13612 \                               \       SR(9)=new Toggle bit memory (ADD on)
13613 \ ------------------------------\
13614 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
13615 \ ------------------------------\
13616 \ define LPM mode for ACCEPT    \
13617 \ ------------------------------\
13618 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
13619 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
13620 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
13621 \ ------------------------------\
13622 \ RC5_FirstStartBitHalfCycle:   \
13623 \ ------------------------------\
13624 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
13625 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
13626 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
13627 MOV     #1778,X                 \ RC5_Period in us
13628 MOV     #14,W                   \ count of loop
13629 BEGIN                           \
13630 \ ------------------------------\
13631 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
13632 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
13633     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
13634 \ RC5_Compute_3/4_Period:       \                   |
13635     RRUM    #1,X                \ X=1/2 cycle       |
13636     MOV     X,Y                 \ Y=1/2             ^
13637     RRUM    #1,Y                \ Y=1/4
13638     ADD     X,Y                 \ Y=3/4
13639 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
13640     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
13641     0= UNTIL                    \
13642 \ ------------------------------\
13643 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
13644 \ ------------------------------\
13645     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
13646     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
13647     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
13648     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
13649     SUB     #1,W                \ decrement count loop
13650 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
13651 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
13652 0<> WHILE                       \ ----> out of loop ----+
13653 \ RC5_compute_7/4_Time_out:     \                       |
13654     ADD     X,Y                 \                       |   out of bound = 7/4 period 
13655 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
13656     BEGIN                       \                       |
13657         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
13658         0>= IF                  \                       |   if cycle time out of bound
13659             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
13660             RETI                \                       |   then quit to do nothing
13661         THEN                    \                       |
13662 \ ------------------------------\                       |
13663         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
13664     0<> UNTIL                   \                   |   |
13665     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
13666 REPEAT                          \ ----> loop back --+   |
13667 \ ------------------------------\                       |
13668 \ RC5_SampleEndOf:              \ <---------------------+
13669 \ ------------------------------\
13670 BIC     #$30,&TA0CTL           \ stop timer_A0
13671 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
13672 \ ******************************\
13673 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
13674 \ ******************************\
13675 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
13676 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
13677 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
13678 BIT     #BIT13,X                \ X(13) = New_RC5_command
13679 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
13680 THEN                            \
13681 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
13682 \ ******************************\
13683 \ RC5_ComputeNewRC5word         \
13684 \ ******************************\
13685 SUB     #4,PSP                  \
13686 MOV     &BASE,2(PSP)            \ save variable BASE before use
13687 MOV     TOS,0(PSP)              \ save TOS before use
13688 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
13689 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
13690 \ ******************************\
13691 \ RC5_ComputeC6bit              \
13692 \ ******************************\
13693 BIT     #$4000,IP              \ test /C6 bit in IP
13694 0= IF   BIS #$40,TOS           \ set C6 bit in S
13695 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
13696 \ ******************************\
13697 \ RC5_CommandByteIsDone         \ RC5_code --
13698 \ ******************************\
13699
13700 \ ------------------------------\
13701 \ Display IR_RC5 code           \
13702 \ ------------------------------\
13703 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
13704 \ ------------------------------\
13705 LO2HI                           \ switch from assembler to FORTH
13706     ['] LCD_CLEAR IS CR         \ redirects CR
13707     ['] LCD_WrC  IS EMIT        \ redirects EMIT
13708     $10 BASE !                 \ change BASE to hexadecimal
13709     CR ." $" 2 U.R             \ print IR_RC5 code
13710     ['] (CR) IS CR              \ restore CR
13711     ['] (EMIT) IS EMIT          \ restore EMIT
13712 HI2LO                           \ switch from FORTH to assembler
13713 \ ------------------------------\
13714 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
13715 \ ------------------------------\
13716 MOV @PSP+,&BASE                 \ restore variable BASE
13717 RETI                            \ CPU is ON, GIE is OFF
13718 ENDASM                          \
13719     \ 
13720
13721 CODE START                      \
13722 \ ------------------------------\
13723 \ TB0CTL = %0000 0010 1001 0100\$3C0
13724 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
13725 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
13726 \                      --       \ID input divider \ 10 = /4
13727 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
13728 \                            -  \TBCLR TimerB Clear
13729 \                             - \TBIE
13730 \                              -\TBIFG
13731 \ --------------------------------\\
13732 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
13733 \              --                 \CM Capture Mode
13734 \                --               \CCIS
13735 \                   -             \SCS
13736 \                    --           \CLLD
13737 \                      -          \CAP
13738 \                        ---      \OUTMOD \ 011 = set/reset
13739 \                           -     \CCIE
13740 \                             -   \CCI
13741 \                              -  \OUT
13742 \                               - \COV
13743 \                                -\CCIFG
13744 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
13745 \ TB0EX0                          \$3E0 
13746 \ ------------------------------\
13747 \ set TimerB to make 50kHz PWM  \
13748 \ ------------------------------\
13749 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
13750 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
13751 \ ------------------------------\
13752 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
13753 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
13754 \ ------------------------------\
13755     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
13756     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
13757 \ ------------------------------\
13758 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
13759 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
13760 \ ------------------------------\
13761 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
13762 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
13763 \ ------------------------------\
13764     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
13765 \ ------------------------------\
13766 \ set TimerB to generate PWM for LCD_Vo
13767 \ ------------------------------\
13768     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
13769 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
13770     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
13771 \ ------------------------------\
13772     BIS.B #LCDVo,&LCDVo_DIR     \
13773     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
13774 \ ------------------------------\
13775     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
13776     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
13777 \ ------------------------------\
13778     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
13779     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
13780 \ ------------------------------\
13781 \ WDT interval init part        \
13782 \ ------------------------------\
13783     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
13784 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
13785 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
13786     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
13787 \ ------------------------------\
13788 \ init RC5_Int                  \
13789 \ ------------------------------\
13790     BIS.B #RC5,&IR_IE           \ enable RC5_Int
13791     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
13792 \ ------------------------------\
13793 \ init interrupt vectors
13794 \ ------------------------------\
13795     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
13796     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
13797 \ ------------------------------\
13798 \ define LPM mode for ACCEPT    \
13799 \ ------------------------------\
13800 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
13801 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
13802 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
13803
13804 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
13805
13806 \ ------------------------------\
13807 \ Init LCD 2x20                 \
13808 \ ------------------------------\
13809     $03E8 20_US                \ 1-  wait 20 ms
13810     $03 TOP_LCD                \ 2- send DB5=DB4=1
13811     $CD 20_US                  \ 3- wait 4,1 ms
13812     $03 TOP_LCD                \ 4- send again DB5=DB4=1
13813     $5 20_US                   \ 5- wait 0,1 ms
13814     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
13815     $2 20_US                   \    wait 40 us = LCD cycle
13816     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
13817     $2 20_US                   \    wait 40 us = LCD cycle
13818     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
13819     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
13820     LCD_Clear                   \ 10- "LCD_Clear"
13821     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
13822     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
13823     LCD_Clear                   \ 10- "LCD_Clear"
13824     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
13825     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
13826     CR ." I love you"   
13827     ['] (CR) IS CR              \ ' (CR) is CR
13828     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
13829     CR
13830     ."    RC5toLCD is running. Type STOP to quit"
13831 \    NOECHO                      \ uncomment to run this app without terminal connexion
13832     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
13833     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
13834 ;
13835     \
13836
13837 : STOP                  \ stops multitasking, must to be used before downloading app
13838     ['] (WARM) IS WARM  \ remove START app from FORTH init process
13839     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
13840 ;
13841     \
13842
13843
13844 RST_STATE   ;
13845
13846
13847 CODE MAX    \    n1 n2 -- n3       signed maximum
13848             CMP     @PSP,TOS    \ n2-n1
13849             S<      ?GOTO FW1   \ n2<n1
13850 BW1         ADD     #2,PSP
13851             MOV     @IP+,PC
13852 ENDCODE
13853     \
13854
13855 CODE MIN    \    n1 n2 -- n3       signed minimum
13856             CMP     @PSP,TOS     \ n2-n1
13857             S<      ?GOTO BW1    \ n2<n1
13858 FW1         MOV     @PSP+,TOS
13859             MOV     @IP+,PC
13860 ENDCODE
13861     \
13862
13863 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
13864   >R  <# 0 # #S #>  
13865   R> OVER - 0 MAX SPACES TYPE
13866 ;
13867     \
13868
13869 CODE 20_US                      \ n --      n * 20 us
13870 BEGIN                           \ 3 cycles loop + 6~  
13871 \    MOV     #5,W                \ 3 MCLK = 1 MHz
13872 \    MOV     #23,W               \ 3 MCLK = 4 MHz
13873     MOV     #51,W               \ 3 MCLK = 8 MHz
13874 \    MOV     #104,W              \ 3 MCLK = 16 MHz
13875 \    MOV     #158,W              \ 3 MCLK = 24 MHz
13876     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
13877         SUB #1,W                \ 1
13878     0= UNTIL                    \ 2
13879     SUB     #1,TOS              \ 1
13880 0= UNTIL                        \ 2
13881     MOV     @PSP+,TOS           \ 2
13882     MOV     @IP+,PC             \ 4
13883 ENDCODE
13884     \
13885
13886 CODE TOP_LCD                    \ LCD Sample
13887 \                               \ if write : %xxxxWWWW --
13888 \                               \ if read  : -- %0000RRRR
13889     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
13890     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
13891 0= IF                           \ write LCD bits pattern
13892     AND.B #LCD_DB,TOS           \ 
13893     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
13894     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
13895     MOV @PSP+,TOS               \
13896     MOV @IP+,PC
13897 THEN                            \ read LCD bits pattern
13898     SUB #2,PSP
13899     MOV TOS,0(PSP)
13900     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
13901     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
13902     AND.B #LCD_DB,TOS           \
13903     MOV @IP+,PC
13904 ENDCODE
13905     \
13906
13907 CODE LCD_W                      \ byte --       write byte to LCD 
13908     SUB #2,PSP                  \
13909     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
13910     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
13911     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
13912     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
13913 COLON                           \ high level word starts here 
13914     TOP_LCD 2 20_US             \ write high nibble first
13915     TOP_LCD 2 20_US 
13916 ;
13917     \
13918
13919 CODE LCD_WrC                    \ char --         Write Char
13920     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
13921     JMP LCD_W 
13922 ENDCODE
13923     \
13924
13925 CODE LCD_WrF                    \ func --         Write Fonction
13926     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
13927     JMP LCD_W 
13928 ENDCODE
13929     \
13930
13931 : LCD_Clear 
13932     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
13933 ;
13934     \
13935
13936 : LCD_Home 
13937     $02 LCD_WrF 100 20_us 
13938 ;
13939     \
13940
13941 \ : LCD_Entry_set       $04 OR LCD_WrF ;
13942
13943 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
13944
13945 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
13946
13947 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
13948
13949 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
13950
13951 \ : LCD_Goto            $80 OR LCD_WrF ;
13952
13953 \ CODE LCD_R                      \ -- byte       read byte from LCD
13954 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
13955 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
13956 \ COLON                           \ starts a FORTH word
13957 \     TOP_LCD 2 20_us             \ -- %0000HHHH
13958 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
13959 \ HI2LO                           \ switch from FORTH to assembler
13960 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
13961 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
13962 \     MOV @RSP+,IP                \ restore IP saved by COLON
13963 \     MOV @IP+,PC                 \
13964 \ ENDCODE
13965 \     \
13966
13967 \ CODE LCD_RdS                    \ -- status       Read Status
13968 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
13969 \     JMP LCD_R
13970 \ ENDCODE
13971 \     \
13972
13973 \ CODE LCD_RdC                    \ -- char         Read Char
13974 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
13975 \     JMP LCD_R
13976 \ ENDCODE
13977 \     \
13978
13979 \ -------------+------+------+------+------++---+---+---+---+---------+
13980 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
13981 \ -------------+------+------+------+------++---+---+---+---+---------+
13982 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
13983 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
13984 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
13985 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
13986 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
13987 \ -------------+------+------+------+------++---+---+---+---+---------+
13988
13989
13990 \ ******************************\
13991 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
13992 \ ******************************\
13993 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
13994 \ ------------------------------\
13995 \ define LPM mode for ACCEPT    \
13996 \ ------------------------------\
13997 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
13998 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
13999 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
14000 BIT.B #SW2,&SW2_IN              \ test switch S2
14001 0= IF                           \ case of switch S2 pressed
14002     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
14003     U< IF
14004         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
14005     THEN
14006 ELSE
14007     BIT.B #SW1,&SW1_IN          \ test switch S1 input
14008     0= IF                       \ case of Switch S1 pressed
14009         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
14010         U>= IF                  \
14011             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
14012         THEN                    \
14013     THEN                        \
14014 THEN                            \
14015 RETI                            \ CPU is ON, GIE is OFF
14016 ENDASM                          \
14017     \
14018
14019
14020 \ ------------------------------\
14021 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
14022 \ ******************************\
14023 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
14024 \ ******************************\
14025 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
14026 \                               \       SMclock = 8|16|24 MHz
14027 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
14028 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
14029 \                               \       SR(9)=new Toggle bit memory (ADD on)
14030 \ ------------------------------\
14031 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
14032 \ ------------------------------\
14033 \ define LPM mode for ACCEPT    \
14034 \ ------------------------------\
14035 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
14036 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
14037 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
14038 \ ------------------------------\
14039 \ RC5_FirstStartBitHalfCycle:   \
14040 \ ------------------------------\
14041 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
14042 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
14043 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
14044 MOV     #1778,X                 \ RC5_Period in us
14045 MOV     #14,W                   \ count of loop
14046 BEGIN                           \
14047 \ ------------------------------\
14048 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
14049 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
14050     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
14051 \ RC5_Compute_3/4_Period:       \                   |
14052     RRUM    #1,X                \ X=1/2 cycle       |
14053     MOV     X,Y                 \ Y=1/2             ^
14054     RRUM    #1,Y                \ Y=1/4
14055     ADD     X,Y                 \ Y=3/4
14056 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
14057     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
14058     0= UNTIL                    \
14059 \ ------------------------------\
14060 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
14061 \ ------------------------------\
14062     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
14063     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
14064     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
14065     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
14066     SUB     #1,W                \ decrement count loop
14067 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
14068 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
14069 0<> WHILE                       \ ----> out of loop ----+
14070 \ RC5_compute_7/4_Time_out:     \                       |
14071     ADD     X,Y                 \                       |   out of bound = 7/4 period 
14072 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
14073     BEGIN                       \                       |
14074         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
14075         0>= IF                  \                       |   if cycle time out of bound
14076             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
14077             RETI                \                       |   then quit to do nothing
14078         THEN                    \                       |
14079 \ ------------------------------\                       |
14080         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
14081     0<> UNTIL                   \                   |   |
14082     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
14083 REPEAT                          \ ----> loop back --+   |
14084 \ ------------------------------\                       |
14085 \ RC5_SampleEndOf:              \ <---------------------+
14086 \ ------------------------------\
14087 BIC     #$30,&TA0CTL           \ stop timer_A0
14088 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
14089 \ ******************************\
14090 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
14091 \ ******************************\
14092 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
14093 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
14094 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
14095 BIT     #BIT13,X                \ X(13) = New_RC5_command
14096 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
14097 THEN                            \
14098 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
14099 \ ******************************\
14100 \ RC5_ComputeNewRC5word         \
14101 \ ******************************\
14102 SUB     #4,PSP                  \
14103 MOV     &BASE,2(PSP)            \ save variable BASE before use
14104 MOV     TOS,0(PSP)              \ save TOS before use
14105 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
14106 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
14107 \ ******************************\
14108 \ RC5_ComputeC6bit              \
14109 \ ******************************\
14110 BIT     #$4000,IP              \ test /C6 bit in IP
14111 0= IF   BIS #$40,TOS           \ set C6 bit in S
14112 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
14113 \ ******************************\
14114 \ RC5_CommandByteIsDone         \ RC5_code --
14115 \ ******************************\
14116
14117 \ ------------------------------\
14118 \ Display IR_RC5 code           \
14119 \ ------------------------------\
14120 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
14121 \ ------------------------------\
14122 LO2HI                           \ switch from assembler to FORTH
14123     ['] LCD_CLEAR IS CR         \ redirects CR
14124     ['] LCD_WrC  IS EMIT        \ redirects EMIT
14125     $10 BASE !                 \ change BASE to hexadecimal
14126     CR ." $" 2 U.R             \ print IR_RC5 code
14127     ['] (CR) IS CR              \ restore CR
14128     ['] (EMIT) IS EMIT          \ restore EMIT
14129 HI2LO                           \ switch from FORTH to assembler
14130 \ ------------------------------\
14131 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
14132 \ ------------------------------\
14133 MOV @PSP+,&BASE                 \ restore variable BASE
14134 RETI                            \ CPU is ON, GIE is OFF
14135 ENDASM                          \
14136     \ 
14137
14138 CODE START                      \
14139 \ ------------------------------\
14140 \ TB0CTL = %0000 0010 1001 0100\$3C0
14141 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
14142 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
14143 \                      --       \ID input divider \ 10 = /4
14144 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
14145 \                            -  \TBCLR TimerB Clear
14146 \                             - \TBIE
14147 \                              -\TBIFG
14148 \ --------------------------------\\
14149 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
14150 \              --                 \CM Capture Mode
14151 \                --               \CCIS
14152 \                   -             \SCS
14153 \                    --           \CLLD
14154 \                      -          \CAP
14155 \                        ---      \OUTMOD \ 011 = set/reset
14156 \                           -     \CCIE
14157 \                             -   \CCI
14158 \                              -  \OUT
14159 \                               - \COV
14160 \                                -\CCIFG
14161 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
14162 \ TB0EX0                          \$3E0 
14163 \ ------------------------------\
14164 \ set TimerB to make 50kHz PWM  \
14165 \ ------------------------------\
14166 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
14167 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
14168 \ ------------------------------\
14169 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
14170 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
14171 \ ------------------------------\
14172     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
14173     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
14174 \ ------------------------------\
14175 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
14176 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
14177 \ ------------------------------\
14178 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
14179 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
14180 \ ------------------------------\
14181     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
14182 \ ------------------------------\
14183 \ set TimerB to generate PWM for LCD_Vo
14184 \ ------------------------------\
14185     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
14186 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
14187     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
14188 \ ------------------------------\
14189     BIS.B #LCDVo,&LCDVo_DIR     \
14190     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
14191 \ ------------------------------\
14192     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
14193     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
14194 \ ------------------------------\
14195     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
14196     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
14197 \ ------------------------------\
14198 \ WDT interval init part        \
14199 \ ------------------------------\
14200     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
14201 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
14202 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
14203     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
14204 \ ------------------------------\
14205 \ init RC5_Int                  \
14206 \ ------------------------------\
14207     BIS.B #RC5,&IR_IE           \ enable RC5_Int
14208     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
14209 \ ------------------------------\
14210 \ init interrupt vectors
14211 \ ------------------------------\
14212     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
14213     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
14214 \ ------------------------------\
14215 \ define LPM mode for ACCEPT    \
14216 \ ------------------------------\
14217 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
14218 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
14219 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
14220
14221 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
14222
14223 \ ------------------------------\
14224 \ Init LCD 2x20                 \
14225 \ ------------------------------\
14226     $03E8 20_US                \ 1-  wait 20 ms
14227     $03 TOP_LCD                \ 2- send DB5=DB4=1
14228     $CD 20_US                  \ 3- wait 4,1 ms
14229     $03 TOP_LCD                \ 4- send again DB5=DB4=1
14230     $5 20_US                   \ 5- wait 0,1 ms
14231     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
14232     $2 20_US                   \    wait 40 us = LCD cycle
14233     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
14234     $2 20_US                   \    wait 40 us = LCD cycle
14235     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
14236     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
14237     LCD_Clear                   \ 10- "LCD_Clear"
14238     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
14239     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
14240     LCD_Clear                   \ 10- "LCD_Clear"
14241     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
14242     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
14243     CR ." I love you"   
14244     ['] (CR) IS CR              \ ' (CR) is CR
14245     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
14246     CR
14247     ."    RC5toLCD is running. Type STOP to quit"
14248 \    NOECHO                      \ uncomment to run this app without terminal connexion
14249     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
14250     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
14251 ;
14252     \
14253
14254 : STOP                  \ stops multitasking, must to be used before downloading app
14255     ['] (WARM) IS WARM  \ remove START app from FORTH init process
14256     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
14257 ;
14258     \
14259
14260
14261 RST_STATE   ;
14262
14263
14264 CODE MAX    \    n1 n2 -- n3       signed maximum
14265             CMP     @PSP,TOS    \ n2-n1
14266             S<      ?GOTO FW1   \ n2<n1
14267 BW1         ADD     #2,PSP
14268             MOV     @IP+,PC
14269 ENDCODE
14270     \
14271
14272 CODE MIN    \    n1 n2 -- n3       signed minimum
14273             CMP     @PSP,TOS     \ n2-n1
14274             S<      ?GOTO BW1    \ n2<n1
14275 FW1         MOV     @PSP+,TOS
14276             MOV     @IP+,PC
14277 ENDCODE
14278     \
14279
14280 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
14281   >R  <# 0 # #S #>  
14282   R> OVER - 0 MAX SPACES TYPE
14283 ;
14284     \
14285
14286 CODE 20_US                      \ n --      n * 20 us
14287 BEGIN                           \ 3 cycles loop + 6~  
14288 \    MOV     #5,W                \ 3 MCLK = 1 MHz
14289 \    MOV     #23,W               \ 3 MCLK = 4 MHz
14290     MOV     #51,W               \ 3 MCLK = 8 MHz
14291 \    MOV     #104,W              \ 3 MCLK = 16 MHz
14292 \    MOV     #158,W              \ 3 MCLK = 24 MHz
14293     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
14294         SUB #1,W                \ 1
14295     0= UNTIL                    \ 2
14296     SUB     #1,TOS              \ 1
14297 0= UNTIL                        \ 2
14298     MOV     @PSP+,TOS           \ 2
14299     MOV     @IP+,PC             \ 4
14300 ENDCODE
14301     \
14302
14303 CODE TOP_LCD                    \ LCD Sample
14304 \                               \ if write : %xxxxWWWW --
14305 \                               \ if read  : -- %0000RRRR
14306     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
14307     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
14308 0= IF                           \ write LCD bits pattern
14309     AND.B #LCD_DB,TOS           \ 
14310     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
14311     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
14312     MOV @PSP+,TOS               \
14313     MOV @IP+,PC
14314 THEN                            \ read LCD bits pattern
14315     SUB #2,PSP
14316     MOV TOS,0(PSP)
14317     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
14318     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
14319     AND.B #LCD_DB,TOS           \
14320     MOV @IP+,PC
14321 ENDCODE
14322     \
14323
14324 CODE LCD_W                      \ byte --       write byte to LCD 
14325     SUB #2,PSP                  \
14326     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
14327     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
14328     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
14329     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
14330 COLON                           \ high level word starts here 
14331     TOP_LCD 2 20_US             \ write high nibble first
14332     TOP_LCD 2 20_US 
14333 ;
14334     \
14335
14336 CODE LCD_WrC                    \ char --         Write Char
14337     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
14338     JMP LCD_W 
14339 ENDCODE
14340     \
14341
14342 CODE LCD_WrF                    \ func --         Write Fonction
14343     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
14344     JMP LCD_W 
14345 ENDCODE
14346     \
14347
14348 : LCD_Clear 
14349     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
14350 ;
14351     \
14352
14353 : LCD_Home 
14354     $02 LCD_WrF 100 20_us 
14355 ;
14356     \
14357
14358 \ : LCD_Entry_set       $04 OR LCD_WrF ;
14359
14360 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
14361
14362 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
14363
14364 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
14365
14366 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
14367
14368 \ : LCD_Goto            $80 OR LCD_WrF ;
14369
14370 \ CODE LCD_R                      \ -- byte       read byte from LCD
14371 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
14372 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
14373 \ COLON                           \ starts a FORTH word
14374 \     TOP_LCD 2 20_us             \ -- %0000HHHH
14375 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
14376 \ HI2LO                           \ switch from FORTH to assembler
14377 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
14378 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
14379 \     MOV @RSP+,IP                \ restore IP saved by COLON
14380 \     MOV @IP+,PC                 \
14381 \ ENDCODE
14382 \     \
14383
14384 \ CODE LCD_RdS                    \ -- status       Read Status
14385 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
14386 \     JMP LCD_R
14387 \ ENDCODE
14388 \     \
14389
14390 \ CODE LCD_RdC                    \ -- char         Read Char
14391 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
14392 \     JMP LCD_R
14393 \ ENDCODE
14394 \     \
14395
14396 \ -------------+------+------+------+------++---+---+---+---+---------+
14397 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
14398 \ -------------+------+------+------+------++---+---+---+---+---------+
14399 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
14400 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
14401 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
14402 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
14403 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
14404 \ -------------+------+------+------+------++---+---+---+---+---------+
14405
14406
14407 \ ******************************\
14408 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
14409 \ ******************************\
14410 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
14411 \ ------------------------------\
14412 \ define LPM mode for ACCEPT    \
14413 \ ------------------------------\
14414 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
14415 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
14416 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
14417 BIT.B #SW2,&SW2_IN              \ test switch S2
14418 0= IF                           \ case of switch S2 pressed
14419     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
14420     U< IF
14421         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
14422     THEN
14423 ELSE
14424     BIT.B #SW1,&SW1_IN          \ test switch S1 input
14425     0= IF                       \ case of Switch S1 pressed
14426         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
14427         U>= IF                  \
14428             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
14429         THEN                    \
14430     THEN                        \
14431 THEN                            \
14432 RETI                            \ CPU is ON, GIE is OFF
14433 ENDASM                          \
14434     \
14435
14436
14437 \ ------------------------------\
14438 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
14439 \ ******************************\
14440 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
14441 \ ******************************\
14442 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
14443 \                               \       SMclock = 8|16|24 MHz
14444 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
14445 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
14446 \                               \       SR(9)=new Toggle bit memory (ADD on)
14447 \ ------------------------------\
14448 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
14449 \ ------------------------------\
14450 \ define LPM mode for ACCEPT    \
14451 \ ------------------------------\
14452 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
14453 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
14454 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
14455 \ ------------------------------\
14456 \ RC5_FirstStartBitHalfCycle:   \
14457 \ ------------------------------\
14458 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
14459 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
14460 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
14461 MOV     #1778,X                 \ RC5_Period in us
14462 MOV     #14,W                   \ count of loop
14463 BEGIN                           \
14464 \ ------------------------------\
14465 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
14466 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
14467     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
14468 \ RC5_Compute_3/4_Period:       \                   |
14469     RRUM    #1,X                \ X=1/2 cycle       |
14470     MOV     X,Y                 \ Y=1/2             ^
14471     RRUM    #1,Y                \ Y=1/4
14472     ADD     X,Y                 \ Y=3/4
14473 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
14474     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
14475     0= UNTIL                    \
14476 \ ------------------------------\
14477 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
14478 \ ------------------------------\
14479     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
14480     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
14481     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
14482     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
14483     SUB     #1,W                \ decrement count loop
14484 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
14485 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
14486 0<> WHILE                       \ ----> out of loop ----+
14487 \ RC5_compute_7/4_Time_out:     \                       |
14488     ADD     X,Y                 \                       |   out of bound = 7/4 period 
14489 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
14490     BEGIN                       \                       |
14491         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
14492         0>= IF                  \                       |   if cycle time out of bound
14493             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
14494             RETI                \                       |   then quit to do nothing
14495         THEN                    \                       |
14496 \ ------------------------------\                       |
14497         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
14498     0<> UNTIL                   \                   |   |
14499     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
14500 REPEAT                          \ ----> loop back --+   |
14501 \ ------------------------------\                       |
14502 \ RC5_SampleEndOf:              \ <---------------------+
14503 \ ------------------------------\
14504 BIC     #$30,&TA0CTL           \ stop timer_A0
14505 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
14506 \ ******************************\
14507 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
14508 \ ******************************\
14509 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
14510 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
14511 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
14512 BIT     #BIT13,X                \ X(13) = New_RC5_command
14513 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
14514 THEN                            \
14515 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
14516 \ ******************************\
14517 \ RC5_ComputeNewRC5word         \
14518 \ ******************************\
14519 SUB     #4,PSP                  \
14520 MOV     &BASE,2(PSP)            \ save variable BASE before use
14521 MOV     TOS,0(PSP)              \ save TOS before use
14522 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
14523 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
14524 \ ******************************\
14525 \ RC5_ComputeC6bit              \
14526 \ ******************************\
14527 BIT     #$4000,IP              \ test /C6 bit in IP
14528 0= IF   BIS #$40,TOS           \ set C6 bit in S
14529 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
14530 \ ******************************\
14531 \ RC5_CommandByteIsDone         \ RC5_code --
14532 \ ******************************\
14533
14534 \ ------------------------------\
14535 \ Display IR_RC5 code           \
14536 \ ------------------------------\
14537 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
14538 \ ------------------------------\
14539 LO2HI                           \ switch from assembler to FORTH
14540     ['] LCD_CLEAR IS CR         \ redirects CR
14541     ['] LCD_WrC  IS EMIT        \ redirects EMIT
14542     $10 BASE !                 \ change BASE to hexadecimal
14543     CR ." $" 2 U.R             \ print IR_RC5 code
14544     ['] (CR) IS CR              \ restore CR
14545     ['] (EMIT) IS EMIT          \ restore EMIT
14546 HI2LO                           \ switch from FORTH to assembler
14547 \ ------------------------------\
14548 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
14549 \ ------------------------------\
14550 MOV @PSP+,&BASE                 \ restore variable BASE
14551 RETI                            \ CPU is ON, GIE is OFF
14552 ENDASM                          \
14553     \ 
14554
14555 CODE START                      \
14556 \ ------------------------------\
14557 \ TB0CTL = %0000 0010 1001 0100\$3C0
14558 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
14559 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
14560 \                      --       \ID input divider \ 10 = /4
14561 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
14562 \                            -  \TBCLR TimerB Clear
14563 \                             - \TBIE
14564 \                              -\TBIFG
14565 \ --------------------------------\\
14566 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
14567 \              --                 \CM Capture Mode
14568 \                --               \CCIS
14569 \                   -             \SCS
14570 \                    --           \CLLD
14571 \                      -          \CAP
14572 \                        ---      \OUTMOD \ 011 = set/reset
14573 \                           -     \CCIE
14574 \                             -   \CCI
14575 \                              -  \OUT
14576 \                               - \COV
14577 \                                -\CCIFG
14578 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
14579 \ TB0EX0                          \$3E0 
14580 \ ------------------------------\
14581 \ set TimerB to make 50kHz PWM  \
14582 \ ------------------------------\
14583 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
14584 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
14585 \ ------------------------------\
14586 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
14587 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
14588 \ ------------------------------\
14589     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
14590     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
14591 \ ------------------------------\
14592 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
14593 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
14594 \ ------------------------------\
14595 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
14596 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
14597 \ ------------------------------\
14598     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
14599 \ ------------------------------\
14600 \ set TimerB to generate PWM for LCD_Vo
14601 \ ------------------------------\
14602     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
14603 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
14604     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
14605 \ ------------------------------\
14606     BIS.B #LCDVo,&LCDVo_DIR     \
14607     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
14608 \ ------------------------------\
14609     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
14610     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
14611 \ ------------------------------\
14612     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
14613     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
14614 \ ------------------------------\
14615 \ WDT interval init part        \
14616 \ ------------------------------\
14617     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
14618 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
14619 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
14620     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
14621 \ ------------------------------\
14622 \ init RC5_Int                  \
14623 \ ------------------------------\
14624     BIS.B #RC5,&IR_IE           \ enable RC5_Int
14625     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
14626 \ ------------------------------\
14627 \ init interrupt vectors
14628 \ ------------------------------\
14629     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
14630     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
14631 \ ------------------------------\
14632 \ define LPM mode for ACCEPT    \
14633 \ ------------------------------\
14634 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
14635 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
14636 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
14637
14638 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
14639
14640 \ ------------------------------\
14641 \ Init LCD 2x20                 \
14642 \ ------------------------------\
14643     $03E8 20_US                \ 1-  wait 20 ms
14644     $03 TOP_LCD                \ 2- send DB5=DB4=1
14645     $CD 20_US                  \ 3- wait 4,1 ms
14646     $03 TOP_LCD                \ 4- send again DB5=DB4=1
14647     $5 20_US                   \ 5- wait 0,1 ms
14648     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
14649     $2 20_US                   \    wait 40 us = LCD cycle
14650     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
14651     $2 20_US                   \    wait 40 us = LCD cycle
14652     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
14653     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
14654     LCD_Clear                   \ 10- "LCD_Clear"
14655     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
14656     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
14657     LCD_Clear                   \ 10- "LCD_Clear"
14658     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
14659     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
14660     CR ." I love you"   
14661     ['] (CR) IS CR              \ ' (CR) is CR
14662     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
14663     CR
14664     ."    RC5toLCD is running. Type STOP to quit"
14665 \    NOECHO                      \ uncomment to run this app without terminal connexion
14666     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
14667     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
14668 ;
14669     \
14670
14671 : STOP                  \ stops multitasking, must to be used before downloading app
14672     ['] (WARM) IS WARM  \ remove START app from FORTH init process
14673     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
14674 ;
14675     \
14676
14677
14678 RST_STATE   ;
14679
14680
14681 CODE MAX    \    n1 n2 -- n3       signed maximum
14682             CMP     @PSP,TOS    \ n2-n1
14683             S<      ?GOTO FW1   \ n2<n1
14684 BW1         ADD     #2,PSP
14685             MOV     @IP+,PC
14686 ENDCODE
14687     \
14688
14689 CODE MIN    \    n1 n2 -- n3       signed minimum
14690             CMP     @PSP,TOS     \ n2-n1
14691             S<      ?GOTO BW1    \ n2<n1
14692 FW1         MOV     @PSP+,TOS
14693             MOV     @IP+,PC
14694 ENDCODE
14695     \
14696
14697 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
14698   >R  <# 0 # #S #>  
14699   R> OVER - 0 MAX SPACES TYPE
14700 ;
14701     \
14702
14703 CODE 20_US                      \ n --      n * 20 us
14704 BEGIN                           \ 3 cycles loop + 6~  
14705 \    MOV     #5,W                \ 3 MCLK = 1 MHz
14706 \    MOV     #23,W               \ 3 MCLK = 4 MHz
14707     MOV     #51,W               \ 3 MCLK = 8 MHz
14708 \    MOV     #104,W              \ 3 MCLK = 16 MHz
14709 \    MOV     #158,W              \ 3 MCLK = 24 MHz
14710     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
14711         SUB #1,W                \ 1
14712     0= UNTIL                    \ 2
14713     SUB     #1,TOS              \ 1
14714 0= UNTIL                        \ 2
14715     MOV     @PSP+,TOS           \ 2
14716     MOV     @IP+,PC             \ 4
14717 ENDCODE
14718     \
14719
14720 CODE TOP_LCD                    \ LCD Sample
14721 \                               \ if write : %xxxxWWWW --
14722 \                               \ if read  : -- %0000RRRR
14723     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
14724     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
14725 0= IF                           \ write LCD bits pattern
14726     AND.B #LCD_DB,TOS           \ 
14727     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
14728     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
14729     MOV @PSP+,TOS               \
14730     MOV @IP+,PC
14731 THEN                            \ read LCD bits pattern
14732     SUB #2,PSP
14733     MOV TOS,0(PSP)
14734     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
14735     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
14736     AND.B #LCD_DB,TOS           \
14737     MOV @IP+,PC
14738 ENDCODE
14739     \
14740
14741 CODE LCD_W                      \ byte --       write byte to LCD 
14742     SUB #2,PSP                  \
14743     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
14744     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
14745     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
14746     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
14747 COLON                           \ high level word starts here 
14748     TOP_LCD 2 20_US             \ write high nibble first
14749     TOP_LCD 2 20_US 
14750 ;
14751     \
14752
14753 CODE LCD_WrC                    \ char --         Write Char
14754     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
14755     JMP LCD_W 
14756 ENDCODE
14757     \
14758
14759 CODE LCD_WrF                    \ func --         Write Fonction
14760     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
14761     JMP LCD_W 
14762 ENDCODE
14763     \
14764
14765 : LCD_Clear 
14766     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
14767 ;
14768     \
14769
14770 : LCD_Home 
14771     $02 LCD_WrF 100 20_us 
14772 ;
14773     \
14774
14775 \ : LCD_Entry_set       $04 OR LCD_WrF ;
14776
14777 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
14778
14779 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
14780
14781 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
14782
14783 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
14784
14785 \ : LCD_Goto            $80 OR LCD_WrF ;
14786
14787 \ CODE LCD_R                      \ -- byte       read byte from LCD
14788 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
14789 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
14790 \ COLON                           \ starts a FORTH word
14791 \     TOP_LCD 2 20_us             \ -- %0000HHHH
14792 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
14793 \ HI2LO                           \ switch from FORTH to assembler
14794 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
14795 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
14796 \     MOV @RSP+,IP                \ restore IP saved by COLON
14797 \     MOV @IP+,PC                 \
14798 \ ENDCODE
14799 \     \
14800
14801 \ CODE LCD_RdS                    \ -- status       Read Status
14802 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
14803 \     JMP LCD_R
14804 \ ENDCODE
14805 \     \
14806
14807 \ CODE LCD_RdC                    \ -- char         Read Char
14808 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
14809 \     JMP LCD_R
14810 \ ENDCODE
14811 \     \
14812
14813 \ -------------+------+------+------+------++---+---+---+---+---------+
14814 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
14815 \ -------------+------+------+------+------++---+---+---+---+---------+
14816 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
14817 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
14818 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
14819 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
14820 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
14821 \ -------------+------+------+------+------++---+---+---+---+---------+
14822
14823
14824 \ ******************************\
14825 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
14826 \ ******************************\
14827 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
14828 \ ------------------------------\
14829 \ define LPM mode for ACCEPT    \
14830 \ ------------------------------\
14831 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
14832 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
14833 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
14834 BIT.B #SW2,&SW2_IN              \ test switch S2
14835 0= IF                           \ case of switch S2 pressed
14836     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
14837     U< IF
14838         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
14839     THEN
14840 ELSE
14841     BIT.B #SW1,&SW1_IN          \ test switch S1 input
14842     0= IF                       \ case of Switch S1 pressed
14843         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
14844         U>= IF                  \
14845             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
14846         THEN                    \
14847     THEN                        \
14848 THEN                            \
14849 RETI                            \ CPU is ON, GIE is OFF
14850 ENDASM                          \
14851     \
14852
14853
14854 \ ------------------------------\
14855 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
14856 \ ******************************\
14857 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
14858 \ ******************************\
14859 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
14860 \                               \       SMclock = 8|16|24 MHz
14861 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
14862 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
14863 \                               \       SR(9)=new Toggle bit memory (ADD on)
14864 \ ------------------------------\
14865 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
14866 \ ------------------------------\
14867 \ define LPM mode for ACCEPT    \
14868 \ ------------------------------\
14869 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
14870 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
14871 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
14872 \ ------------------------------\
14873 \ RC5_FirstStartBitHalfCycle:   \
14874 \ ------------------------------\
14875 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
14876 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
14877 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
14878 MOV     #1778,X                 \ RC5_Period in us
14879 MOV     #14,W                   \ count of loop
14880 BEGIN                           \
14881 \ ------------------------------\
14882 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
14883 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
14884     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
14885 \ RC5_Compute_3/4_Period:       \                   |
14886     RRUM    #1,X                \ X=1/2 cycle       |
14887     MOV     X,Y                 \ Y=1/2             ^
14888     RRUM    #1,Y                \ Y=1/4
14889     ADD     X,Y                 \ Y=3/4
14890 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
14891     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
14892     0= UNTIL                    \
14893 \ ------------------------------\
14894 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
14895 \ ------------------------------\
14896     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
14897     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
14898     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
14899     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
14900     SUB     #1,W                \ decrement count loop
14901 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
14902 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
14903 0<> WHILE                       \ ----> out of loop ----+
14904 \ RC5_compute_7/4_Time_out:     \                       |
14905     ADD     X,Y                 \                       |   out of bound = 7/4 period 
14906 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
14907     BEGIN                       \                       |
14908         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
14909         0>= IF                  \                       |   if cycle time out of bound
14910             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
14911             RETI                \                       |   then quit to do nothing
14912         THEN                    \                       |
14913 \ ------------------------------\                       |
14914         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
14915     0<> UNTIL                   \                   |   |
14916     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
14917 REPEAT                          \ ----> loop back --+   |
14918 \ ------------------------------\                       |
14919 \ RC5_SampleEndOf:              \ <---------------------+
14920 \ ------------------------------\
14921 BIC     #$30,&TA0CTL           \ stop timer_A0
14922 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
14923 \ ******************************\
14924 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
14925 \ ******************************\
14926 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
14927 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
14928 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
14929 BIT     #BIT13,X                \ X(13) = New_RC5_command
14930 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
14931 THEN                            \
14932 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
14933 \ ******************************\
14934 \ RC5_ComputeNewRC5word         \
14935 \ ******************************\
14936 SUB     #4,PSP                  \
14937 MOV     &BASE,2(PSP)            \ save variable BASE before use
14938 MOV     TOS,0(PSP)              \ save TOS before use
14939 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
14940 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
14941 \ ******************************\
14942 \ RC5_ComputeC6bit              \
14943 \ ******************************\
14944 BIT     #$4000,IP              \ test /C6 bit in IP
14945 0= IF   BIS #$40,TOS           \ set C6 bit in S
14946 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
14947 \ ******************************\
14948 \ RC5_CommandByteIsDone         \ RC5_code --
14949 \ ******************************\
14950
14951 \ ------------------------------\
14952 \ Display IR_RC5 code           \
14953 \ ------------------------------\
14954 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
14955 \ ------------------------------\
14956 LO2HI                           \ switch from assembler to FORTH
14957     ['] LCD_CLEAR IS CR         \ redirects CR
14958     ['] LCD_WrC  IS EMIT        \ redirects EMIT
14959     $10 BASE !                 \ change BASE to hexadecimal
14960     CR ." $" 2 U.R             \ print IR_RC5 code
14961     ['] (CR) IS CR              \ restore CR
14962     ['] (EMIT) IS EMIT          \ restore EMIT
14963 HI2LO                           \ switch from FORTH to assembler
14964 \ ------------------------------\
14965 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
14966 \ ------------------------------\
14967 MOV @PSP+,&BASE                 \ restore variable BASE
14968 RETI                            \ CPU is ON, GIE is OFF
14969 ENDASM                          \
14970     \ 
14971
14972 CODE START                      \
14973 \ ------------------------------\
14974 \ TB0CTL = %0000 0010 1001 0100\$3C0
14975 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
14976 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
14977 \                      --       \ID input divider \ 10 = /4
14978 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
14979 \                            -  \TBCLR TimerB Clear
14980 \                             - \TBIE
14981 \                              -\TBIFG
14982 \ --------------------------------\\
14983 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
14984 \              --                 \CM Capture Mode
14985 \                --               \CCIS
14986 \                   -             \SCS
14987 \                    --           \CLLD
14988 \                      -          \CAP
14989 \                        ---      \OUTMOD \ 011 = set/reset
14990 \                           -     \CCIE
14991 \                             -   \CCI
14992 \                              -  \OUT
14993 \                               - \COV
14994 \                                -\CCIFG
14995 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
14996 \ TB0EX0                          \$3E0 
14997 \ ------------------------------\
14998 \ set TimerB to make 50kHz PWM  \
14999 \ ------------------------------\
15000 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
15001 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
15002 \ ------------------------------\
15003 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
15004 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
15005 \ ------------------------------\
15006     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
15007     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
15008 \ ------------------------------\
15009 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
15010 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
15011 \ ------------------------------\
15012 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
15013 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
15014 \ ------------------------------\
15015     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
15016 \ ------------------------------\
15017 \ set TimerB to generate PWM for LCD_Vo
15018 \ ------------------------------\
15019     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
15020 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
15021     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
15022 \ ------------------------------\
15023     BIS.B #LCDVo,&LCDVo_DIR     \
15024     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
15025 \ ------------------------------\
15026     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
15027     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
15028 \ ------------------------------\
15029     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
15030     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
15031 \ ------------------------------\
15032 \ WDT interval init part        \
15033 \ ------------------------------\
15034     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
15035 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
15036 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
15037     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
15038 \ ------------------------------\
15039 \ init RC5_Int                  \
15040 \ ------------------------------\
15041     BIS.B #RC5,&IR_IE           \ enable RC5_Int
15042     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
15043 \ ------------------------------\
15044 \ init interrupt vectors
15045 \ ------------------------------\
15046     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
15047     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
15048 \ ------------------------------\
15049 \ define LPM mode for ACCEPT    \
15050 \ ------------------------------\
15051 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
15052 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
15053 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
15054
15055 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
15056
15057 \ ------------------------------\
15058 \ Init LCD 2x20                 \
15059 \ ------------------------------\
15060     $03E8 20_US                \ 1-  wait 20 ms
15061     $03 TOP_LCD                \ 2- send DB5=DB4=1
15062     $CD 20_US                  \ 3- wait 4,1 ms
15063     $03 TOP_LCD                \ 4- send again DB5=DB4=1
15064     $5 20_US                   \ 5- wait 0,1 ms
15065     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
15066     $2 20_US                   \    wait 40 us = LCD cycle
15067     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
15068     $2 20_US                   \    wait 40 us = LCD cycle
15069     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
15070     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
15071     LCD_Clear                   \ 10- "LCD_Clear"
15072     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
15073     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
15074     LCD_Clear                   \ 10- "LCD_Clear"
15075     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
15076     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
15077     CR ." I love you"   
15078     ['] (CR) IS CR              \ ' (CR) is CR
15079     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
15080     CR
15081     ."    RC5toLCD is running. Type STOP to quit"
15082 \    NOECHO                      \ uncomment to run this app without terminal connexion
15083     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
15084     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
15085 ;
15086     \
15087
15088 : STOP                  \ stops multitasking, must to be used before downloading app
15089     ['] (WARM) IS WARM  \ remove START app from FORTH init process
15090     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
15091 ;
15092     \
15093
15094
15095 RST_STATE   ;
15096
15097
15098 CODE MAX    \    n1 n2 -- n3       signed maximum
15099             CMP     @PSP,TOS    \ n2-n1
15100             S<      ?GOTO FW1   \ n2<n1
15101 BW1         ADD     #2,PSP
15102             MOV     @IP+,PC
15103 ENDCODE
15104     \
15105
15106 CODE MIN    \    n1 n2 -- n3       signed minimum
15107             CMP     @PSP,TOS     \ n2-n1
15108             S<      ?GOTO BW1    \ n2<n1
15109 FW1         MOV     @PSP+,TOS
15110             MOV     @IP+,PC
15111 ENDCODE
15112     \
15113
15114 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
15115   >R  <# 0 # #S #>  
15116   R> OVER - 0 MAX SPACES TYPE
15117 ;
15118     \
15119
15120 CODE 20_US                      \ n --      n * 20 us
15121 BEGIN                           \ 3 cycles loop + 6~  
15122 \    MOV     #5,W                \ 3 MCLK = 1 MHz
15123 \    MOV     #23,W               \ 3 MCLK = 4 MHz
15124     MOV     #51,W               \ 3 MCLK = 8 MHz
15125 \    MOV     #104,W              \ 3 MCLK = 16 MHz
15126 \    MOV     #158,W              \ 3 MCLK = 24 MHz
15127     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
15128         SUB #1,W                \ 1
15129     0= UNTIL                    \ 2
15130     SUB     #1,TOS              \ 1
15131 0= UNTIL                        \ 2
15132     MOV     @PSP+,TOS           \ 2
15133     MOV     @IP+,PC             \ 4
15134 ENDCODE
15135     \
15136
15137 CODE TOP_LCD                    \ LCD Sample
15138 \                               \ if write : %xxxxWWWW --
15139 \                               \ if read  : -- %0000RRRR
15140     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
15141     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
15142 0= IF                           \ write LCD bits pattern
15143     AND.B #LCD_DB,TOS           \ 
15144     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
15145     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
15146     MOV @PSP+,TOS               \
15147     MOV @IP+,PC
15148 THEN                            \ read LCD bits pattern
15149     SUB #2,PSP
15150     MOV TOS,0(PSP)
15151     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
15152     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
15153     AND.B #LCD_DB,TOS           \
15154     MOV @IP+,PC
15155 ENDCODE
15156     \
15157
15158 CODE LCD_W                      \ byte --       write byte to LCD 
15159     SUB #2,PSP                  \
15160     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
15161     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
15162     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
15163     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
15164 COLON                           \ high level word starts here 
15165     TOP_LCD 2 20_US             \ write high nibble first
15166     TOP_LCD 2 20_US 
15167 ;
15168     \
15169
15170 CODE LCD_WrC                    \ char --         Write Char
15171     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
15172     JMP LCD_W 
15173 ENDCODE
15174     \
15175
15176 CODE LCD_WrF                    \ func --         Write Fonction
15177     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
15178     JMP LCD_W 
15179 ENDCODE
15180     \
15181
15182 : LCD_Clear 
15183     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
15184 ;
15185     \
15186
15187 : LCD_Home 
15188     $02 LCD_WrF 100 20_us 
15189 ;
15190     \
15191
15192 \ : LCD_Entry_set       $04 OR LCD_WrF ;
15193
15194 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
15195
15196 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
15197
15198 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
15199
15200 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
15201
15202 \ : LCD_Goto            $80 OR LCD_WrF ;
15203
15204 \ CODE LCD_R                      \ -- byte       read byte from LCD
15205 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
15206 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
15207 \ COLON                           \ starts a FORTH word
15208 \     TOP_LCD 2 20_us             \ -- %0000HHHH
15209 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
15210 \ HI2LO                           \ switch from FORTH to assembler
15211 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
15212 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
15213 \     MOV @RSP+,IP                \ restore IP saved by COLON
15214 \     MOV @IP+,PC                 \
15215 \ ENDCODE
15216 \     \
15217
15218 \ CODE LCD_RdS                    \ -- status       Read Status
15219 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
15220 \     JMP LCD_R
15221 \ ENDCODE
15222 \     \
15223
15224 \ CODE LCD_RdC                    \ -- char         Read Char
15225 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
15226 \     JMP LCD_R
15227 \ ENDCODE
15228 \     \
15229
15230 \ -------------+------+------+------+------++---+---+---+---+---------+
15231 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
15232 \ -------------+------+------+------+------++---+---+---+---+---------+
15233 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
15234 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
15235 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
15236 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
15237 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
15238 \ -------------+------+------+------+------++---+---+---+---+---------+
15239
15240
15241 \ ******************************\
15242 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
15243 \ ******************************\
15244 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
15245 \ ------------------------------\
15246 \ define LPM mode for ACCEPT    \
15247 \ ------------------------------\
15248 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
15249 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
15250 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
15251 BIT.B #SW2,&SW2_IN              \ test switch S2
15252 0= IF                           \ case of switch S2 pressed
15253     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
15254     U< IF
15255         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
15256     THEN
15257 ELSE
15258     BIT.B #SW1,&SW1_IN          \ test switch S1 input
15259     0= IF                       \ case of Switch S1 pressed
15260         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
15261         U>= IF                  \
15262             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
15263         THEN                    \
15264     THEN                        \
15265 THEN                            \
15266 RETI                            \ CPU is ON, GIE is OFF
15267 ENDASM                          \
15268     \
15269
15270
15271 \ ------------------------------\
15272 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
15273 \ ******************************\
15274 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
15275 \ ******************************\
15276 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
15277 \                               \       SMclock = 8|16|24 MHz
15278 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
15279 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
15280 \                               \       SR(9)=new Toggle bit memory (ADD on)
15281 \ ------------------------------\
15282 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
15283 \ ------------------------------\
15284 \ define LPM mode for ACCEPT    \
15285 \ ------------------------------\
15286 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
15287 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
15288 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
15289 \ ------------------------------\
15290 \ RC5_FirstStartBitHalfCycle:   \
15291 \ ------------------------------\
15292 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
15293 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
15294 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
15295 MOV     #1778,X                 \ RC5_Period in us
15296 MOV     #14,W                   \ count of loop
15297 BEGIN                           \
15298 \ ------------------------------\
15299 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
15300 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
15301     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
15302 \ RC5_Compute_3/4_Period:       \                   |
15303     RRUM    #1,X                \ X=1/2 cycle       |
15304     MOV     X,Y                 \ Y=1/2             ^
15305     RRUM    #1,Y                \ Y=1/4
15306     ADD     X,Y                 \ Y=3/4
15307 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
15308     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
15309     0= UNTIL                    \
15310 \ ------------------------------\
15311 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
15312 \ ------------------------------\
15313     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
15314     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
15315     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
15316     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
15317     SUB     #1,W                \ decrement count loop
15318 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
15319 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
15320 0<> WHILE                       \ ----> out of loop ----+
15321 \ RC5_compute_7/4_Time_out:     \                       |
15322     ADD     X,Y                 \                       |   out of bound = 7/4 period 
15323 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
15324     BEGIN                       \                       |
15325         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
15326         0>= IF                  \                       |   if cycle time out of bound
15327             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
15328             RETI                \                       |   then quit to do nothing
15329         THEN                    \                       |
15330 \ ------------------------------\                       |
15331         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
15332     0<> UNTIL                   \                   |   |
15333     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
15334 REPEAT                          \ ----> loop back --+   |
15335 \ ------------------------------\                       |
15336 \ RC5_SampleEndOf:              \ <---------------------+
15337 \ ------------------------------\
15338 BIC     #$30,&TA0CTL           \ stop timer_A0
15339 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
15340 \ ******************************\
15341 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
15342 \ ******************************\
15343 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
15344 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
15345 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
15346 BIT     #BIT13,X                \ X(13) = New_RC5_command
15347 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
15348 THEN                            \
15349 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
15350 \ ******************************\
15351 \ RC5_ComputeNewRC5word         \
15352 \ ******************************\
15353 SUB     #4,PSP                  \
15354 MOV     &BASE,2(PSP)            \ save variable BASE before use
15355 MOV     TOS,0(PSP)              \ save TOS before use
15356 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
15357 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
15358 \ ******************************\
15359 \ RC5_ComputeC6bit              \
15360 \ ******************************\
15361 BIT     #$4000,IP              \ test /C6 bit in IP
15362 0= IF   BIS #$40,TOS           \ set C6 bit in S
15363 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
15364 \ ******************************\
15365 \ RC5_CommandByteIsDone         \ RC5_code --
15366 \ ******************************\
15367
15368 \ ------------------------------\
15369 \ Display IR_RC5 code           \
15370 \ ------------------------------\
15371 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
15372 \ ------------------------------\
15373 LO2HI                           \ switch from assembler to FORTH
15374     ['] LCD_CLEAR IS CR         \ redirects CR
15375     ['] LCD_WrC  IS EMIT        \ redirects EMIT
15376     $10 BASE !                 \ change BASE to hexadecimal
15377     CR ." $" 2 U.R             \ print IR_RC5 code
15378     ['] (CR) IS CR              \ restore CR
15379     ['] (EMIT) IS EMIT          \ restore EMIT
15380 HI2LO                           \ switch from FORTH to assembler
15381 \ ------------------------------\
15382 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
15383 \ ------------------------------\
15384 MOV @PSP+,&BASE                 \ restore variable BASE
15385 RETI                            \ CPU is ON, GIE is OFF
15386 ENDASM                          \
15387     \ 
15388
15389 CODE START                      \
15390 \ ------------------------------\
15391 \ TB0CTL = %0000 0010 1001 0100\$3C0
15392 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
15393 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
15394 \                      --       \ID input divider \ 10 = /4
15395 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
15396 \                            -  \TBCLR TimerB Clear
15397 \                             - \TBIE
15398 \                              -\TBIFG
15399 \ --------------------------------\\
15400 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
15401 \              --                 \CM Capture Mode
15402 \                --               \CCIS
15403 \                   -             \SCS
15404 \                    --           \CLLD
15405 \                      -          \CAP
15406 \                        ---      \OUTMOD \ 011 = set/reset
15407 \                           -     \CCIE
15408 \                             -   \CCI
15409 \                              -  \OUT
15410 \                               - \COV
15411 \                                -\CCIFG
15412 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
15413 \ TB0EX0                          \$3E0 
15414 \ ------------------------------\
15415 \ set TimerB to make 50kHz PWM  \
15416 \ ------------------------------\
15417 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
15418 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
15419 \ ------------------------------\
15420 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
15421 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
15422 \ ------------------------------\
15423     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
15424     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
15425 \ ------------------------------\
15426 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
15427 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
15428 \ ------------------------------\
15429 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
15430 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
15431 \ ------------------------------\
15432     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
15433 \ ------------------------------\
15434 \ set TimerB to generate PWM for LCD_Vo
15435 \ ------------------------------\
15436     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
15437 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
15438     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
15439 \ ------------------------------\
15440     BIS.B #LCDVo,&LCDVo_DIR     \
15441     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
15442 \ ------------------------------\
15443     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
15444     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
15445 \ ------------------------------\
15446     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
15447     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
15448 \ ------------------------------\
15449 \ WDT interval init part        \
15450 \ ------------------------------\
15451     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
15452 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
15453 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
15454     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
15455 \ ------------------------------\
15456 \ init RC5_Int                  \
15457 \ ------------------------------\
15458     BIS.B #RC5,&IR_IE           \ enable RC5_Int
15459     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
15460 \ ------------------------------\
15461 \ init interrupt vectors
15462 \ ------------------------------\
15463     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
15464     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
15465 \ ------------------------------\
15466 \ define LPM mode for ACCEPT    \
15467 \ ------------------------------\
15468 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
15469 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
15470 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
15471
15472 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
15473
15474 \ ------------------------------\
15475 \ Init LCD 2x20                 \
15476 \ ------------------------------\
15477     $03E8 20_US                \ 1-  wait 20 ms
15478     $03 TOP_LCD                \ 2- send DB5=DB4=1
15479     $CD 20_US                  \ 3- wait 4,1 ms
15480     $03 TOP_LCD                \ 4- send again DB5=DB4=1
15481     $5 20_US                   \ 5- wait 0,1 ms
15482     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
15483     $2 20_US                   \    wait 40 us = LCD cycle
15484     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
15485     $2 20_US                   \    wait 40 us = LCD cycle
15486     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
15487     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
15488     LCD_Clear                   \ 10- "LCD_Clear"
15489     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
15490     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
15491     LCD_Clear                   \ 10- "LCD_Clear"
15492     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
15493     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
15494     CR ." I love you"   
15495     ['] (CR) IS CR              \ ' (CR) is CR
15496     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
15497     CR
15498     ."    RC5toLCD is running. Type STOP to quit"
15499 \    NOECHO                      \ uncomment to run this app without terminal connexion
15500     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
15501     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
15502 ;
15503     \
15504
15505 : STOP                  \ stops multitasking, must to be used before downloading app
15506     ['] (WARM) IS WARM  \ remove START app from FORTH init process
15507     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
15508 ;
15509     \
15510
15511
15512 RST_STATE   ;
15513
15514
15515 CODE MAX    \    n1 n2 -- n3       signed maximum
15516             CMP     @PSP,TOS    \ n2-n1
15517             S<      ?GOTO FW1   \ n2<n1
15518 BW1         ADD     #2,PSP
15519             MOV     @IP+,PC
15520 ENDCODE
15521     \
15522
15523 CODE MIN    \    n1 n2 -- n3       signed minimum
15524             CMP     @PSP,TOS     \ n2-n1
15525             S<      ?GOTO BW1    \ n2<n1
15526 FW1         MOV     @PSP+,TOS
15527             MOV     @IP+,PC
15528 ENDCODE
15529     \
15530
15531 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
15532   >R  <# 0 # #S #>  
15533   R> OVER - 0 MAX SPACES TYPE
15534 ;
15535     \
15536
15537 CODE 20_US                      \ n --      n * 20 us
15538 BEGIN                           \ 3 cycles loop + 6~  
15539 \    MOV     #5,W                \ 3 MCLK = 1 MHz
15540 \    MOV     #23,W               \ 3 MCLK = 4 MHz
15541     MOV     #51,W               \ 3 MCLK = 8 MHz
15542 \    MOV     #104,W              \ 3 MCLK = 16 MHz
15543 \    MOV     #158,W              \ 3 MCLK = 24 MHz
15544     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
15545         SUB #1,W                \ 1
15546     0= UNTIL                    \ 2
15547     SUB     #1,TOS              \ 1
15548 0= UNTIL                        \ 2
15549     MOV     @PSP+,TOS           \ 2
15550     MOV     @IP+,PC             \ 4
15551 ENDCODE
15552     \
15553
15554 CODE TOP_LCD                    \ LCD Sample
15555 \                               \ if write : %xxxxWWWW --
15556 \                               \ if read  : -- %0000RRRR
15557     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
15558     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
15559 0= IF                           \ write LCD bits pattern
15560     AND.B #LCD_DB,TOS           \ 
15561     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
15562     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
15563     MOV @PSP+,TOS               \
15564     MOV @IP+,PC
15565 THEN                            \ read LCD bits pattern
15566     SUB #2,PSP
15567     MOV TOS,0(PSP)
15568     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
15569     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
15570     AND.B #LCD_DB,TOS           \
15571     MOV @IP+,PC
15572 ENDCODE
15573     \
15574
15575 CODE LCD_W                      \ byte --       write byte to LCD 
15576     SUB #2,PSP                  \
15577     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
15578     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
15579     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
15580     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
15581 COLON                           \ high level word starts here 
15582     TOP_LCD 2 20_US             \ write high nibble first
15583     TOP_LCD 2 20_US 
15584 ;
15585     \
15586
15587 CODE LCD_WrC                    \ char --         Write Char
15588     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
15589     JMP LCD_W 
15590 ENDCODE
15591     \
15592
15593 CODE LCD_WrF                    \ func --         Write Fonction
15594     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
15595     JMP LCD_W 
15596 ENDCODE
15597     \
15598
15599 : LCD_Clear 
15600     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
15601 ;
15602     \
15603
15604 : LCD_Home 
15605     $02 LCD_WrF 100 20_us 
15606 ;
15607     \
15608
15609 \ : LCD_Entry_set       $04 OR LCD_WrF ;
15610
15611 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
15612
15613 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
15614
15615 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
15616
15617 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
15618
15619 \ : LCD_Goto            $80 OR LCD_WrF ;
15620
15621 \ CODE LCD_R                      \ -- byte       read byte from LCD
15622 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
15623 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
15624 \ COLON                           \ starts a FORTH word
15625 \     TOP_LCD 2 20_us             \ -- %0000HHHH
15626 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
15627 \ HI2LO                           \ switch from FORTH to assembler
15628 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
15629 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
15630 \     MOV @RSP+,IP                \ restore IP saved by COLON
15631 \     MOV @IP+,PC                 \
15632 \ ENDCODE
15633 \     \
15634
15635 \ CODE LCD_RdS                    \ -- status       Read Status
15636 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
15637 \     JMP LCD_R
15638 \ ENDCODE
15639 \     \
15640
15641 \ CODE LCD_RdC                    \ -- char         Read Char
15642 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
15643 \     JMP LCD_R
15644 \ ENDCODE
15645 \     \
15646
15647 \ -------------+------+------+------+------++---+---+---+---+---------+
15648 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
15649 \ -------------+------+------+------+------++---+---+---+---+---------+
15650 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
15651 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
15652 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
15653 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
15654 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
15655 \ -------------+------+------+------+------++---+---+---+---+---------+
15656
15657
15658 \ ******************************\
15659 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
15660 \ ******************************\
15661 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
15662 \ ------------------------------\
15663 \ define LPM mode for ACCEPT    \
15664 \ ------------------------------\
15665 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
15666 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
15667 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
15668 BIT.B #SW2,&SW2_IN              \ test switch S2
15669 0= IF                           \ case of switch S2 pressed
15670     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
15671     U< IF
15672         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
15673     THEN
15674 ELSE
15675     BIT.B #SW1,&SW1_IN          \ test switch S1 input
15676     0= IF                       \ case of Switch S1 pressed
15677         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
15678         U>= IF                  \
15679             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
15680         THEN                    \
15681     THEN                        \
15682 THEN                            \
15683 RETI                            \ CPU is ON, GIE is OFF
15684 ENDASM                          \
15685     \
15686
15687
15688 \ ------------------------------\
15689 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
15690 \ ******************************\
15691 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
15692 \ ******************************\
15693 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
15694 \                               \       SMclock = 8|16|24 MHz
15695 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
15696 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
15697 \                               \       SR(9)=new Toggle bit memory (ADD on)
15698 \ ------------------------------\
15699 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
15700 \ ------------------------------\
15701 \ define LPM mode for ACCEPT    \
15702 \ ------------------------------\
15703 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
15704 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
15705 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
15706 \ ------------------------------\
15707 \ RC5_FirstStartBitHalfCycle:   \
15708 \ ------------------------------\
15709 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
15710 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
15711 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
15712 MOV     #1778,X                 \ RC5_Period in us
15713 MOV     #14,W                   \ count of loop
15714 BEGIN                           \
15715 \ ------------------------------\
15716 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
15717 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
15718     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
15719 \ RC5_Compute_3/4_Period:       \                   |
15720     RRUM    #1,X                \ X=1/2 cycle       |
15721     MOV     X,Y                 \ Y=1/2             ^
15722     RRUM    #1,Y                \ Y=1/4
15723     ADD     X,Y                 \ Y=3/4
15724 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
15725     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
15726     0= UNTIL                    \
15727 \ ------------------------------\
15728 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
15729 \ ------------------------------\
15730     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
15731     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
15732     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
15733     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
15734     SUB     #1,W                \ decrement count loop
15735 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
15736 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
15737 0<> WHILE                       \ ----> out of loop ----+
15738 \ RC5_compute_7/4_Time_out:     \                       |
15739     ADD     X,Y                 \                       |   out of bound = 7/4 period 
15740 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
15741     BEGIN                       \                       |
15742         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
15743         0>= IF                  \                       |   if cycle time out of bound
15744             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
15745             RETI                \                       |   then quit to do nothing
15746         THEN                    \                       |
15747 \ ------------------------------\                       |
15748         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
15749     0<> UNTIL                   \                   |   |
15750     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
15751 REPEAT                          \ ----> loop back --+   |
15752 \ ------------------------------\                       |
15753 \ RC5_SampleEndOf:              \ <---------------------+
15754 \ ------------------------------\
15755 BIC     #$30,&TA0CTL           \ stop timer_A0
15756 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
15757 \ ******************************\
15758 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
15759 \ ******************************\
15760 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
15761 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
15762 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
15763 BIT     #BIT13,X                \ X(13) = New_RC5_command
15764 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
15765 THEN                            \
15766 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
15767 \ ******************************\
15768 \ RC5_ComputeNewRC5word         \
15769 \ ******************************\
15770 SUB     #4,PSP                  \
15771 MOV     &BASE,2(PSP)            \ save variable BASE before use
15772 MOV     TOS,0(PSP)              \ save TOS before use
15773 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
15774 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
15775 \ ******************************\
15776 \ RC5_ComputeC6bit              \
15777 \ ******************************\
15778 BIT     #$4000,IP              \ test /C6 bit in IP
15779 0= IF   BIS #$40,TOS           \ set C6 bit in S
15780 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
15781 \ ******************************\
15782 \ RC5_CommandByteIsDone         \ RC5_code --
15783 \ ******************************\
15784
15785 \ ------------------------------\
15786 \ Display IR_RC5 code           \
15787 \ ------------------------------\
15788 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
15789 \ ------------------------------\
15790 LO2HI                           \ switch from assembler to FORTH
15791     ['] LCD_CLEAR IS CR         \ redirects CR
15792     ['] LCD_WrC  IS EMIT        \ redirects EMIT
15793     $10 BASE !                 \ change BASE to hexadecimal
15794     CR ." $" 2 U.R             \ print IR_RC5 code
15795     ['] (CR) IS CR              \ restore CR
15796     ['] (EMIT) IS EMIT          \ restore EMIT
15797 HI2LO                           \ switch from FORTH to assembler
15798 \ ------------------------------\
15799 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
15800 \ ------------------------------\
15801 MOV @PSP+,&BASE                 \ restore variable BASE
15802 RETI                            \ CPU is ON, GIE is OFF
15803 ENDASM                          \
15804     \ 
15805
15806 CODE START                      \
15807 \ ------------------------------\
15808 \ TB0CTL = %0000 0010 1001 0100\$3C0
15809 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
15810 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
15811 \                      --       \ID input divider \ 10 = /4
15812 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
15813 \                            -  \TBCLR TimerB Clear
15814 \                             - \TBIE
15815 \                              -\TBIFG
15816 \ --------------------------------\\
15817 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
15818 \              --                 \CM Capture Mode
15819 \                --               \CCIS
15820 \                   -             \SCS
15821 \                    --           \CLLD
15822 \                      -          \CAP
15823 \                        ---      \OUTMOD \ 011 = set/reset
15824 \                           -     \CCIE
15825 \                             -   \CCI
15826 \                              -  \OUT
15827 \                               - \COV
15828 \                                -\CCIFG
15829 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
15830 \ TB0EX0                          \$3E0 
15831 \ ------------------------------\
15832 \ set TimerB to make 50kHz PWM  \
15833 \ ------------------------------\
15834 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
15835 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
15836 \ ------------------------------\
15837 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
15838 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
15839 \ ------------------------------\
15840     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
15841     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
15842 \ ------------------------------\
15843 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
15844 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
15845 \ ------------------------------\
15846 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
15847 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
15848 \ ------------------------------\
15849     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
15850 \ ------------------------------\
15851 \ set TimerB to generate PWM for LCD_Vo
15852 \ ------------------------------\
15853     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
15854 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
15855     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
15856 \ ------------------------------\
15857     BIS.B #LCDVo,&LCDVo_DIR     \
15858     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
15859 \ ------------------------------\
15860     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
15861     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
15862 \ ------------------------------\
15863     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
15864     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
15865 \ ------------------------------\
15866 \ WDT interval init part        \
15867 \ ------------------------------\
15868     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
15869 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
15870 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
15871     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
15872 \ ------------------------------\
15873 \ init RC5_Int                  \
15874 \ ------------------------------\
15875     BIS.B #RC5,&IR_IE           \ enable RC5_Int
15876     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
15877 \ ------------------------------\
15878 \ init interrupt vectors
15879 \ ------------------------------\
15880     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
15881     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
15882 \ ------------------------------\
15883 \ define LPM mode for ACCEPT    \
15884 \ ------------------------------\
15885 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
15886 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
15887 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
15888
15889 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
15890
15891 \ ------------------------------\
15892 \ Init LCD 2x20                 \
15893 \ ------------------------------\
15894     $03E8 20_US                \ 1-  wait 20 ms
15895     $03 TOP_LCD                \ 2- send DB5=DB4=1
15896     $CD 20_US                  \ 3- wait 4,1 ms
15897     $03 TOP_LCD                \ 4- send again DB5=DB4=1
15898     $5 20_US                   \ 5- wait 0,1 ms
15899     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
15900     $2 20_US                   \    wait 40 us = LCD cycle
15901     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
15902     $2 20_US                   \    wait 40 us = LCD cycle
15903     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
15904     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
15905     LCD_Clear                   \ 10- "LCD_Clear"
15906     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
15907     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
15908     LCD_Clear                   \ 10- "LCD_Clear"
15909     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
15910     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
15911     CR ." I love you"   
15912     ['] (CR) IS CR              \ ' (CR) is CR
15913     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
15914     CR
15915     ."    RC5toLCD is running. Type STOP to quit"
15916 \    NOECHO                      \ uncomment to run this app without terminal connexion
15917     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
15918     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
15919 ;
15920     \
15921
15922 : STOP                  \ stops multitasking, must to be used before downloading app
15923     ['] (WARM) IS WARM  \ remove START app from FORTH init process
15924     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
15925 ;
15926     \
15927
15928
15929 RST_STATE   ;
15930
15931
15932 CODE MAX    \    n1 n2 -- n3       signed maximum
15933             CMP     @PSP,TOS    \ n2-n1
15934             S<      ?GOTO FW1   \ n2<n1
15935 BW1         ADD     #2,PSP
15936             MOV     @IP+,PC
15937 ENDCODE
15938     \
15939
15940 CODE MIN    \    n1 n2 -- n3       signed minimum
15941             CMP     @PSP,TOS     \ n2-n1
15942             S<      ?GOTO BW1    \ n2<n1
15943 FW1         MOV     @PSP+,TOS
15944             MOV     @IP+,PC
15945 ENDCODE
15946     \
15947
15948 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
15949   >R  <# 0 # #S #>  
15950   R> OVER - 0 MAX SPACES TYPE
15951 ;
15952     \
15953
15954 CODE 20_US                      \ n --      n * 20 us
15955 BEGIN                           \ 3 cycles loop + 6~  
15956 \    MOV     #5,W                \ 3 MCLK = 1 MHz
15957 \    MOV     #23,W               \ 3 MCLK = 4 MHz
15958     MOV     #51,W               \ 3 MCLK = 8 MHz
15959 \    MOV     #104,W              \ 3 MCLK = 16 MHz
15960 \    MOV     #158,W              \ 3 MCLK = 24 MHz
15961     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
15962         SUB #1,W                \ 1
15963     0= UNTIL                    \ 2
15964     SUB     #1,TOS              \ 1
15965 0= UNTIL                        \ 2
15966     MOV     @PSP+,TOS           \ 2
15967     MOV     @IP+,PC             \ 4
15968 ENDCODE
15969     \
15970
15971 CODE TOP_LCD                    \ LCD Sample
15972 \                               \ if write : %xxxxWWWW --
15973 \                               \ if read  : -- %0000RRRR
15974     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
15975     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
15976 0= IF                           \ write LCD bits pattern
15977     AND.B #LCD_DB,TOS           \ 
15978     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
15979     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
15980     MOV @PSP+,TOS               \
15981     MOV @IP+,PC
15982 THEN                            \ read LCD bits pattern
15983     SUB #2,PSP
15984     MOV TOS,0(PSP)
15985     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
15986     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
15987     AND.B #LCD_DB,TOS           \
15988     MOV @IP+,PC
15989 ENDCODE
15990     \
15991
15992 CODE LCD_W                      \ byte --       write byte to LCD 
15993     SUB #2,PSP                  \
15994     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
15995     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
15996     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
15997     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
15998 COLON                           \ high level word starts here 
15999     TOP_LCD 2 20_US             \ write high nibble first
16000     TOP_LCD 2 20_US 
16001 ;
16002     \
16003
16004 CODE LCD_WrC                    \ char --         Write Char
16005     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
16006     JMP LCD_W 
16007 ENDCODE
16008     \
16009
16010 CODE LCD_WrF                    \ func --         Write Fonction
16011     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
16012     JMP LCD_W 
16013 ENDCODE
16014     \
16015
16016 : LCD_Clear 
16017     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
16018 ;
16019     \
16020
16021 : LCD_Home 
16022     $02 LCD_WrF 100 20_us 
16023 ;
16024     \
16025
16026 \ : LCD_Entry_set       $04 OR LCD_WrF ;
16027
16028 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
16029
16030 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
16031
16032 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
16033
16034 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
16035
16036 \ : LCD_Goto            $80 OR LCD_WrF ;
16037
16038 \ CODE LCD_R                      \ -- byte       read byte from LCD
16039 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
16040 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
16041 \ COLON                           \ starts a FORTH word
16042 \     TOP_LCD 2 20_us             \ -- %0000HHHH
16043 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
16044 \ HI2LO                           \ switch from FORTH to assembler
16045 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
16046 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
16047 \     MOV @RSP+,IP                \ restore IP saved by COLON
16048 \     MOV @IP+,PC                 \
16049 \ ENDCODE
16050 \     \
16051
16052 \ CODE LCD_RdS                    \ -- status       Read Status
16053 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
16054 \     JMP LCD_R
16055 \ ENDCODE
16056 \     \
16057
16058 \ CODE LCD_RdC                    \ -- char         Read Char
16059 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
16060 \     JMP LCD_R
16061 \ ENDCODE
16062 \     \
16063
16064 \ -------------+------+------+------+------++---+---+---+---+---------+
16065 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
16066 \ -------------+------+------+------+------++---+---+---+---+---------+
16067 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
16068 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
16069 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
16070 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
16071 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
16072 \ -------------+------+------+------+------++---+---+---+---+---------+
16073
16074
16075 \ ******************************\
16076 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
16077 \ ******************************\
16078 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
16079 \ ------------------------------\
16080 \ define LPM mode for ACCEPT    \
16081 \ ------------------------------\
16082 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
16083 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
16084 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
16085 BIT.B #SW2,&SW2_IN              \ test switch S2
16086 0= IF                           \ case of switch S2 pressed
16087     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
16088     U< IF
16089         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
16090     THEN
16091 ELSE
16092     BIT.B #SW1,&SW1_IN          \ test switch S1 input
16093     0= IF                       \ case of Switch S1 pressed
16094         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
16095         U>= IF                  \
16096             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
16097         THEN                    \
16098     THEN                        \
16099 THEN                            \
16100 RETI                            \ CPU is ON, GIE is OFF
16101 ENDASM                          \
16102     \
16103
16104
16105 \ ------------------------------\
16106 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
16107 \ ******************************\
16108 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
16109 \ ******************************\
16110 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
16111 \                               \       SMclock = 8|16|24 MHz
16112 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
16113 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
16114 \                               \       SR(9)=new Toggle bit memory (ADD on)
16115 \ ------------------------------\
16116 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
16117 \ ------------------------------\
16118 \ define LPM mode for ACCEPT    \
16119 \ ------------------------------\
16120 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
16121 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
16122 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
16123 \ ------------------------------\
16124 \ RC5_FirstStartBitHalfCycle:   \
16125 \ ------------------------------\
16126 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
16127 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
16128 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
16129 MOV     #1778,X                 \ RC5_Period in us
16130 MOV     #14,W                   \ count of loop
16131 BEGIN                           \
16132 \ ------------------------------\
16133 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
16134 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
16135     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
16136 \ RC5_Compute_3/4_Period:       \                   |
16137     RRUM    #1,X                \ X=1/2 cycle       |
16138     MOV     X,Y                 \ Y=1/2             ^
16139     RRUM    #1,Y                \ Y=1/4
16140     ADD     X,Y                 \ Y=3/4
16141 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
16142     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
16143     0= UNTIL                    \
16144 \ ------------------------------\
16145 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
16146 \ ------------------------------\
16147     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
16148     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
16149     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
16150     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
16151     SUB     #1,W                \ decrement count loop
16152 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
16153 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
16154 0<> WHILE                       \ ----> out of loop ----+
16155 \ RC5_compute_7/4_Time_out:     \                       |
16156     ADD     X,Y                 \                       |   out of bound = 7/4 period 
16157 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
16158     BEGIN                       \                       |
16159         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
16160         0>= IF                  \                       |   if cycle time out of bound
16161             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
16162             RETI                \                       |   then quit to do nothing
16163         THEN                    \                       |
16164 \ ------------------------------\                       |
16165         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
16166     0<> UNTIL                   \                   |   |
16167     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
16168 REPEAT                          \ ----> loop back --+   |
16169 \ ------------------------------\                       |
16170 \ RC5_SampleEndOf:              \ <---------------------+
16171 \ ------------------------------\
16172 BIC     #$30,&TA0CTL           \ stop timer_A0
16173 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
16174 \ ******************************\
16175 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
16176 \ ******************************\
16177 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
16178 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
16179 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
16180 BIT     #BIT13,X                \ X(13) = New_RC5_command
16181 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
16182 THEN                            \
16183 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
16184 \ ******************************\
16185 \ RC5_ComputeNewRC5word         \
16186 \ ******************************\
16187 SUB     #4,PSP                  \
16188 MOV     &BASE,2(PSP)            \ save variable BASE before use
16189 MOV     TOS,0(PSP)              \ save TOS before use
16190 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
16191 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
16192 \ ******************************\
16193 \ RC5_ComputeC6bit              \
16194 \ ******************************\
16195 BIT     #$4000,IP              \ test /C6 bit in IP
16196 0= IF   BIS #$40,TOS           \ set C6 bit in S
16197 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
16198 \ ******************************\
16199 \ RC5_CommandByteIsDone         \ RC5_code --
16200 \ ******************************\
16201
16202 \ ------------------------------\
16203 \ Display IR_RC5 code           \
16204 \ ------------------------------\
16205 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
16206 \ ------------------------------\
16207 LO2HI                           \ switch from assembler to FORTH
16208     ['] LCD_CLEAR IS CR         \ redirects CR
16209     ['] LCD_WrC  IS EMIT        \ redirects EMIT
16210     $10 BASE !                 \ change BASE to hexadecimal
16211     CR ." $" 2 U.R             \ print IR_RC5 code
16212     ['] (CR) IS CR              \ restore CR
16213     ['] (EMIT) IS EMIT          \ restore EMIT
16214 HI2LO                           \ switch from FORTH to assembler
16215 \ ------------------------------\
16216 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
16217 \ ------------------------------\
16218 MOV @PSP+,&BASE                 \ restore variable BASE
16219 RETI                            \ CPU is ON, GIE is OFF
16220 ENDASM                          \
16221     \ 
16222
16223 CODE START                      \
16224 \ ------------------------------\
16225 \ TB0CTL = %0000 0010 1001 0100\$3C0
16226 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
16227 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
16228 \                      --       \ID input divider \ 10 = /4
16229 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
16230 \                            -  \TBCLR TimerB Clear
16231 \                             - \TBIE
16232 \                              -\TBIFG
16233 \ --------------------------------\\
16234 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
16235 \              --                 \CM Capture Mode
16236 \                --               \CCIS
16237 \                   -             \SCS
16238 \                    --           \CLLD
16239 \                      -          \CAP
16240 \                        ---      \OUTMOD \ 011 = set/reset
16241 \                           -     \CCIE
16242 \                             -   \CCI
16243 \                              -  \OUT
16244 \                               - \COV
16245 \                                -\CCIFG
16246 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
16247 \ TB0EX0                          \$3E0 
16248 \ ------------------------------\
16249 \ set TimerB to make 50kHz PWM  \
16250 \ ------------------------------\
16251 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
16252 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
16253 \ ------------------------------\
16254 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
16255 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
16256 \ ------------------------------\
16257     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
16258     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
16259 \ ------------------------------\
16260 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
16261 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
16262 \ ------------------------------\
16263 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
16264 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
16265 \ ------------------------------\
16266     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
16267 \ ------------------------------\
16268 \ set TimerB to generate PWM for LCD_Vo
16269 \ ------------------------------\
16270     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
16271 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
16272     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
16273 \ ------------------------------\
16274     BIS.B #LCDVo,&LCDVo_DIR     \
16275     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
16276 \ ------------------------------\
16277     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
16278     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
16279 \ ------------------------------\
16280     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
16281     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
16282 \ ------------------------------\
16283 \ WDT interval init part        \
16284 \ ------------------------------\
16285     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
16286 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
16287 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
16288     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
16289 \ ------------------------------\
16290 \ init RC5_Int                  \
16291 \ ------------------------------\
16292     BIS.B #RC5,&IR_IE           \ enable RC5_Int
16293     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
16294 \ ------------------------------\
16295 \ init interrupt vectors
16296 \ ------------------------------\
16297     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
16298     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
16299 \ ------------------------------\
16300 \ define LPM mode for ACCEPT    \
16301 \ ------------------------------\
16302 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
16303 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
16304 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
16305
16306 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
16307
16308 \ ------------------------------\
16309 \ Init LCD 2x20                 \
16310 \ ------------------------------\
16311     $03E8 20_US                \ 1-  wait 20 ms
16312     $03 TOP_LCD                \ 2- send DB5=DB4=1
16313     $CD 20_US                  \ 3- wait 4,1 ms
16314     $03 TOP_LCD                \ 4- send again DB5=DB4=1
16315     $5 20_US                   \ 5- wait 0,1 ms
16316     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
16317     $2 20_US                   \    wait 40 us = LCD cycle
16318     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
16319     $2 20_US                   \    wait 40 us = LCD cycle
16320     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
16321     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
16322     LCD_Clear                   \ 10- "LCD_Clear"
16323     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
16324     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
16325     LCD_Clear                   \ 10- "LCD_Clear"
16326     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
16327     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
16328     CR ." I love you"   
16329     ['] (CR) IS CR              \ ' (CR) is CR
16330     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
16331     CR
16332     ."    RC5toLCD is running. Type STOP to quit"
16333 \    NOECHO                      \ uncomment to run this app without terminal connexion
16334     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
16335     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
16336 ;
16337     \
16338
16339 : STOP                  \ stops multitasking, must to be used before downloading app
16340     ['] (WARM) IS WARM  \ remove START app from FORTH init process
16341     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
16342 ;
16343     \
16344
16345
16346 RST_STATE   ;
16347
16348
16349 CODE MAX    \    n1 n2 -- n3       signed maximum
16350             CMP     @PSP,TOS    \ n2-n1
16351             S<      ?GOTO FW1   \ n2<n1
16352 BW1         ADD     #2,PSP
16353             MOV     @IP+,PC
16354 ENDCODE
16355     \
16356
16357 CODE MIN    \    n1 n2 -- n3       signed minimum
16358             CMP     @PSP,TOS     \ n2-n1
16359             S<      ?GOTO BW1    \ n2<n1
16360 FW1         MOV     @PSP+,TOS
16361             MOV     @IP+,PC
16362 ENDCODE
16363     \
16364
16365 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
16366   >R  <# 0 # #S #>  
16367   R> OVER - 0 MAX SPACES TYPE
16368 ;
16369     \
16370
16371 CODE 20_US                      \ n --      n * 20 us
16372 BEGIN                           \ 3 cycles loop + 6~  
16373 \    MOV     #5,W                \ 3 MCLK = 1 MHz
16374 \    MOV     #23,W               \ 3 MCLK = 4 MHz
16375     MOV     #51,W               \ 3 MCLK = 8 MHz
16376 \    MOV     #104,W              \ 3 MCLK = 16 MHz
16377 \    MOV     #158,W              \ 3 MCLK = 24 MHz
16378     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
16379         SUB #1,W                \ 1
16380     0= UNTIL                    \ 2
16381     SUB     #1,TOS              \ 1
16382 0= UNTIL                        \ 2
16383     MOV     @PSP+,TOS           \ 2
16384     MOV     @IP+,PC             \ 4
16385 ENDCODE
16386     \
16387
16388 CODE TOP_LCD                    \ LCD Sample
16389 \                               \ if write : %xxxxWWWW --
16390 \                               \ if read  : -- %0000RRRR
16391     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
16392     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
16393 0= IF                           \ write LCD bits pattern
16394     AND.B #LCD_DB,TOS           \ 
16395     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
16396     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
16397     MOV @PSP+,TOS               \
16398     MOV @IP+,PC
16399 THEN                            \ read LCD bits pattern
16400     SUB #2,PSP
16401     MOV TOS,0(PSP)
16402     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
16403     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
16404     AND.B #LCD_DB,TOS           \
16405     MOV @IP+,PC
16406 ENDCODE
16407     \
16408
16409 CODE LCD_W                      \ byte --       write byte to LCD 
16410     SUB #2,PSP                  \
16411     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
16412     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
16413     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
16414     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
16415 COLON                           \ high level word starts here 
16416     TOP_LCD 2 20_US             \ write high nibble first
16417     TOP_LCD 2 20_US 
16418 ;
16419     \
16420
16421 CODE LCD_WrC                    \ char --         Write Char
16422     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
16423     JMP LCD_W 
16424 ENDCODE
16425     \
16426
16427 CODE LCD_WrF                    \ func --         Write Fonction
16428     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
16429     JMP LCD_W 
16430 ENDCODE
16431     \
16432
16433 : LCD_Clear 
16434     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
16435 ;
16436     \
16437
16438 : LCD_Home 
16439     $02 LCD_WrF 100 20_us 
16440 ;
16441     \
16442
16443 \ : LCD_Entry_set       $04 OR LCD_WrF ;
16444
16445 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
16446
16447 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
16448
16449 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
16450
16451 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
16452
16453 \ : LCD_Goto            $80 OR LCD_WrF ;
16454
16455 \ CODE LCD_R                      \ -- byte       read byte from LCD
16456 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
16457 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
16458 \ COLON                           \ starts a FORTH word
16459 \     TOP_LCD 2 20_us             \ -- %0000HHHH
16460 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
16461 \ HI2LO                           \ switch from FORTH to assembler
16462 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
16463 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
16464 \     MOV @RSP+,IP                \ restore IP saved by COLON
16465 \     MOV @IP+,PC                 \
16466 \ ENDCODE
16467 \     \
16468
16469 \ CODE LCD_RdS                    \ -- status       Read Status
16470 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
16471 \     JMP LCD_R
16472 \ ENDCODE
16473 \     \
16474
16475 \ CODE LCD_RdC                    \ -- char         Read Char
16476 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
16477 \     JMP LCD_R
16478 \ ENDCODE
16479 \     \
16480
16481 \ -------------+------+------+------+------++---+---+---+---+---------+
16482 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
16483 \ -------------+------+------+------+------++---+---+---+---+---------+
16484 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
16485 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
16486 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
16487 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
16488 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
16489 \ -------------+------+------+------+------++---+---+---+---+---------+
16490
16491
16492 \ ******************************\
16493 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
16494 \ ******************************\
16495 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
16496 \ ------------------------------\
16497 \ define LPM mode for ACCEPT    \
16498 \ ------------------------------\
16499 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
16500 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
16501 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
16502 BIT.B #SW2,&SW2_IN              \ test switch S2
16503 0= IF                           \ case of switch S2 pressed
16504     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
16505     U< IF
16506         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
16507     THEN
16508 ELSE
16509     BIT.B #SW1,&SW1_IN          \ test switch S1 input
16510     0= IF                       \ case of Switch S1 pressed
16511         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
16512         U>= IF                  \
16513             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
16514         THEN                    \
16515     THEN                        \
16516 THEN                            \
16517 RETI                            \ CPU is ON, GIE is OFF
16518 ENDASM                          \
16519     \
16520
16521
16522 \ ------------------------------\
16523 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
16524 \ ******************************\
16525 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
16526 \ ******************************\
16527 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
16528 \                               \       SMclock = 8|16|24 MHz
16529 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
16530 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
16531 \                               \       SR(9)=new Toggle bit memory (ADD on)
16532 \ ------------------------------\
16533 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
16534 \ ------------------------------\
16535 \ define LPM mode for ACCEPT    \
16536 \ ------------------------------\
16537 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
16538 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
16539 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
16540 \ ------------------------------\
16541 \ RC5_FirstStartBitHalfCycle:   \
16542 \ ------------------------------\
16543 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
16544 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
16545 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
16546 MOV     #1778,X                 \ RC5_Period in us
16547 MOV     #14,W                   \ count of loop
16548 BEGIN                           \
16549 \ ------------------------------\
16550 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
16551 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
16552     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
16553 \ RC5_Compute_3/4_Period:       \                   |
16554     RRUM    #1,X                \ X=1/2 cycle       |
16555     MOV     X,Y                 \ Y=1/2             ^
16556     RRUM    #1,Y                \ Y=1/4
16557     ADD     X,Y                 \ Y=3/4
16558 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
16559     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
16560     0= UNTIL                    \
16561 \ ------------------------------\
16562 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
16563 \ ------------------------------\
16564     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
16565     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
16566     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
16567     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
16568     SUB     #1,W                \ decrement count loop
16569 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
16570 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
16571 0<> WHILE                       \ ----> out of loop ----+
16572 \ RC5_compute_7/4_Time_out:     \                       |
16573     ADD     X,Y                 \                       |   out of bound = 7/4 period 
16574 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
16575     BEGIN                       \                       |
16576         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
16577         0>= IF                  \                       |   if cycle time out of bound
16578             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
16579             RETI                \                       |   then quit to do nothing
16580         THEN                    \                       |
16581 \ ------------------------------\                       |
16582         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
16583     0<> UNTIL                   \                   |   |
16584     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
16585 REPEAT                          \ ----> loop back --+   |
16586 \ ------------------------------\                       |
16587 \ RC5_SampleEndOf:              \ <---------------------+
16588 \ ------------------------------\
16589 BIC     #$30,&TA0CTL           \ stop timer_A0
16590 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
16591 \ ******************************\
16592 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
16593 \ ******************************\
16594 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
16595 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
16596 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
16597 BIT     #BIT13,X                \ X(13) = New_RC5_command
16598 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
16599 THEN                            \
16600 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
16601 \ ******************************\
16602 \ RC5_ComputeNewRC5word         \
16603 \ ******************************\
16604 SUB     #4,PSP                  \
16605 MOV     &BASE,2(PSP)            \ save variable BASE before use
16606 MOV     TOS,0(PSP)              \ save TOS before use
16607 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
16608 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
16609 \ ******************************\
16610 \ RC5_ComputeC6bit              \
16611 \ ******************************\
16612 BIT     #$4000,IP              \ test /C6 bit in IP
16613 0= IF   BIS #$40,TOS           \ set C6 bit in S
16614 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
16615 \ ******************************\
16616 \ RC5_CommandByteIsDone         \ RC5_code --
16617 \ ******************************\
16618
16619 \ ------------------------------\
16620 \ Display IR_RC5 code           \
16621 \ ------------------------------\
16622 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
16623 \ ------------------------------\
16624 LO2HI                           \ switch from assembler to FORTH
16625     ['] LCD_CLEAR IS CR         \ redirects CR
16626     ['] LCD_WrC  IS EMIT        \ redirects EMIT
16627     $10 BASE !                 \ change BASE to hexadecimal
16628     CR ." $" 2 U.R             \ print IR_RC5 code
16629     ['] (CR) IS CR              \ restore CR
16630     ['] (EMIT) IS EMIT          \ restore EMIT
16631 HI2LO                           \ switch from FORTH to assembler
16632 \ ------------------------------\
16633 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
16634 \ ------------------------------\
16635 MOV @PSP+,&BASE                 \ restore variable BASE
16636 RETI                            \ CPU is ON, GIE is OFF
16637 ENDASM                          \
16638     \ 
16639
16640 CODE START                      \
16641 \ ------------------------------\
16642 \ TB0CTL = %0000 0010 1001 0100\$3C0
16643 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
16644 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
16645 \                      --       \ID input divider \ 10 = /4
16646 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
16647 \                            -  \TBCLR TimerB Clear
16648 \                             - \TBIE
16649 \                              -\TBIFG
16650 \ --------------------------------\\
16651 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
16652 \              --                 \CM Capture Mode
16653 \                --               \CCIS
16654 \                   -             \SCS
16655 \                    --           \CLLD
16656 \                      -          \CAP
16657 \                        ---      \OUTMOD \ 011 = set/reset
16658 \                           -     \CCIE
16659 \                             -   \CCI
16660 \                              -  \OUT
16661 \                               - \COV
16662 \                                -\CCIFG
16663 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
16664 \ TB0EX0                          \$3E0 
16665 \ ------------------------------\
16666 \ set TimerB to make 50kHz PWM  \
16667 \ ------------------------------\
16668 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
16669 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
16670 \ ------------------------------\
16671 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
16672 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
16673 \ ------------------------------\
16674     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
16675     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
16676 \ ------------------------------\
16677 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
16678 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
16679 \ ------------------------------\
16680 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
16681 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
16682 \ ------------------------------\
16683     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
16684 \ ------------------------------\
16685 \ set TimerB to generate PWM for LCD_Vo
16686 \ ------------------------------\
16687     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
16688 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
16689     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
16690 \ ------------------------------\
16691     BIS.B #LCDVo,&LCDVo_DIR     \
16692     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
16693 \ ------------------------------\
16694     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
16695     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
16696 \ ------------------------------\
16697     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
16698     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
16699 \ ------------------------------\
16700 \ WDT interval init part        \
16701 \ ------------------------------\
16702     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
16703 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
16704 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
16705     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
16706 \ ------------------------------\
16707 \ init RC5_Int                  \
16708 \ ------------------------------\
16709     BIS.B #RC5,&IR_IE           \ enable RC5_Int
16710     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
16711 \ ------------------------------\
16712 \ init interrupt vectors
16713 \ ------------------------------\
16714     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
16715     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
16716 \ ------------------------------\
16717 \ define LPM mode for ACCEPT    \
16718 \ ------------------------------\
16719 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
16720 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
16721 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
16722
16723 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
16724
16725 \ ------------------------------\
16726 \ Init LCD 2x20                 \
16727 \ ------------------------------\
16728     $03E8 20_US                \ 1-  wait 20 ms
16729     $03 TOP_LCD                \ 2- send DB5=DB4=1
16730     $CD 20_US                  \ 3- wait 4,1 ms
16731     $03 TOP_LCD                \ 4- send again DB5=DB4=1
16732     $5 20_US                   \ 5- wait 0,1 ms
16733     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
16734     $2 20_US                   \    wait 40 us = LCD cycle
16735     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
16736     $2 20_US                   \    wait 40 us = LCD cycle
16737     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
16738     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
16739     LCD_Clear                   \ 10- "LCD_Clear"
16740     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
16741     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
16742     LCD_Clear                   \ 10- "LCD_Clear"
16743     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
16744     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
16745     CR ." I love you"   
16746     ['] (CR) IS CR              \ ' (CR) is CR
16747     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
16748     CR
16749     ."    RC5toLCD is running. Type STOP to quit"
16750 \    NOECHO                      \ uncomment to run this app without terminal connexion
16751     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
16752     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
16753 ;
16754     \
16755
16756 : STOP                  \ stops multitasking, must to be used before downloading app
16757     ['] (WARM) IS WARM  \ remove START app from FORTH init process
16758     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
16759 ;
16760     \
16761
16762
16763 RST_STATE   ;
16764
16765
16766 CODE MAX    \    n1 n2 -- n3       signed maximum
16767             CMP     @PSP,TOS    \ n2-n1
16768             S<      ?GOTO FW1   \ n2<n1
16769 BW1         ADD     #2,PSP
16770             MOV     @IP+,PC
16771 ENDCODE
16772     \
16773
16774 CODE MIN    \    n1 n2 -- n3       signed minimum
16775             CMP     @PSP,TOS     \ n2-n1
16776             S<      ?GOTO BW1    \ n2<n1
16777 FW1         MOV     @PSP+,TOS
16778             MOV     @IP+,PC
16779 ENDCODE
16780     \
16781
16782 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
16783   >R  <# 0 # #S #>  
16784   R> OVER - 0 MAX SPACES TYPE
16785 ;
16786     \
16787
16788 CODE 20_US                      \ n --      n * 20 us
16789 BEGIN                           \ 3 cycles loop + 6~  
16790 \    MOV     #5,W                \ 3 MCLK = 1 MHz
16791 \    MOV     #23,W               \ 3 MCLK = 4 MHz
16792     MOV     #51,W               \ 3 MCLK = 8 MHz
16793 \    MOV     #104,W              \ 3 MCLK = 16 MHz
16794 \    MOV     #158,W              \ 3 MCLK = 24 MHz
16795     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
16796         SUB #1,W                \ 1
16797     0= UNTIL                    \ 2
16798     SUB     #1,TOS              \ 1
16799 0= UNTIL                        \ 2
16800     MOV     @PSP+,TOS           \ 2
16801     MOV     @IP+,PC             \ 4
16802 ENDCODE
16803     \
16804
16805 CODE TOP_LCD                    \ LCD Sample
16806 \                               \ if write : %xxxxWWWW --
16807 \                               \ if read  : -- %0000RRRR
16808     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
16809     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
16810 0= IF                           \ write LCD bits pattern
16811     AND.B #LCD_DB,TOS           \ 
16812     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
16813     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
16814     MOV @PSP+,TOS               \
16815     MOV @IP+,PC
16816 THEN                            \ read LCD bits pattern
16817     SUB #2,PSP
16818     MOV TOS,0(PSP)
16819     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
16820     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
16821     AND.B #LCD_DB,TOS           \
16822     MOV @IP+,PC
16823 ENDCODE
16824     \
16825
16826 CODE LCD_W                      \ byte --       write byte to LCD 
16827     SUB #2,PSP                  \
16828     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
16829     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
16830     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
16831     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
16832 COLON                           \ high level word starts here 
16833     TOP_LCD 2 20_US             \ write high nibble first
16834     TOP_LCD 2 20_US 
16835 ;
16836     \
16837
16838 CODE LCD_WrC                    \ char --         Write Char
16839     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
16840     JMP LCD_W 
16841 ENDCODE
16842     \
16843
16844 CODE LCD_WrF                    \ func --         Write Fonction
16845     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
16846     JMP LCD_W 
16847 ENDCODE
16848     \
16849
16850 : LCD_Clear 
16851     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
16852 ;
16853     \
16854
16855 : LCD_Home 
16856     $02 LCD_WrF 100 20_us 
16857 ;
16858     \
16859
16860 \ : LCD_Entry_set       $04 OR LCD_WrF ;
16861
16862 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
16863
16864 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
16865
16866 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
16867
16868 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
16869
16870 \ : LCD_Goto            $80 OR LCD_WrF ;
16871
16872 \ CODE LCD_R                      \ -- byte       read byte from LCD
16873 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
16874 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
16875 \ COLON                           \ starts a FORTH word
16876 \     TOP_LCD 2 20_us             \ -- %0000HHHH
16877 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
16878 \ HI2LO                           \ switch from FORTH to assembler
16879 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
16880 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
16881 \     MOV @RSP+,IP                \ restore IP saved by COLON
16882 \     MOV @IP+,PC                 \
16883 \ ENDCODE
16884 \     \
16885
16886 \ CODE LCD_RdS                    \ -- status       Read Status
16887 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
16888 \     JMP LCD_R
16889 \ ENDCODE
16890 \     \
16891
16892 \ CODE LCD_RdC                    \ -- char         Read Char
16893 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
16894 \     JMP LCD_R
16895 \ ENDCODE
16896 \     \
16897
16898 \ -------------+------+------+------+------++---+---+---+---+---------+
16899 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
16900 \ -------------+------+------+------+------++---+---+---+---+---------+
16901 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
16902 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
16903 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
16904 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
16905 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
16906 \ -------------+------+------+------+------++---+---+---+---+---------+
16907
16908
16909 \ ******************************\
16910 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
16911 \ ******************************\
16912 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
16913 \ ------------------------------\
16914 \ define LPM mode for ACCEPT    \
16915 \ ------------------------------\
16916 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
16917 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
16918 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
16919 BIT.B #SW2,&SW2_IN              \ test switch S2
16920 0= IF                           \ case of switch S2 pressed
16921     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
16922     U< IF
16923         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
16924     THEN
16925 ELSE
16926     BIT.B #SW1,&SW1_IN          \ test switch S1 input
16927     0= IF                       \ case of Switch S1 pressed
16928         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
16929         U>= IF                  \
16930             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
16931         THEN                    \
16932     THEN                        \
16933 THEN                            \
16934 RETI                            \ CPU is ON, GIE is OFF
16935 ENDASM                          \
16936     \
16937
16938
16939 \ ------------------------------\
16940 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
16941 \ ******************************\
16942 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
16943 \ ******************************\
16944 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
16945 \                               \       SMclock = 8|16|24 MHz
16946 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
16947 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
16948 \                               \       SR(9)=new Toggle bit memory (ADD on)
16949 \ ------------------------------\
16950 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
16951 \ ------------------------------\
16952 \ define LPM mode for ACCEPT    \
16953 \ ------------------------------\
16954 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
16955 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
16956 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
16957 \ ------------------------------\
16958 \ RC5_FirstStartBitHalfCycle:   \
16959 \ ------------------------------\
16960 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
16961 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
16962 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
16963 MOV     #1778,X                 \ RC5_Period in us
16964 MOV     #14,W                   \ count of loop
16965 BEGIN                           \
16966 \ ------------------------------\
16967 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
16968 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
16969     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
16970 \ RC5_Compute_3/4_Period:       \                   |
16971     RRUM    #1,X                \ X=1/2 cycle       |
16972     MOV     X,Y                 \ Y=1/2             ^
16973     RRUM    #1,Y                \ Y=1/4
16974     ADD     X,Y                 \ Y=3/4
16975 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
16976     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
16977     0= UNTIL                    \
16978 \ ------------------------------\
16979 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
16980 \ ------------------------------\
16981     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
16982     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
16983     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
16984     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
16985     SUB     #1,W                \ decrement count loop
16986 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
16987 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
16988 0<> WHILE                       \ ----> out of loop ----+
16989 \ RC5_compute_7/4_Time_out:     \                       |
16990     ADD     X,Y                 \                       |   out of bound = 7/4 period 
16991 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
16992     BEGIN                       \                       |
16993         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
16994         0>= IF                  \                       |   if cycle time out of bound
16995             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
16996             RETI                \                       |   then quit to do nothing
16997         THEN                    \                       |
16998 \ ------------------------------\                       |
16999         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
17000     0<> UNTIL                   \                   |   |
17001     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
17002 REPEAT                          \ ----> loop back --+   |
17003 \ ------------------------------\                       |
17004 \ RC5_SampleEndOf:              \ <---------------------+
17005 \ ------------------------------\
17006 BIC     #$30,&TA0CTL           \ stop timer_A0
17007 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
17008 \ ******************************\
17009 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
17010 \ ******************************\
17011 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
17012 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
17013 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
17014 BIT     #BIT13,X                \ X(13) = New_RC5_command
17015 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
17016 THEN                            \
17017 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
17018 \ ******************************\
17019 \ RC5_ComputeNewRC5word         \
17020 \ ******************************\
17021 SUB     #4,PSP                  \
17022 MOV     &BASE,2(PSP)            \ save variable BASE before use
17023 MOV     TOS,0(PSP)              \ save TOS before use
17024 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
17025 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
17026 \ ******************************\
17027 \ RC5_ComputeC6bit              \
17028 \ ******************************\
17029 BIT     #$4000,IP              \ test /C6 bit in IP
17030 0= IF   BIS #$40,TOS           \ set C6 bit in S
17031 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
17032 \ ******************************\
17033 \ RC5_CommandByteIsDone         \ RC5_code --
17034 \ ******************************\
17035
17036 \ ------------------------------\
17037 \ Display IR_RC5 code           \
17038 \ ------------------------------\
17039 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
17040 \ ------------------------------\
17041 LO2HI                           \ switch from assembler to FORTH
17042     ['] LCD_CLEAR IS CR         \ redirects CR
17043     ['] LCD_WrC  IS EMIT        \ redirects EMIT
17044     $10 BASE !                 \ change BASE to hexadecimal
17045     CR ." $" 2 U.R             \ print IR_RC5 code
17046     ['] (CR) IS CR              \ restore CR
17047     ['] (EMIT) IS EMIT          \ restore EMIT
17048 HI2LO                           \ switch from FORTH to assembler
17049 \ ------------------------------\
17050 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
17051 \ ------------------------------\
17052 MOV @PSP+,&BASE                 \ restore variable BASE
17053 RETI                            \ CPU is ON, GIE is OFF
17054 ENDASM                          \
17055     \ 
17056
17057 CODE START                      \
17058 \ ------------------------------\
17059 \ TB0CTL = %0000 0010 1001 0100\$3C0
17060 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
17061 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
17062 \                      --       \ID input divider \ 10 = /4
17063 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
17064 \                            -  \TBCLR TimerB Clear
17065 \                             - \TBIE
17066 \                              -\TBIFG
17067 \ --------------------------------\\
17068 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
17069 \              --                 \CM Capture Mode
17070 \                --               \CCIS
17071 \                   -             \SCS
17072 \                    --           \CLLD
17073 \                      -          \CAP
17074 \                        ---      \OUTMOD \ 011 = set/reset
17075 \                           -     \CCIE
17076 \                             -   \CCI
17077 \                              -  \OUT
17078 \                               - \COV
17079 \                                -\CCIFG
17080 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
17081 \ TB0EX0                          \$3E0 
17082 \ ------------------------------\
17083 \ set TimerB to make 50kHz PWM  \
17084 \ ------------------------------\
17085 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
17086 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
17087 \ ------------------------------\
17088 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
17089 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
17090 \ ------------------------------\
17091     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
17092     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
17093 \ ------------------------------\
17094 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
17095 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
17096 \ ------------------------------\
17097 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
17098 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
17099 \ ------------------------------\
17100     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
17101 \ ------------------------------\
17102 \ set TimerB to generate PWM for LCD_Vo
17103 \ ------------------------------\
17104     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
17105 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
17106     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
17107 \ ------------------------------\
17108     BIS.B #LCDVo,&LCDVo_DIR     \
17109     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
17110 \ ------------------------------\
17111     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
17112     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
17113 \ ------------------------------\
17114     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
17115     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
17116 \ ------------------------------\
17117 \ WDT interval init part        \
17118 \ ------------------------------\
17119     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
17120 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
17121 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
17122     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
17123 \ ------------------------------\
17124 \ init RC5_Int                  \
17125 \ ------------------------------\
17126     BIS.B #RC5,&IR_IE           \ enable RC5_Int
17127     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
17128 \ ------------------------------\
17129 \ init interrupt vectors
17130 \ ------------------------------\
17131     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
17132     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
17133 \ ------------------------------\
17134 \ define LPM mode for ACCEPT    \
17135 \ ------------------------------\
17136 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
17137 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
17138 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
17139
17140 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
17141
17142 \ ------------------------------\
17143 \ Init LCD 2x20                 \
17144 \ ------------------------------\
17145     $03E8 20_US                \ 1-  wait 20 ms
17146     $03 TOP_LCD                \ 2- send DB5=DB4=1
17147     $CD 20_US                  \ 3- wait 4,1 ms
17148     $03 TOP_LCD                \ 4- send again DB5=DB4=1
17149     $5 20_US                   \ 5- wait 0,1 ms
17150     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
17151     $2 20_US                   \    wait 40 us = LCD cycle
17152     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
17153     $2 20_US                   \    wait 40 us = LCD cycle
17154     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
17155     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
17156     LCD_Clear                   \ 10- "LCD_Clear"
17157     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
17158     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
17159     LCD_Clear                   \ 10- "LCD_Clear"
17160     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
17161     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
17162     CR ." I love you"   
17163     ['] (CR) IS CR              \ ' (CR) is CR
17164     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
17165     CR
17166     ."    RC5toLCD is running. Type STOP to quit"
17167 \    NOECHO                      \ uncomment to run this app without terminal connexion
17168     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
17169     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
17170 ;
17171     \
17172
17173 : STOP                  \ stops multitasking, must to be used before downloading app
17174     ['] (WARM) IS WARM  \ remove START app from FORTH init process
17175     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
17176 ;
17177     \
17178
17179
17180 RST_STATE   ;
17181
17182
17183 CODE MAX    \    n1 n2 -- n3       signed maximum
17184             CMP     @PSP,TOS    \ n2-n1
17185             S<      ?GOTO FW1   \ n2<n1
17186 BW1         ADD     #2,PSP
17187             MOV     @IP+,PC
17188 ENDCODE
17189     \
17190
17191 CODE MIN    \    n1 n2 -- n3       signed minimum
17192             CMP     @PSP,TOS     \ n2-n1
17193             S<      ?GOTO BW1    \ n2<n1
17194 FW1         MOV     @PSP+,TOS
17195             MOV     @IP+,PC
17196 ENDCODE
17197     \
17198
17199 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
17200   >R  <# 0 # #S #>  
17201   R> OVER - 0 MAX SPACES TYPE
17202 ;
17203     \
17204
17205 CODE 20_US                      \ n --      n * 20 us
17206 BEGIN                           \ 3 cycles loop + 6~  
17207 \    MOV     #5,W                \ 3 MCLK = 1 MHz
17208 \    MOV     #23,W               \ 3 MCLK = 4 MHz
17209     MOV     #51,W               \ 3 MCLK = 8 MHz
17210 \    MOV     #104,W              \ 3 MCLK = 16 MHz
17211 \    MOV     #158,W              \ 3 MCLK = 24 MHz
17212     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
17213         SUB #1,W                \ 1
17214     0= UNTIL                    \ 2
17215     SUB     #1,TOS              \ 1
17216 0= UNTIL                        \ 2
17217     MOV     @PSP+,TOS           \ 2
17218     MOV     @IP+,PC             \ 4
17219 ENDCODE
17220     \
17221
17222 CODE TOP_LCD                    \ LCD Sample
17223 \                               \ if write : %xxxxWWWW --
17224 \                               \ if read  : -- %0000RRRR
17225     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
17226     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
17227 0= IF                           \ write LCD bits pattern
17228     AND.B #LCD_DB,TOS           \ 
17229     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
17230     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
17231     MOV @PSP+,TOS               \
17232     MOV @IP+,PC
17233 THEN                            \ read LCD bits pattern
17234     SUB #2,PSP
17235     MOV TOS,0(PSP)
17236     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
17237     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
17238     AND.B #LCD_DB,TOS           \
17239     MOV @IP+,PC
17240 ENDCODE
17241     \
17242
17243 CODE LCD_W                      \ byte --       write byte to LCD 
17244     SUB #2,PSP                  \
17245     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
17246     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
17247     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
17248     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
17249 COLON                           \ high level word starts here 
17250     TOP_LCD 2 20_US             \ write high nibble first
17251     TOP_LCD 2 20_US 
17252 ;
17253     \
17254
17255 CODE LCD_WrC                    \ char --         Write Char
17256     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
17257     JMP LCD_W 
17258 ENDCODE
17259     \
17260
17261 CODE LCD_WrF                    \ func --         Write Fonction
17262     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
17263     JMP LCD_W 
17264 ENDCODE
17265     \
17266
17267 : LCD_Clear 
17268     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
17269 ;
17270     \
17271
17272 : LCD_Home 
17273     $02 LCD_WrF 100 20_us 
17274 ;
17275     \
17276
17277 \ : LCD_Entry_set       $04 OR LCD_WrF ;
17278
17279 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
17280
17281 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
17282
17283 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
17284
17285 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
17286
17287 \ : LCD_Goto            $80 OR LCD_WrF ;
17288
17289 \ CODE LCD_R                      \ -- byte       read byte from LCD
17290 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
17291 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
17292 \ COLON                           \ starts a FORTH word
17293 \     TOP_LCD 2 20_us             \ -- %0000HHHH
17294 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
17295 \ HI2LO                           \ switch from FORTH to assembler
17296 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
17297 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
17298 \     MOV @RSP+,IP                \ restore IP saved by COLON
17299 \     MOV @IP+,PC                 \
17300 \ ENDCODE
17301 \     \
17302
17303 \ CODE LCD_RdS                    \ -- status       Read Status
17304 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
17305 \     JMP LCD_R
17306 \ ENDCODE
17307 \     \
17308
17309 \ CODE LCD_RdC                    \ -- char         Read Char
17310 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
17311 \     JMP LCD_R
17312 \ ENDCODE
17313 \     \
17314
17315 \ -------------+------+------+------+------++---+---+---+---+---------+
17316 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
17317 \ -------------+------+------+------+------++---+---+---+---+---------+
17318 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
17319 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
17320 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
17321 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
17322 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
17323 \ -------------+------+------+------+------++---+---+---+---+---------+
17324
17325
17326 \ ******************************\
17327 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
17328 \ ******************************\
17329 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
17330 \ ------------------------------\
17331 \ define LPM mode for ACCEPT    \
17332 \ ------------------------------\
17333 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
17334 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
17335 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
17336 BIT.B #SW2,&SW2_IN              \ test switch S2
17337 0= IF                           \ case of switch S2 pressed
17338     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
17339     U< IF
17340         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
17341     THEN
17342 ELSE
17343     BIT.B #SW1,&SW1_IN          \ test switch S1 input
17344     0= IF                       \ case of Switch S1 pressed
17345         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
17346         U>= IF                  \
17347             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
17348         THEN                    \
17349     THEN                        \
17350 THEN                            \
17351 RETI                            \ CPU is ON, GIE is OFF
17352 ENDASM                          \
17353     \
17354
17355
17356 \ ------------------------------\
17357 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
17358 \ ******************************\
17359 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
17360 \ ******************************\
17361 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
17362 \                               \       SMclock = 8|16|24 MHz
17363 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
17364 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
17365 \                               \       SR(9)=new Toggle bit memory (ADD on)
17366 \ ------------------------------\
17367 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
17368 \ ------------------------------\
17369 \ define LPM mode for ACCEPT    \
17370 \ ------------------------------\
17371 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
17372 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
17373 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
17374 \ ------------------------------\
17375 \ RC5_FirstStartBitHalfCycle:   \
17376 \ ------------------------------\
17377 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
17378 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
17379 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
17380 MOV     #1778,X                 \ RC5_Period in us
17381 MOV     #14,W                   \ count of loop
17382 BEGIN                           \
17383 \ ------------------------------\
17384 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
17385 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
17386     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
17387 \ RC5_Compute_3/4_Period:       \                   |
17388     RRUM    #1,X                \ X=1/2 cycle       |
17389     MOV     X,Y                 \ Y=1/2             ^
17390     RRUM    #1,Y                \ Y=1/4
17391     ADD     X,Y                 \ Y=3/4
17392 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
17393     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
17394     0= UNTIL                    \
17395 \ ------------------------------\
17396 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
17397 \ ------------------------------\
17398     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
17399     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
17400     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
17401     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
17402     SUB     #1,W                \ decrement count loop
17403 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
17404 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
17405 0<> WHILE                       \ ----> out of loop ----+
17406 \ RC5_compute_7/4_Time_out:     \                       |
17407     ADD     X,Y                 \                       |   out of bound = 7/4 period 
17408 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
17409     BEGIN                       \                       |
17410         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
17411         0>= IF                  \                       |   if cycle time out of bound
17412             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
17413             RETI                \                       |   then quit to do nothing
17414         THEN                    \                       |
17415 \ ------------------------------\                       |
17416         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
17417     0<> UNTIL                   \                   |   |
17418     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
17419 REPEAT                          \ ----> loop back --+   |
17420 \ ------------------------------\                       |
17421 \ RC5_SampleEndOf:              \ <---------------------+
17422 \ ------------------------------\
17423 BIC     #$30,&TA0CTL           \ stop timer_A0
17424 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
17425 \ ******************************\
17426 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
17427 \ ******************************\
17428 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
17429 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
17430 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
17431 BIT     #BIT13,X                \ X(13) = New_RC5_command
17432 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
17433 THEN                            \
17434 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
17435 \ ******************************\
17436 \ RC5_ComputeNewRC5word         \
17437 \ ******************************\
17438 SUB     #4,PSP                  \
17439 MOV     &BASE,2(PSP)            \ save variable BASE before use
17440 MOV     TOS,0(PSP)              \ save TOS before use
17441 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
17442 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
17443 \ ******************************\
17444 \ RC5_ComputeC6bit              \
17445 \ ******************************\
17446 BIT     #$4000,IP              \ test /C6 bit in IP
17447 0= IF   BIS #$40,TOS           \ set C6 bit in S
17448 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
17449 \ ******************************\
17450 \ RC5_CommandByteIsDone         \ RC5_code --
17451 \ ******************************\
17452
17453 \ ------------------------------\
17454 \ Display IR_RC5 code           \
17455 \ ------------------------------\
17456 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
17457 \ ------------------------------\
17458 LO2HI                           \ switch from assembler to FORTH
17459     ['] LCD_CLEAR IS CR         \ redirects CR
17460     ['] LCD_WrC  IS EMIT        \ redirects EMIT
17461     $10 BASE !                 \ change BASE to hexadecimal
17462     CR ." $" 2 U.R             \ print IR_RC5 code
17463     ['] (CR) IS CR              \ restore CR
17464     ['] (EMIT) IS EMIT          \ restore EMIT
17465 HI2LO                           \ switch from FORTH to assembler
17466 \ ------------------------------\
17467 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
17468 \ ------------------------------\
17469 MOV @PSP+,&BASE                 \ restore variable BASE
17470 RETI                            \ CPU is ON, GIE is OFF
17471 ENDASM                          \
17472     \ 
17473
17474 CODE START                      \
17475 \ ------------------------------\
17476 \ TB0CTL = %0000 0010 1001 0100\$3C0
17477 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
17478 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
17479 \                      --       \ID input divider \ 10 = /4
17480 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
17481 \                            -  \TBCLR TimerB Clear
17482 \                             - \TBIE
17483 \                              -\TBIFG
17484 \ --------------------------------\\
17485 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
17486 \              --                 \CM Capture Mode
17487 \                --               \CCIS
17488 \                   -             \SCS
17489 \                    --           \CLLD
17490 \                      -          \CAP
17491 \                        ---      \OUTMOD \ 011 = set/reset
17492 \                           -     \CCIE
17493 \                             -   \CCI
17494 \                              -  \OUT
17495 \                               - \COV
17496 \                                -\CCIFG
17497 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
17498 \ TB0EX0                          \$3E0 
17499 \ ------------------------------\
17500 \ set TimerB to make 50kHz PWM  \
17501 \ ------------------------------\
17502 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
17503 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
17504 \ ------------------------------\
17505 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
17506 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
17507 \ ------------------------------\
17508     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
17509     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
17510 \ ------------------------------\
17511 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
17512 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
17513 \ ------------------------------\
17514 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
17515 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
17516 \ ------------------------------\
17517     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
17518 \ ------------------------------\
17519 \ set TimerB to generate PWM for LCD_Vo
17520 \ ------------------------------\
17521     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
17522 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
17523     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
17524 \ ------------------------------\
17525     BIS.B #LCDVo,&LCDVo_DIR     \
17526     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
17527 \ ------------------------------\
17528     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
17529     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
17530 \ ------------------------------\
17531     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
17532     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
17533 \ ------------------------------\
17534 \ WDT interval init part        \
17535 \ ------------------------------\
17536     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
17537 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
17538 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
17539     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
17540 \ ------------------------------\
17541 \ init RC5_Int                  \
17542 \ ------------------------------\
17543     BIS.B #RC5,&IR_IE           \ enable RC5_Int
17544     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
17545 \ ------------------------------\
17546 \ init interrupt vectors
17547 \ ------------------------------\
17548     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
17549     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
17550 \ ------------------------------\
17551 \ define LPM mode for ACCEPT    \
17552 \ ------------------------------\
17553 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
17554 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
17555 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
17556
17557 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
17558
17559 \ ------------------------------\
17560 \ Init LCD 2x20                 \
17561 \ ------------------------------\
17562     $03E8 20_US                \ 1-  wait 20 ms
17563     $03 TOP_LCD                \ 2- send DB5=DB4=1
17564     $CD 20_US                  \ 3- wait 4,1 ms
17565     $03 TOP_LCD                \ 4- send again DB5=DB4=1
17566     $5 20_US                   \ 5- wait 0,1 ms
17567     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
17568     $2 20_US                   \    wait 40 us = LCD cycle
17569     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
17570     $2 20_US                   \    wait 40 us = LCD cycle
17571     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
17572     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
17573     LCD_Clear                   \ 10- "LCD_Clear"
17574     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
17575     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
17576     LCD_Clear                   \ 10- "LCD_Clear"
17577     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
17578     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
17579     CR ." I love you"   
17580     ['] (CR) IS CR              \ ' (CR) is CR
17581     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
17582     CR
17583     ."    RC5toLCD is running. Type STOP to quit"
17584 \    NOECHO                      \ uncomment to run this app without terminal connexion
17585     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
17586     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
17587 ;
17588     \
17589
17590 : STOP                  \ stops multitasking, must to be used before downloading app
17591     ['] (WARM) IS WARM  \ remove START app from FORTH init process
17592     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
17593 ;
17594     \
17595
17596
17597 RST_STATE   ;
17598
17599
17600 CODE MAX    \    n1 n2 -- n3       signed maximum
17601             CMP     @PSP,TOS    \ n2-n1
17602             S<      ?GOTO FW1   \ n2<n1
17603 BW1         ADD     #2,PSP
17604             MOV     @IP+,PC
17605 ENDCODE
17606     \
17607
17608 CODE MIN    \    n1 n2 -- n3       signed minimum
17609             CMP     @PSP,TOS     \ n2-n1
17610             S<      ?GOTO BW1    \ n2<n1
17611 FW1         MOV     @PSP+,TOS
17612             MOV     @IP+,PC
17613 ENDCODE
17614     \
17615
17616 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
17617   >R  <# 0 # #S #>  
17618   R> OVER - 0 MAX SPACES TYPE
17619 ;
17620     \
17621
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
17630         SUB #1,W                \ 1
17631     0= UNTIL                    \ 2
17632     SUB     #1,TOS              \ 1
17633 0= UNTIL                        \ 2
17634     MOV     @PSP+,TOS           \ 2
17635     MOV     @IP+,PC             \ 4
17636 ENDCODE
17637     \
17638
17639 CODE TOP_LCD                    \ LCD Sample
17640 \                               \ if write : %xxxxWWWW --
17641 \                               \ if read  : -- %0000RRRR
17642     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
17643     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
17644 0= IF                           \ write LCD bits pattern
17645     AND.B #LCD_DB,TOS           \ 
17646     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
17647     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
17648     MOV @PSP+,TOS               \
17649     MOV @IP+,PC
17650 THEN                            \ read LCD bits pattern
17651     SUB #2,PSP
17652     MOV TOS,0(PSP)
17653     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
17654     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
17655     AND.B #LCD_DB,TOS           \
17656     MOV @IP+,PC
17657 ENDCODE
17658     \
17659
17660 CODE LCD_W                      \ byte --       write byte to LCD 
17661     SUB #2,PSP                  \
17662     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
17663     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
17664     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
17665     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
17666 COLON                           \ high level word starts here 
17667     TOP_LCD 2 20_US             \ write high nibble first
17668     TOP_LCD 2 20_US 
17669 ;
17670     \
17671
17672 CODE LCD_WrC                    \ char --         Write Char
17673     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
17674     JMP LCD_W 
17675 ENDCODE
17676     \
17677
17678 CODE LCD_WrF                    \ func --         Write Fonction
17679     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
17680     JMP LCD_W 
17681 ENDCODE
17682     \
17683
17684 : LCD_Clear 
17685     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
17686 ;
17687     \
17688
17689 : LCD_Home 
17690     $02 LCD_WrF 100 20_us 
17691 ;
17692     \
17693
17694 \ : LCD_Entry_set       $04 OR LCD_WrF ;
17695
17696 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
17697
17698 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
17699
17700 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
17701
17702 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
17703
17704 \ : LCD_Goto            $80 OR LCD_WrF ;
17705
17706 \ CODE LCD_R                      \ -- byte       read byte from LCD
17707 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
17708 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
17709 \ COLON                           \ starts a FORTH word
17710 \     TOP_LCD 2 20_us             \ -- %0000HHHH
17711 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
17712 \ HI2LO                           \ switch from FORTH to assembler
17713 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
17714 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
17715 \     MOV @RSP+,IP                \ restore IP saved by COLON
17716 \     MOV @IP+,PC                 \
17717 \ ENDCODE
17718 \     \
17719
17720 \ CODE LCD_RdS                    \ -- status       Read Status
17721 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
17722 \     JMP LCD_R
17723 \ ENDCODE
17724 \     \
17725
17726 \ CODE LCD_RdC                    \ -- char         Read Char
17727 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
17728 \     JMP LCD_R
17729 \ ENDCODE
17730 \     \
17731
17732 \ -------------+------+------+------+------++---+---+---+---+---------+
17733 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
17734 \ -------------+------+------+------+------++---+---+---+---+---------+
17735 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
17736 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
17737 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
17738 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
17739 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
17740 \ -------------+------+------+------+------++---+---+---+---+---------+
17741
17742
17743 \ ******************************\
17744 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
17745 \ ******************************\
17746 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
17747 \ ------------------------------\
17748 \ define LPM mode for ACCEPT    \
17749 \ ------------------------------\
17750 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
17751 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
17752 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
17753 BIT.B #SW2,&SW2_IN              \ test switch S2
17754 0= IF                           \ case of switch S2 pressed
17755     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
17756     U< IF
17757         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
17758     THEN
17759 ELSE
17760     BIT.B #SW1,&SW1_IN          \ test switch S1 input
17761     0= IF                       \ case of Switch S1 pressed
17762         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
17763         U>= IF                  \
17764             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
17765         THEN                    \
17766     THEN                        \
17767 THEN                            \
17768 RETI                            \ CPU is ON, GIE is OFF
17769 ENDASM                          \
17770     \
17771
17772
17773 \ ------------------------------\
17774 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
17775 \ ******************************\
17776 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
17777 \ ******************************\
17778 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
17779 \                               \       SMclock = 8|16|24 MHz
17780 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
17781 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
17782 \                               \       SR(9)=new Toggle bit memory (ADD on)
17783 \ ------------------------------\
17784 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
17785 \ ------------------------------\
17786 \ define LPM mode for ACCEPT    \
17787 \ ------------------------------\
17788 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
17789 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
17790 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
17791 \ ------------------------------\
17792 \ RC5_FirstStartBitHalfCycle:   \
17793 \ ------------------------------\
17794 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
17795 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
17796 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
17797 MOV     #1778,X                 \ RC5_Period in us
17798 MOV     #14,W                   \ count of loop
17799 BEGIN                           \
17800 \ ------------------------------\
17801 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
17802 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
17803     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
17804 \ RC5_Compute_3/4_Period:       \                   |
17805     RRUM    #1,X                \ X=1/2 cycle       |
17806     MOV     X,Y                 \ Y=1/2             ^
17807     RRUM    #1,Y                \ Y=1/4
17808     ADD     X,Y                 \ Y=3/4
17809 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
17810     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
17811     0= UNTIL                    \
17812 \ ------------------------------\
17813 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
17814 \ ------------------------------\
17815     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
17816     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
17817     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
17818     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
17819     SUB     #1,W                \ decrement count loop
17820 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
17821 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
17822 0<> WHILE                       \ ----> out of loop ----+
17823 \ RC5_compute_7/4_Time_out:     \                       |
17824     ADD     X,Y                 \                       |   out of bound = 7/4 period 
17825 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
17826     BEGIN                       \                       |
17827         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
17828         0>= IF                  \                       |   if cycle time out of bound
17829             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
17830             RETI                \                       |   then quit to do nothing
17831         THEN                    \                       |
17832 \ ------------------------------\                       |
17833         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
17834     0<> UNTIL                   \                   |   |
17835     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
17836 REPEAT                          \ ----> loop back --+   |
17837 \ ------------------------------\                       |
17838 \ RC5_SampleEndOf:              \ <---------------------+
17839 \ ------------------------------\
17840 BIC     #$30,&TA0CTL           \ stop timer_A0
17841 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
17842 \ ******************************\
17843 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
17844 \ ******************************\
17845 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
17846 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
17847 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
17848 BIT     #BIT13,X                \ X(13) = New_RC5_command
17849 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
17850 THEN                            \
17851 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
17852 \ ******************************\
17853 \ RC5_ComputeNewRC5word         \
17854 \ ******************************\
17855 SUB     #4,PSP                  \
17856 MOV     &BASE,2(PSP)            \ save variable BASE before use
17857 MOV     TOS,0(PSP)              \ save TOS before use
17858 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
17859 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
17860 \ ******************************\
17861 \ RC5_ComputeC6bit              \
17862 \ ******************************\
17863 BIT     #$4000,IP              \ test /C6 bit in IP
17864 0= IF   BIS #$40,TOS           \ set C6 bit in S
17865 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
17866 \ ******************************\
17867 \ RC5_CommandByteIsDone         \ RC5_code --
17868 \ ******************************\
17869
17870 \ ------------------------------\
17871 \ Display IR_RC5 code           \
17872 \ ------------------------------\
17873 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
17874 \ ------------------------------\
17875 LO2HI                           \ switch from assembler to FORTH
17876     ['] LCD_CLEAR IS CR         \ redirects CR
17877     ['] LCD_WrC  IS EMIT        \ redirects EMIT
17878     $10 BASE !                 \ change BASE to hexadecimal
17879     CR ." $" 2 U.R             \ print IR_RC5 code
17880     ['] (CR) IS CR              \ restore CR
17881     ['] (EMIT) IS EMIT          \ restore EMIT
17882 HI2LO                           \ switch from FORTH to assembler
17883 \ ------------------------------\
17884 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
17885 \ ------------------------------\
17886 MOV @PSP+,&BASE                 \ restore variable BASE
17887 RETI                            \ CPU is ON, GIE is OFF
17888 ENDASM                          \
17889     \ 
17890
17891 CODE START                      \
17892 \ ------------------------------\
17893 \ TB0CTL = %0000 0010 1001 0100\$3C0
17894 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
17895 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
17896 \                      --       \ID input divider \ 10 = /4
17897 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
17898 \                            -  \TBCLR TimerB Clear
17899 \                             - \TBIE
17900 \                              -\TBIFG
17901 \ --------------------------------\\
17902 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
17903 \              --                 \CM Capture Mode
17904 \                --               \CCIS
17905 \                   -             \SCS
17906 \                    --           \CLLD
17907 \                      -          \CAP
17908 \                        ---      \OUTMOD \ 011 = set/reset
17909 \                           -     \CCIE
17910 \                             -   \CCI
17911 \                              -  \OUT
17912 \                               - \COV
17913 \                                -\CCIFG
17914 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
17915 \ TB0EX0                          \$3E0 
17916 \ ------------------------------\
17917 \ set TimerB to make 50kHz PWM  \
17918 \ ------------------------------\
17919 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
17920 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
17921 \ ------------------------------\
17922 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
17923 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
17924 \ ------------------------------\
17925     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
17926     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
17927 \ ------------------------------\
17928 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
17929 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
17930 \ ------------------------------\
17931 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
17932 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
17933 \ ------------------------------\
17934     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
17935 \ ------------------------------\
17936 \ set TimerB to generate PWM for LCD_Vo
17937 \ ------------------------------\
17938     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
17939 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
17940     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
17941 \ ------------------------------\
17942     BIS.B #LCDVo,&LCDVo_DIR     \
17943     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
17944 \ ------------------------------\
17945     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
17946     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
17947 \ ------------------------------\
17948     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
17949     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
17950 \ ------------------------------\
17951 \ WDT interval init part        \
17952 \ ------------------------------\
17953     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
17954 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
17955 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
17956     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
17957 \ ------------------------------\
17958 \ init RC5_Int                  \
17959 \ ------------------------------\
17960     BIS.B #RC5,&IR_IE           \ enable RC5_Int
17961     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
17962 \ ------------------------------\
17963 \ init interrupt vectors
17964 \ ------------------------------\
17965     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
17966     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
17967 \ ------------------------------\
17968 \ define LPM mode for ACCEPT    \
17969 \ ------------------------------\
17970 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
17971 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
17972 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
17973
17974 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
17975
17976 \ ------------------------------\
17977 \ Init LCD 2x20                 \
17978 \ ------------------------------\
17979     $03E8 20_US                \ 1-  wait 20 ms
17980     $03 TOP_LCD                \ 2- send DB5=DB4=1
17981     $CD 20_US                  \ 3- wait 4,1 ms
17982     $03 TOP_LCD                \ 4- send again DB5=DB4=1
17983     $5 20_US                   \ 5- wait 0,1 ms
17984     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
17985     $2 20_US                   \    wait 40 us = LCD cycle
17986     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
17987     $2 20_US                   \    wait 40 us = LCD cycle
17988     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
17989     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
17990     LCD_Clear                   \ 10- "LCD_Clear"
17991     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
17992     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
17993     LCD_Clear                   \ 10- "LCD_Clear"
17994     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
17995     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
17996     CR ." I love you"   
17997     ['] (CR) IS CR              \ ' (CR) is CR
17998     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
17999     CR
18000     ."    RC5toLCD is running. Type STOP to quit"
18001 \    NOECHO                      \ uncomment to run this app without terminal connexion
18002     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
18003     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
18004 ;
18005     \
18006
18007 : STOP                  \ stops multitasking, must to be used before downloading app
18008     ['] (WARM) IS WARM  \ remove START app from FORTH init process
18009     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
18010 ;
18011     \
18012
18013
18014 RST_STATE   ;
18015
18016
18017 CODE MAX    \    n1 n2 -- n3       signed maximum
18018             CMP     @PSP,TOS    \ n2-n1
18019             S<      ?GOTO FW1   \ n2<n1
18020 BW1         ADD     #2,PSP
18021             MOV     @IP+,PC
18022 ENDCODE
18023     \
18024
18025 CODE MIN    \    n1 n2 -- n3       signed minimum
18026             CMP     @PSP,TOS     \ n2-n1
18027             S<      ?GOTO BW1    \ n2<n1
18028 FW1         MOV     @PSP+,TOS
18029             MOV     @IP+,PC
18030 ENDCODE
18031     \
18032
18033 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
18034   >R  <# 0 # #S #>  
18035   R> OVER - 0 MAX SPACES TYPE
18036 ;
18037     \
18038
18039 CODE 20_US                      \ n --      n * 20 us
18040 BEGIN                           \ 3 cycles loop + 6~  
18041 \    MOV     #5,W                \ 3 MCLK = 1 MHz
18042 \    MOV     #23,W               \ 3 MCLK = 4 MHz
18043     MOV     #51,W               \ 3 MCLK = 8 MHz
18044 \    MOV     #104,W              \ 3 MCLK = 16 MHz
18045 \    MOV     #158,W              \ 3 MCLK = 24 MHz
18046     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
18047         SUB #1,W                \ 1
18048     0= UNTIL                    \ 2
18049     SUB     #1,TOS              \ 1
18050 0= UNTIL                        \ 2
18051     MOV     @PSP+,TOS           \ 2
18052     MOV     @IP+,PC             \ 4
18053 ENDCODE
18054     \
18055
18056 CODE TOP_LCD                    \ LCD Sample
18057 \                               \ if write : %xxxxWWWW --
18058 \                               \ if read  : -- %0000RRRR
18059     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
18060     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
18061 0= IF                           \ write LCD bits pattern
18062     AND.B #LCD_DB,TOS           \ 
18063     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
18064     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
18065     MOV @PSP+,TOS               \
18066     MOV @IP+,PC
18067 THEN                            \ read LCD bits pattern
18068     SUB #2,PSP
18069     MOV TOS,0(PSP)
18070     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
18071     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
18072     AND.B #LCD_DB,TOS           \
18073     MOV @IP+,PC
18074 ENDCODE
18075     \
18076
18077 CODE LCD_W                      \ byte --       write byte to LCD 
18078     SUB #2,PSP                  \
18079     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
18080     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
18081     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
18082     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
18083 COLON                           \ high level word starts here 
18084     TOP_LCD 2 20_US             \ write high nibble first
18085     TOP_LCD 2 20_US 
18086 ;
18087     \
18088
18089 CODE LCD_WrC                    \ char --         Write Char
18090     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
18091     JMP LCD_W 
18092 ENDCODE
18093     \
18094
18095 CODE LCD_WrF                    \ func --         Write Fonction
18096     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
18097     JMP LCD_W 
18098 ENDCODE
18099     \
18100
18101 : LCD_Clear 
18102     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
18103 ;
18104     \
18105
18106 : LCD_Home 
18107     $02 LCD_WrF 100 20_us 
18108 ;
18109     \
18110
18111 \ : LCD_Entry_set       $04 OR LCD_WrF ;
18112
18113 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
18114
18115 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
18116
18117 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
18118
18119 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
18120
18121 \ : LCD_Goto            $80 OR LCD_WrF ;
18122
18123 \ CODE LCD_R                      \ -- byte       read byte from LCD
18124 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
18125 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
18126 \ COLON                           \ starts a FORTH word
18127 \     TOP_LCD 2 20_us             \ -- %0000HHHH
18128 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
18129 \ HI2LO                           \ switch from FORTH to assembler
18130 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
18131 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
18132 \     MOV @RSP+,IP                \ restore IP saved by COLON
18133 \     MOV @IP+,PC                 \
18134 \ ENDCODE
18135 \     \
18136
18137 \ CODE LCD_RdS                    \ -- status       Read Status
18138 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
18139 \     JMP LCD_R
18140 \ ENDCODE
18141 \     \
18142
18143 \ CODE LCD_RdC                    \ -- char         Read Char
18144 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
18145 \     JMP LCD_R
18146 \ ENDCODE
18147 \     \
18148
18149 \ -------------+------+------+------+------++---+---+---+---+---------+
18150 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
18151 \ -------------+------+------+------+------++---+---+---+---+---------+
18152 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
18153 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
18154 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
18155 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
18156 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
18157 \ -------------+------+------+------+------++---+---+---+---+---------+
18158
18159
18160 \ ******************************\
18161 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
18162 \ ******************************\
18163 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
18164 \ ------------------------------\
18165 \ define LPM mode for ACCEPT    \
18166 \ ------------------------------\
18167 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
18168 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
18169 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
18170 BIT.B #SW2,&SW2_IN              \ test switch S2
18171 0= IF                           \ case of switch S2 pressed
18172     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
18173     U< IF
18174         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
18175     THEN
18176 ELSE
18177     BIT.B #SW1,&SW1_IN          \ test switch S1 input
18178     0= IF                       \ case of Switch S1 pressed
18179         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
18180         U>= IF                  \
18181             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
18182         THEN                    \
18183     THEN                        \
18184 THEN                            \
18185 RETI                            \ CPU is ON, GIE is OFF
18186 ENDASM                          \
18187     \
18188
18189
18190 \ ------------------------------\
18191 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
18192 \ ******************************\
18193 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
18194 \ ******************************\
18195 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
18196 \                               \       SMclock = 8|16|24 MHz
18197 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
18198 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
18199 \                               \       SR(9)=new Toggle bit memory (ADD on)
18200 \ ------------------------------\
18201 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
18202 \ ------------------------------\
18203 \ define LPM mode for ACCEPT    \
18204 \ ------------------------------\
18205 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
18206 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
18207 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
18208 \ ------------------------------\
18209 \ RC5_FirstStartBitHalfCycle:   \
18210 \ ------------------------------\
18211 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
18212 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
18213 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
18214 MOV     #1778,X                 \ RC5_Period in us
18215 MOV     #14,W                   \ count of loop
18216 BEGIN                           \
18217 \ ------------------------------\
18218 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
18219 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
18220     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
18221 \ RC5_Compute_3/4_Period:       \                   |
18222     RRUM    #1,X                \ X=1/2 cycle       |
18223     MOV     X,Y                 \ Y=1/2             ^
18224     RRUM    #1,Y                \ Y=1/4
18225     ADD     X,Y                 \ Y=3/4
18226 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
18227     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
18228     0= UNTIL                    \
18229 \ ------------------------------\
18230 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
18231 \ ------------------------------\
18232     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
18233     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
18234     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
18235     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
18236     SUB     #1,W                \ decrement count loop
18237 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
18238 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
18239 0<> WHILE                       \ ----> out of loop ----+
18240 \ RC5_compute_7/4_Time_out:     \                       |
18241     ADD     X,Y                 \                       |   out of bound = 7/4 period 
18242 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
18243     BEGIN                       \                       |
18244         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
18245         0>= IF                  \                       |   if cycle time out of bound
18246             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
18247             RETI                \                       |   then quit to do nothing
18248         THEN                    \                       |
18249 \ ------------------------------\                       |
18250         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
18251     0<> UNTIL                   \                   |   |
18252     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
18253 REPEAT                          \ ----> loop back --+   |
18254 \ ------------------------------\                       |
18255 \ RC5_SampleEndOf:              \ <---------------------+
18256 \ ------------------------------\
18257 BIC     #$30,&TA0CTL           \ stop timer_A0
18258 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
18259 \ ******************************\
18260 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
18261 \ ******************************\
18262 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
18263 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
18264 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
18265 BIT     #BIT13,X                \ X(13) = New_RC5_command
18266 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
18267 THEN                            \
18268 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
18269 \ ******************************\
18270 \ RC5_ComputeNewRC5word         \
18271 \ ******************************\
18272 SUB     #4,PSP                  \
18273 MOV     &BASE,2(PSP)            \ save variable BASE before use
18274 MOV     TOS,0(PSP)              \ save TOS before use
18275 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
18276 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
18277 \ ******************************\
18278 \ RC5_ComputeC6bit              \
18279 \ ******************************\
18280 BIT     #$4000,IP              \ test /C6 bit in IP
18281 0= IF   BIS #$40,TOS           \ set C6 bit in S
18282 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
18283 \ ******************************\
18284 \ RC5_CommandByteIsDone         \ RC5_code --
18285 \ ******************************\
18286
18287 \ ------------------------------\
18288 \ Display IR_RC5 code           \
18289 \ ------------------------------\
18290 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
18291 \ ------------------------------\
18292 LO2HI                           \ switch from assembler to FORTH
18293     ['] LCD_CLEAR IS CR         \ redirects CR
18294     ['] LCD_WrC  IS EMIT        \ redirects EMIT
18295     $10 BASE !                 \ change BASE to hexadecimal
18296     CR ." $" 2 U.R             \ print IR_RC5 code
18297     ['] (CR) IS CR              \ restore CR
18298     ['] (EMIT) IS EMIT          \ restore EMIT
18299 HI2LO                           \ switch from FORTH to assembler
18300 \ ------------------------------\
18301 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
18302 \ ------------------------------\
18303 MOV @PSP+,&BASE                 \ restore variable BASE
18304 RETI                            \ CPU is ON, GIE is OFF
18305 ENDASM                          \
18306     \ 
18307
18308 CODE START                      \
18309 \ ------------------------------\
18310 \ TB0CTL = %0000 0010 1001 0100\$3C0
18311 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
18312 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
18313 \                      --       \ID input divider \ 10 = /4
18314 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
18315 \                            -  \TBCLR TimerB Clear
18316 \                             - \TBIE
18317 \                              -\TBIFG
18318 \ --------------------------------\\
18319 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
18320 \              --                 \CM Capture Mode
18321 \                --               \CCIS
18322 \                   -             \SCS
18323 \                    --           \CLLD
18324 \                      -          \CAP
18325 \                        ---      \OUTMOD \ 011 = set/reset
18326 \                           -     \CCIE
18327 \                             -   \CCI
18328 \                              -  \OUT
18329 \                               - \COV
18330 \                                -\CCIFG
18331 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
18332 \ TB0EX0                          \$3E0 
18333 \ ------------------------------\
18334 \ set TimerB to make 50kHz PWM  \
18335 \ ------------------------------\
18336 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
18337 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
18338 \ ------------------------------\
18339 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
18340 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
18341 \ ------------------------------\
18342     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
18343     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
18344 \ ------------------------------\
18345 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
18346 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
18347 \ ------------------------------\
18348 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
18349 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
18350 \ ------------------------------\
18351     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
18352 \ ------------------------------\
18353 \ set TimerB to generate PWM for LCD_Vo
18354 \ ------------------------------\
18355     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
18356 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
18357     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
18358 \ ------------------------------\
18359     BIS.B #LCDVo,&LCDVo_DIR     \
18360     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
18361 \ ------------------------------\
18362     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
18363     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
18364 \ ------------------------------\
18365     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
18366     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
18367 \ ------------------------------\
18368 \ WDT interval init part        \
18369 \ ------------------------------\
18370     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
18371 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
18372 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
18373     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
18374 \ ------------------------------\
18375 \ init RC5_Int                  \
18376 \ ------------------------------\
18377     BIS.B #RC5,&IR_IE           \ enable RC5_Int
18378     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
18379 \ ------------------------------\
18380 \ init interrupt vectors
18381 \ ------------------------------\
18382     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
18383     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
18384 \ ------------------------------\
18385 \ define LPM mode for ACCEPT    \
18386 \ ------------------------------\
18387 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
18388 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
18389 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
18390
18391 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
18392
18393 \ ------------------------------\
18394 \ Init LCD 2x20                 \
18395 \ ------------------------------\
18396     $03E8 20_US                \ 1-  wait 20 ms
18397     $03 TOP_LCD                \ 2- send DB5=DB4=1
18398     $CD 20_US                  \ 3- wait 4,1 ms
18399     $03 TOP_LCD                \ 4- send again DB5=DB4=1
18400     $5 20_US                   \ 5- wait 0,1 ms
18401     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
18402     $2 20_US                   \    wait 40 us = LCD cycle
18403     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
18404     $2 20_US                   \    wait 40 us = LCD cycle
18405     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
18406     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
18407     LCD_Clear                   \ 10- "LCD_Clear"
18408     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
18409     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
18410     LCD_Clear                   \ 10- "LCD_Clear"
18411     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
18412     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
18413     CR ." I love you"   
18414     ['] (CR) IS CR              \ ' (CR) is CR
18415     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
18416     CR
18417     ."    RC5toLCD is running. Type STOP to quit"
18418 \    NOECHO                      \ uncomment to run this app without terminal connexion
18419     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
18420     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
18421 ;
18422     \
18423
18424 : STOP                  \ stops multitasking, must to be used before downloading app
18425     ['] (WARM) IS WARM  \ remove START app from FORTH init process
18426     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
18427 ;
18428     \
18429
18430
18431 RST_STATE   ;
18432
18433
18434 CODE MAX    \    n1 n2 -- n3       signed maximum
18435             CMP     @PSP,TOS    \ n2-n1
18436             S<      ?GOTO FW1   \ n2<n1
18437 BW1         ADD     #2,PSP
18438             MOV     @IP+,PC
18439 ENDCODE
18440     \
18441
18442 CODE MIN    \    n1 n2 -- n3       signed minimum
18443             CMP     @PSP,TOS     \ n2-n1
18444             S<      ?GOTO BW1    \ n2<n1
18445 FW1         MOV     @PSP+,TOS
18446             MOV     @IP+,PC
18447 ENDCODE
18448     \
18449
18450 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
18451   >R  <# 0 # #S #>  
18452   R> OVER - 0 MAX SPACES TYPE
18453 ;
18454     \
18455
18456 CODE 20_US                      \ n --      n * 20 us
18457 BEGIN                           \ 3 cycles loop + 6~  
18458 \    MOV     #5,W                \ 3 MCLK = 1 MHz
18459 \    MOV     #23,W               \ 3 MCLK = 4 MHz
18460     MOV     #51,W               \ 3 MCLK = 8 MHz
18461 \    MOV     #104,W              \ 3 MCLK = 16 MHz
18462 \    MOV     #158,W              \ 3 MCLK = 24 MHz
18463     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
18464         SUB #1,W                \ 1
18465     0= UNTIL                    \ 2
18466     SUB     #1,TOS              \ 1
18467 0= UNTIL                        \ 2
18468     MOV     @PSP+,TOS           \ 2
18469     MOV     @IP+,PC             \ 4
18470 ENDCODE
18471     \
18472
18473 CODE TOP_LCD                    \ LCD Sample
18474 \                               \ if write : %xxxxWWWW --
18475 \                               \ if read  : -- %0000RRRR
18476     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
18477     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
18478 0= IF                           \ write LCD bits pattern
18479     AND.B #LCD_DB,TOS           \ 
18480     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
18481     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
18482     MOV @PSP+,TOS               \
18483     MOV @IP+,PC
18484 THEN                            \ read LCD bits pattern
18485     SUB #2,PSP
18486     MOV TOS,0(PSP)
18487     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
18488     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
18489     AND.B #LCD_DB,TOS           \
18490     MOV @IP+,PC
18491 ENDCODE
18492     \
18493
18494 CODE LCD_W                      \ byte --       write byte to LCD 
18495     SUB #2,PSP                  \
18496     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
18497     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
18498     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
18499     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
18500 COLON                           \ high level word starts here 
18501     TOP_LCD 2 20_US             \ write high nibble first
18502     TOP_LCD 2 20_US 
18503 ;
18504     \
18505
18506 CODE LCD_WrC                    \ char --         Write Char
18507     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
18508     JMP LCD_W 
18509 ENDCODE
18510     \
18511
18512 CODE LCD_WrF                    \ func --         Write Fonction
18513     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
18514     JMP LCD_W 
18515 ENDCODE
18516     \
18517
18518 : LCD_Clear 
18519     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
18520 ;
18521     \
18522
18523 : LCD_Home 
18524     $02 LCD_WrF 100 20_us 
18525 ;
18526     \
18527
18528 \ : LCD_Entry_set       $04 OR LCD_WrF ;
18529
18530 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
18531
18532 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
18533
18534 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
18535
18536 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
18537
18538 \ : LCD_Goto            $80 OR LCD_WrF ;
18539
18540 \ CODE LCD_R                      \ -- byte       read byte from LCD
18541 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
18542 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
18543 \ COLON                           \ starts a FORTH word
18544 \     TOP_LCD 2 20_us             \ -- %0000HHHH
18545 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
18546 \ HI2LO                           \ switch from FORTH to assembler
18547 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
18548 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
18549 \     MOV @RSP+,IP                \ restore IP saved by COLON
18550 \     MOV @IP+,PC                 \
18551 \ ENDCODE
18552 \     \
18553
18554 \ CODE LCD_RdS                    \ -- status       Read Status
18555 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
18556 \     JMP LCD_R
18557 \ ENDCODE
18558 \     \
18559
18560 \ CODE LCD_RdC                    \ -- char         Read Char
18561 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
18562 \     JMP LCD_R
18563 \ ENDCODE
18564 \     \
18565
18566 \ -------------+------+------+------+------++---+---+---+---+---------+
18567 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
18568 \ -------------+------+------+------+------++---+---+---+---+---------+
18569 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
18570 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
18571 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
18572 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
18573 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
18574 \ -------------+------+------+------+------++---+---+---+---+---------+
18575
18576
18577 \ ******************************\
18578 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
18579 \ ******************************\
18580 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
18581 \ ------------------------------\
18582 \ define LPM mode for ACCEPT    \
18583 \ ------------------------------\
18584 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
18585 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
18586 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
18587 BIT.B #SW2,&SW2_IN              \ test switch S2
18588 0= IF                           \ case of switch S2 pressed
18589     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
18590     U< IF
18591         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
18592     THEN
18593 ELSE
18594     BIT.B #SW1,&SW1_IN          \ test switch S1 input
18595     0= IF                       \ case of Switch S1 pressed
18596         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
18597         U>= IF                  \
18598             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
18599         THEN                    \
18600     THEN                        \
18601 THEN                            \
18602 RETI                            \ CPU is ON, GIE is OFF
18603 ENDASM                          \
18604     \
18605
18606
18607 \ ------------------------------\
18608 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
18609 \ ******************************\
18610 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
18611 \ ******************************\
18612 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
18613 \                               \       SMclock = 8|16|24 MHz
18614 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
18615 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
18616 \                               \       SR(9)=new Toggle bit memory (ADD on)
18617 \ ------------------------------\
18618 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
18619 \ ------------------------------\
18620 \ define LPM mode for ACCEPT    \
18621 \ ------------------------------\
18622 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
18623 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
18624 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
18625 \ ------------------------------\
18626 \ RC5_FirstStartBitHalfCycle:   \
18627 \ ------------------------------\
18628 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
18629 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
18630 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
18631 MOV     #1778,X                 \ RC5_Period in us
18632 MOV     #14,W                   \ count of loop
18633 BEGIN                           \
18634 \ ------------------------------\
18635 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
18636 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
18637     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
18638 \ RC5_Compute_3/4_Period:       \                   |
18639     RRUM    #1,X                \ X=1/2 cycle       |
18640     MOV     X,Y                 \ Y=1/2             ^
18641     RRUM    #1,Y                \ Y=1/4
18642     ADD     X,Y                 \ Y=3/4
18643 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
18644     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
18645     0= UNTIL                    \
18646 \ ------------------------------\
18647 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
18648 \ ------------------------------\
18649     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
18650     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
18651     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
18652     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
18653     SUB     #1,W                \ decrement count loop
18654 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
18655 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
18656 0<> WHILE                       \ ----> out of loop ----+
18657 \ RC5_compute_7/4_Time_out:     \                       |
18658     ADD     X,Y                 \                       |   out of bound = 7/4 period 
18659 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
18660     BEGIN                       \                       |
18661         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
18662         0>= IF                  \                       |   if cycle time out of bound
18663             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
18664             RETI                \                       |   then quit to do nothing
18665         THEN                    \                       |
18666 \ ------------------------------\                       |
18667         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
18668     0<> UNTIL                   \                   |   |
18669     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
18670 REPEAT                          \ ----> loop back --+   |
18671 \ ------------------------------\                       |
18672 \ RC5_SampleEndOf:              \ <---------------------+
18673 \ ------------------------------\
18674 BIC     #$30,&TA0CTL           \ stop timer_A0
18675 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
18676 \ ******************************\
18677 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
18678 \ ******************************\
18679 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
18680 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
18681 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
18682 BIT     #BIT13,X                \ X(13) = New_RC5_command
18683 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
18684 THEN                            \
18685 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
18686 \ ******************************\
18687 \ RC5_ComputeNewRC5word         \
18688 \ ******************************\
18689 SUB     #4,PSP                  \
18690 MOV     &BASE,2(PSP)            \ save variable BASE before use
18691 MOV     TOS,0(PSP)              \ save TOS before use
18692 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
18693 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
18694 \ ******************************\
18695 \ RC5_ComputeC6bit              \
18696 \ ******************************\
18697 BIT     #$4000,IP              \ test /C6 bit in IP
18698 0= IF   BIS #$40,TOS           \ set C6 bit in S
18699 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
18700 \ ******************************\
18701 \ RC5_CommandByteIsDone         \ RC5_code --
18702 \ ******************************\
18703
18704 \ ------------------------------\
18705 \ Display IR_RC5 code           \
18706 \ ------------------------------\
18707 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
18708 \ ------------------------------\
18709 LO2HI                           \ switch from assembler to FORTH
18710     ['] LCD_CLEAR IS CR         \ redirects CR
18711     ['] LCD_WrC  IS EMIT        \ redirects EMIT
18712     $10 BASE !                 \ change BASE to hexadecimal
18713     CR ." $" 2 U.R             \ print IR_RC5 code
18714     ['] (CR) IS CR              \ restore CR
18715     ['] (EMIT) IS EMIT          \ restore EMIT
18716 HI2LO                           \ switch from FORTH to assembler
18717 \ ------------------------------\
18718 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
18719 \ ------------------------------\
18720 MOV @PSP+,&BASE                 \ restore variable BASE
18721 RETI                            \ CPU is ON, GIE is OFF
18722 ENDASM                          \
18723     \ 
18724
18725 CODE START                      \
18726 \ ------------------------------\
18727 \ TB0CTL = %0000 0010 1001 0100\$3C0
18728 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
18729 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
18730 \                      --       \ID input divider \ 10 = /4
18731 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
18732 \                            -  \TBCLR TimerB Clear
18733 \                             - \TBIE
18734 \                              -\TBIFG
18735 \ --------------------------------\\
18736 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
18737 \              --                 \CM Capture Mode
18738 \                --               \CCIS
18739 \                   -             \SCS
18740 \                    --           \CLLD
18741 \                      -          \CAP
18742 \                        ---      \OUTMOD \ 011 = set/reset
18743 \                           -     \CCIE
18744 \                             -   \CCI
18745 \                              -  \OUT
18746 \                               - \COV
18747 \                                -\CCIFG
18748 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
18749 \ TB0EX0                          \$3E0 
18750 \ ------------------------------\
18751 \ set TimerB to make 50kHz PWM  \
18752 \ ------------------------------\
18753 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
18754 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
18755 \ ------------------------------\
18756 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
18757 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
18758 \ ------------------------------\
18759     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
18760     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
18761 \ ------------------------------\
18762 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
18763 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
18764 \ ------------------------------\
18765 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
18766 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
18767 \ ------------------------------\
18768     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
18769 \ ------------------------------\
18770 \ set TimerB to generate PWM for LCD_Vo
18771 \ ------------------------------\
18772     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
18773 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
18774     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
18775 \ ------------------------------\
18776     BIS.B #LCDVo,&LCDVo_DIR     \
18777     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
18778 \ ------------------------------\
18779     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
18780     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
18781 \ ------------------------------\
18782     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
18783     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
18784 \ ------------------------------\
18785 \ WDT interval init part        \
18786 \ ------------------------------\
18787     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
18788 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
18789 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
18790     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
18791 \ ------------------------------\
18792 \ init RC5_Int                  \
18793 \ ------------------------------\
18794     BIS.B #RC5,&IR_IE           \ enable RC5_Int
18795     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
18796 \ ------------------------------\
18797 \ init interrupt vectors
18798 \ ------------------------------\
18799     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
18800     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
18801 \ ------------------------------\
18802 \ define LPM mode for ACCEPT    \
18803 \ ------------------------------\
18804 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
18805 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
18806 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
18807
18808 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
18809
18810 \ ------------------------------\
18811 \ Init LCD 2x20                 \
18812 \ ------------------------------\
18813     $03E8 20_US                \ 1-  wait 20 ms
18814     $03 TOP_LCD                \ 2- send DB5=DB4=1
18815     $CD 20_US                  \ 3- wait 4,1 ms
18816     $03 TOP_LCD                \ 4- send again DB5=DB4=1
18817     $5 20_US                   \ 5- wait 0,1 ms
18818     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
18819     $2 20_US                   \    wait 40 us = LCD cycle
18820     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
18821     $2 20_US                   \    wait 40 us = LCD cycle
18822     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
18823     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
18824     LCD_Clear                   \ 10- "LCD_Clear"
18825     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
18826     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
18827     LCD_Clear                   \ 10- "LCD_Clear"
18828     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
18829     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
18830     CR ." I love you"   
18831     ['] (CR) IS CR              \ ' (CR) is CR
18832     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
18833     CR
18834     ."    RC5toLCD is running. Type STOP to quit"
18835 \    NOECHO                      \ uncomment to run this app without terminal connexion
18836     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
18837     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
18838 ;
18839     \
18840
18841 : STOP                  \ stops multitasking, must to be used before downloading app
18842     ['] (WARM) IS WARM  \ remove START app from FORTH init process
18843     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
18844 ;
18845     \
18846
18847
18848 RST_STATE   ;
18849
18850
18851 CODE MAX    \    n1 n2 -- n3       signed maximum
18852             CMP     @PSP,TOS    \ n2-n1
18853             S<      ?GOTO FW1   \ n2<n1
18854 BW1         ADD     #2,PSP
18855             MOV     @IP+,PC
18856 ENDCODE
18857     \
18858
18859 CODE MIN    \    n1 n2 -- n3       signed minimum
18860             CMP     @PSP,TOS     \ n2-n1
18861             S<      ?GOTO BW1    \ n2<n1
18862 FW1         MOV     @PSP+,TOS
18863             MOV     @IP+,PC
18864 ENDCODE
18865     \
18866
18867 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
18868   >R  <# 0 # #S #>  
18869   R> OVER - 0 MAX SPACES TYPE
18870 ;
18871     \
18872
18873 CODE 20_US                      \ n --      n * 20 us
18874 BEGIN                           \ 3 cycles loop + 6~  
18875 \    MOV     #5,W                \ 3 MCLK = 1 MHz
18876 \    MOV     #23,W               \ 3 MCLK = 4 MHz
18877     MOV     #51,W               \ 3 MCLK = 8 MHz
18878 \    MOV     #104,W              \ 3 MCLK = 16 MHz
18879 \    MOV     #158,W              \ 3 MCLK = 24 MHz
18880     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
18881         SUB #1,W                \ 1
18882     0= UNTIL                    \ 2
18883     SUB     #1,TOS              \ 1
18884 0= UNTIL                        \ 2
18885     MOV     @PSP+,TOS           \ 2
18886     MOV     @IP+,PC             \ 4
18887 ENDCODE
18888     \
18889
18890 CODE TOP_LCD                    \ LCD Sample
18891 \                               \ if write : %xxxxWWWW --
18892 \                               \ if read  : -- %0000RRRR
18893     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
18894     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
18895 0= IF                           \ write LCD bits pattern
18896     AND.B #LCD_DB,TOS           \ 
18897     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
18898     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
18899     MOV @PSP+,TOS               \
18900     MOV @IP+,PC
18901 THEN                            \ read LCD bits pattern
18902     SUB #2,PSP
18903     MOV TOS,0(PSP)
18904     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
18905     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
18906     AND.B #LCD_DB,TOS           \
18907     MOV @IP+,PC
18908 ENDCODE
18909     \
18910
18911 CODE LCD_W                      \ byte --       write byte to LCD 
18912     SUB #2,PSP                  \
18913     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
18914     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
18915     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
18916     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
18917 COLON                           \ high level word starts here 
18918     TOP_LCD 2 20_US             \ write high nibble first
18919     TOP_LCD 2 20_US 
18920 ;
18921     \
18922
18923 CODE LCD_WrC                    \ char --         Write Char
18924     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
18925     JMP LCD_W 
18926 ENDCODE
18927     \
18928
18929 CODE LCD_WrF                    \ func --         Write Fonction
18930     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
18931     JMP LCD_W 
18932 ENDCODE
18933     \
18934
18935 : LCD_Clear 
18936     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
18937 ;
18938     \
18939
18940 : LCD_Home 
18941     $02 LCD_WrF 100 20_us 
18942 ;
18943     \
18944
18945 \ : LCD_Entry_set       $04 OR LCD_WrF ;
18946
18947 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
18948
18949 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
18950
18951 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
18952
18953 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
18954
18955 \ : LCD_Goto            $80 OR LCD_WrF ;
18956
18957 \ CODE LCD_R                      \ -- byte       read byte from LCD
18958 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
18959 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
18960 \ COLON                           \ starts a FORTH word
18961 \     TOP_LCD 2 20_us             \ -- %0000HHHH
18962 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
18963 \ HI2LO                           \ switch from FORTH to assembler
18964 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
18965 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
18966 \     MOV @RSP+,IP                \ restore IP saved by COLON
18967 \     MOV @IP+,PC                 \
18968 \ ENDCODE
18969 \     \
18970
18971 \ CODE LCD_RdS                    \ -- status       Read Status
18972 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
18973 \     JMP LCD_R
18974 \ ENDCODE
18975 \     \
18976
18977 \ CODE LCD_RdC                    \ -- char         Read Char
18978 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
18979 \     JMP LCD_R
18980 \ ENDCODE
18981 \     \
18982
18983 \ -------------+------+------+------+------++---+---+---+---+---------+
18984 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
18985 \ -------------+------+------+------+------++---+---+---+---+---------+
18986 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
18987 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
18988 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
18989 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
18990 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
18991 \ -------------+------+------+------+------++---+---+---+---+---------+
18992
18993
18994 \ ******************************\
18995 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
18996 \ ******************************\
18997 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
18998 \ ------------------------------\
18999 \ define LPM mode for ACCEPT    \
19000 \ ------------------------------\
19001 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
19002 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
19003 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
19004 BIT.B #SW2,&SW2_IN              \ test switch S2
19005 0= IF                           \ case of switch S2 pressed
19006     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
19007     U< IF
19008         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
19009     THEN
19010 ELSE
19011     BIT.B #SW1,&SW1_IN          \ test switch S1 input
19012     0= IF                       \ case of Switch S1 pressed
19013         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
19014         U>= IF                  \
19015             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
19016         THEN                    \
19017     THEN                        \
19018 THEN                            \
19019 RETI                            \ CPU is ON, GIE is OFF
19020 ENDASM                          \
19021     \
19022
19023
19024 \ ------------------------------\
19025 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
19026 \ ******************************\
19027 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
19028 \ ******************************\
19029 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
19030 \                               \       SMclock = 8|16|24 MHz
19031 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
19032 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
19033 \                               \       SR(9)=new Toggle bit memory (ADD on)
19034 \ ------------------------------\
19035 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
19036 \ ------------------------------\
19037 \ define LPM mode for ACCEPT    \
19038 \ ------------------------------\
19039 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
19040 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
19041 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
19042 \ ------------------------------\
19043 \ RC5_FirstStartBitHalfCycle:   \
19044 \ ------------------------------\
19045 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
19046 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
19047 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
19048 MOV     #1778,X                 \ RC5_Period in us
19049 MOV     #14,W                   \ count of loop
19050 BEGIN                           \
19051 \ ------------------------------\
19052 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
19053 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
19054     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
19055 \ RC5_Compute_3/4_Period:       \                   |
19056     RRUM    #1,X                \ X=1/2 cycle       |
19057     MOV     X,Y                 \ Y=1/2             ^
19058     RRUM    #1,Y                \ Y=1/4
19059     ADD     X,Y                 \ Y=3/4
19060 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
19061     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
19062     0= UNTIL                    \
19063 \ ------------------------------\
19064 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
19065 \ ------------------------------\
19066     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
19067     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
19068     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
19069     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
19070     SUB     #1,W                \ decrement count loop
19071 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
19072 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
19073 0<> WHILE                       \ ----> out of loop ----+
19074 \ RC5_compute_7/4_Time_out:     \                       |
19075     ADD     X,Y                 \                       |   out of bound = 7/4 period 
19076 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
19077     BEGIN                       \                       |
19078         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
19079         0>= IF                  \                       |   if cycle time out of bound
19080             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
19081             RETI                \                       |   then quit to do nothing
19082         THEN                    \                       |
19083 \ ------------------------------\                       |
19084         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
19085     0<> UNTIL                   \                   |   |
19086     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
19087 REPEAT                          \ ----> loop back --+   |
19088 \ ------------------------------\                       |
19089 \ RC5_SampleEndOf:              \ <---------------------+
19090 \ ------------------------------\
19091 BIC     #$30,&TA0CTL           \ stop timer_A0
19092 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
19093 \ ******************************\
19094 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
19095 \ ******************************\
19096 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
19097 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
19098 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
19099 BIT     #BIT13,X                \ X(13) = New_RC5_command
19100 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
19101 THEN                            \
19102 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
19103 \ ******************************\
19104 \ RC5_ComputeNewRC5word         \
19105 \ ******************************\
19106 SUB     #4,PSP                  \
19107 MOV     &BASE,2(PSP)            \ save variable BASE before use
19108 MOV     TOS,0(PSP)              \ save TOS before use
19109 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
19110 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
19111 \ ******************************\
19112 \ RC5_ComputeC6bit              \
19113 \ ******************************\
19114 BIT     #$4000,IP              \ test /C6 bit in IP
19115 0= IF   BIS #$40,TOS           \ set C6 bit in S
19116 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
19117 \ ******************************\
19118 \ RC5_CommandByteIsDone         \ RC5_code --
19119 \ ******************************\
19120
19121 \ ------------------------------\
19122 \ Display IR_RC5 code           \
19123 \ ------------------------------\
19124 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
19125 \ ------------------------------\
19126 LO2HI                           \ switch from assembler to FORTH
19127     ['] LCD_CLEAR IS CR         \ redirects CR
19128     ['] LCD_WrC  IS EMIT        \ redirects EMIT
19129     $10 BASE !                 \ change BASE to hexadecimal
19130     CR ." $" 2 U.R             \ print IR_RC5 code
19131     ['] (CR) IS CR              \ restore CR
19132     ['] (EMIT) IS EMIT          \ restore EMIT
19133 HI2LO                           \ switch from FORTH to assembler
19134 \ ------------------------------\
19135 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
19136 \ ------------------------------\
19137 MOV @PSP+,&BASE                 \ restore variable BASE
19138 RETI                            \ CPU is ON, GIE is OFF
19139 ENDASM                          \
19140     \ 
19141
19142 CODE START                      \
19143 \ ------------------------------\
19144 \ TB0CTL = %0000 0010 1001 0100\$3C0
19145 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
19146 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
19147 \                      --       \ID input divider \ 10 = /4
19148 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
19149 \                            -  \TBCLR TimerB Clear
19150 \                             - \TBIE
19151 \                              -\TBIFG
19152 \ --------------------------------\\
19153 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
19154 \              --                 \CM Capture Mode
19155 \                --               \CCIS
19156 \                   -             \SCS
19157 \                    --           \CLLD
19158 \                      -          \CAP
19159 \                        ---      \OUTMOD \ 011 = set/reset
19160 \                           -     \CCIE
19161 \                             -   \CCI
19162 \                              -  \OUT
19163 \                               - \COV
19164 \                                -\CCIFG
19165 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
19166 \ TB0EX0                          \$3E0 
19167 \ ------------------------------\
19168 \ set TimerB to make 50kHz PWM  \
19169 \ ------------------------------\
19170 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
19171 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
19172 \ ------------------------------\
19173 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
19174 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
19175 \ ------------------------------\
19176     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
19177     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
19178 \ ------------------------------\
19179 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
19180 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
19181 \ ------------------------------\
19182 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
19183 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
19184 \ ------------------------------\
19185     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
19186 \ ------------------------------\
19187 \ set TimerB to generate PWM for LCD_Vo
19188 \ ------------------------------\
19189     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
19190 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
19191     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
19192 \ ------------------------------\
19193     BIS.B #LCDVo,&LCDVo_DIR     \
19194     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
19195 \ ------------------------------\
19196     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
19197     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
19198 \ ------------------------------\
19199     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
19200     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
19201 \ ------------------------------\
19202 \ WDT interval init part        \
19203 \ ------------------------------\
19204     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
19205 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
19206 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
19207     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
19208 \ ------------------------------\
19209 \ init RC5_Int                  \
19210 \ ------------------------------\
19211     BIS.B #RC5,&IR_IE           \ enable RC5_Int
19212     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
19213 \ ------------------------------\
19214 \ init interrupt vectors
19215 \ ------------------------------\
19216     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
19217     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
19218 \ ------------------------------\
19219 \ define LPM mode for ACCEPT    \
19220 \ ------------------------------\
19221 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
19222 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
19223 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
19224
19225 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
19226
19227 \ ------------------------------\
19228 \ Init LCD 2x20                 \
19229 \ ------------------------------\
19230     $03E8 20_US                \ 1-  wait 20 ms
19231     $03 TOP_LCD                \ 2- send DB5=DB4=1
19232     $CD 20_US                  \ 3- wait 4,1 ms
19233     $03 TOP_LCD                \ 4- send again DB5=DB4=1
19234     $5 20_US                   \ 5- wait 0,1 ms
19235     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
19236     $2 20_US                   \    wait 40 us = LCD cycle
19237     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
19238     $2 20_US                   \    wait 40 us = LCD cycle
19239     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
19240     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
19241     LCD_Clear                   \ 10- "LCD_Clear"
19242     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
19243     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
19244     LCD_Clear                   \ 10- "LCD_Clear"
19245     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
19246     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
19247     CR ." I love you"   
19248     ['] (CR) IS CR              \ ' (CR) is CR
19249     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
19250     CR
19251     ."    RC5toLCD is running. Type STOP to quit"
19252 \    NOECHO                      \ uncomment to run this app without terminal connexion
19253     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
19254     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
19255 ;
19256     \
19257
19258 : STOP                  \ stops multitasking, must to be used before downloading app
19259     ['] (WARM) IS WARM  \ remove START app from FORTH init process
19260     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
19261 ;
19262     \
19263
19264
19265 RST_STATE   ;
19266
19267
19268 CODE MAX    \    n1 n2 -- n3       signed maximum
19269             CMP     @PSP,TOS    \ n2-n1
19270             S<      ?GOTO FW1   \ n2<n1
19271 BW1         ADD     #2,PSP
19272             MOV     @IP+,PC
19273 ENDCODE
19274     \
19275
19276 CODE MIN    \    n1 n2 -- n3       signed minimum
19277             CMP     @PSP,TOS     \ n2-n1
19278             S<      ?GOTO BW1    \ n2<n1
19279 FW1         MOV     @PSP+,TOS
19280             MOV     @IP+,PC
19281 ENDCODE
19282     \
19283
19284 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
19285   >R  <# 0 # #S #>  
19286   R> OVER - 0 MAX SPACES TYPE
19287 ;
19288     \
19289
19290 CODE 20_US                      \ n --      n * 20 us
19291 BEGIN                           \ 3 cycles loop + 6~  
19292 \    MOV     #5,W                \ 3 MCLK = 1 MHz
19293 \    MOV     #23,W               \ 3 MCLK = 4 MHz
19294     MOV     #51,W               \ 3 MCLK = 8 MHz
19295 \    MOV     #104,W              \ 3 MCLK = 16 MHz
19296 \    MOV     #158,W              \ 3 MCLK = 24 MHz
19297     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
19298         SUB #1,W                \ 1
19299     0= UNTIL                    \ 2
19300     SUB     #1,TOS              \ 1
19301 0= UNTIL                        \ 2
19302     MOV     @PSP+,TOS           \ 2
19303     MOV     @IP+,PC             \ 4
19304 ENDCODE
19305     \
19306
19307 CODE TOP_LCD                    \ LCD Sample
19308 \                               \ if write : %xxxxWWWW --
19309 \                               \ if read  : -- %0000RRRR
19310     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
19311     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
19312 0= IF                           \ write LCD bits pattern
19313     AND.B #LCD_DB,TOS           \ 
19314     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
19315     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
19316     MOV @PSP+,TOS               \
19317     MOV @IP+,PC
19318 THEN                            \ read LCD bits pattern
19319     SUB #2,PSP
19320     MOV TOS,0(PSP)
19321     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
19322     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
19323     AND.B #LCD_DB,TOS           \
19324     MOV @IP+,PC
19325 ENDCODE
19326     \
19327
19328 CODE LCD_W                      \ byte --       write byte to LCD 
19329     SUB #2,PSP                  \
19330     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
19331     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
19332     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
19333     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
19334 COLON                           \ high level word starts here 
19335     TOP_LCD 2 20_US             \ write high nibble first
19336     TOP_LCD 2 20_US 
19337 ;
19338     \
19339
19340 CODE LCD_WrC                    \ char --         Write Char
19341     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
19342     JMP LCD_W 
19343 ENDCODE
19344     \
19345
19346 CODE LCD_WrF                    \ func --         Write Fonction
19347     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
19348     JMP LCD_W 
19349 ENDCODE
19350     \
19351
19352 : LCD_Clear 
19353     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
19354 ;
19355     \
19356
19357 : LCD_Home 
19358     $02 LCD_WrF 100 20_us 
19359 ;
19360     \
19361
19362 \ : LCD_Entry_set       $04 OR LCD_WrF ;
19363
19364 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
19365
19366 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
19367
19368 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
19369
19370 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
19371
19372 \ : LCD_Goto            $80 OR LCD_WrF ;
19373
19374 \ CODE LCD_R                      \ -- byte       read byte from LCD
19375 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
19376 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
19377 \ COLON                           \ starts a FORTH word
19378 \     TOP_LCD 2 20_us             \ -- %0000HHHH
19379 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
19380 \ HI2LO                           \ switch from FORTH to assembler
19381 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
19382 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
19383 \     MOV @RSP+,IP                \ restore IP saved by COLON
19384 \     MOV @IP+,PC                 \
19385 \ ENDCODE
19386 \     \
19387
19388 \ CODE LCD_RdS                    \ -- status       Read Status
19389 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
19390 \     JMP LCD_R
19391 \ ENDCODE
19392 \     \
19393
19394 \ CODE LCD_RdC                    \ -- char         Read Char
19395 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
19396 \     JMP LCD_R
19397 \ ENDCODE
19398 \     \
19399
19400 \ -------------+------+------+------+------++---+---+---+---+---------+
19401 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
19402 \ -------------+------+------+------+------++---+---+---+---+---------+
19403 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
19404 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
19405 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
19406 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
19407 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
19408 \ -------------+------+------+------+------++---+---+---+---+---------+
19409
19410
19411 \ ******************************\
19412 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
19413 \ ******************************\
19414 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
19415 \ ------------------------------\
19416 \ define LPM mode for ACCEPT    \
19417 \ ------------------------------\
19418 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
19419 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
19420 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
19421 BIT.B #SW2,&SW2_IN              \ test switch S2
19422 0= IF                           \ case of switch S2 pressed
19423     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
19424     U< IF
19425         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
19426     THEN
19427 ELSE
19428     BIT.B #SW1,&SW1_IN          \ test switch S1 input
19429     0= IF                       \ case of Switch S1 pressed
19430         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
19431         U>= IF                  \
19432             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
19433         THEN                    \
19434     THEN                        \
19435 THEN                            \
19436 RETI                            \ CPU is ON, GIE is OFF
19437 ENDASM                          \
19438     \
19439
19440
19441 \ ------------------------------\
19442 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
19443 \ ******************************\
19444 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
19445 \ ******************************\
19446 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
19447 \                               \       SMclock = 8|16|24 MHz
19448 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
19449 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
19450 \                               \       SR(9)=new Toggle bit memory (ADD on)
19451 \ ------------------------------\
19452 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
19453 \ ------------------------------\
19454 \ define LPM mode for ACCEPT    \
19455 \ ------------------------------\
19456 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
19457 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
19458 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
19459 \ ------------------------------\
19460 \ RC5_FirstStartBitHalfCycle:   \
19461 \ ------------------------------\
19462 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
19463 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
19464 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
19465 MOV     #1778,X                 \ RC5_Period in us
19466 MOV     #14,W                   \ count of loop
19467 BEGIN                           \
19468 \ ------------------------------\
19469 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
19470 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
19471     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
19472 \ RC5_Compute_3/4_Period:       \                   |
19473     RRUM    #1,X                \ X=1/2 cycle       |
19474     MOV     X,Y                 \ Y=1/2             ^
19475     RRUM    #1,Y                \ Y=1/4
19476     ADD     X,Y                 \ Y=3/4
19477 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
19478     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
19479     0= UNTIL                    \
19480 \ ------------------------------\
19481 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
19482 \ ------------------------------\
19483     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
19484     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
19485     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
19486     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
19487     SUB     #1,W                \ decrement count loop
19488 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
19489 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
19490 0<> WHILE                       \ ----> out of loop ----+
19491 \ RC5_compute_7/4_Time_out:     \                       |
19492     ADD     X,Y                 \                       |   out of bound = 7/4 period 
19493 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
19494     BEGIN                       \                       |
19495         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
19496         0>= IF                  \                       |   if cycle time out of bound
19497             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
19498             RETI                \                       |   then quit to do nothing
19499         THEN                    \                       |
19500 \ ------------------------------\                       |
19501         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
19502     0<> UNTIL                   \                   |   |
19503     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
19504 REPEAT                          \ ----> loop back --+   |
19505 \ ------------------------------\                       |
19506 \ RC5_SampleEndOf:              \ <---------------------+
19507 \ ------------------------------\
19508 BIC     #$30,&TA0CTL           \ stop timer_A0
19509 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
19510 \ ******************************\
19511 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
19512 \ ******************************\
19513 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
19514 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
19515 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
19516 BIT     #BIT13,X                \ X(13) = New_RC5_command
19517 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
19518 THEN                            \
19519 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
19520 \ ******************************\
19521 \ RC5_ComputeNewRC5word         \
19522 \ ******************************\
19523 SUB     #4,PSP                  \
19524 MOV     &BASE,2(PSP)            \ save variable BASE before use
19525 MOV     TOS,0(PSP)              \ save TOS before use
19526 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
19527 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
19528 \ ******************************\
19529 \ RC5_ComputeC6bit              \
19530 \ ******************************\
19531 BIT     #$4000,IP              \ test /C6 bit in IP
19532 0= IF   BIS #$40,TOS           \ set C6 bit in S
19533 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
19534 \ ******************************\
19535 \ RC5_CommandByteIsDone         \ RC5_code --
19536 \ ******************************\
19537
19538 \ ------------------------------\
19539 \ Display IR_RC5 code           \
19540 \ ------------------------------\
19541 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
19542 \ ------------------------------\
19543 LO2HI                           \ switch from assembler to FORTH
19544     ['] LCD_CLEAR IS CR         \ redirects CR
19545     ['] LCD_WrC  IS EMIT        \ redirects EMIT
19546     $10 BASE !                 \ change BASE to hexadecimal
19547     CR ." $" 2 U.R             \ print IR_RC5 code
19548     ['] (CR) IS CR              \ restore CR
19549     ['] (EMIT) IS EMIT          \ restore EMIT
19550 HI2LO                           \ switch from FORTH to assembler
19551 \ ------------------------------\
19552 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
19553 \ ------------------------------\
19554 MOV @PSP+,&BASE                 \ restore variable BASE
19555 RETI                            \ CPU is ON, GIE is OFF
19556 ENDASM                          \
19557     \ 
19558
19559 CODE START                      \
19560 \ ------------------------------\
19561 \ TB0CTL = %0000 0010 1001 0100\$3C0
19562 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
19563 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
19564 \                      --       \ID input divider \ 10 = /4
19565 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
19566 \                            -  \TBCLR TimerB Clear
19567 \                             - \TBIE
19568 \                              -\TBIFG
19569 \ --------------------------------\\
19570 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
19571 \              --                 \CM Capture Mode
19572 \                --               \CCIS
19573 \                   -             \SCS
19574 \                    --           \CLLD
19575 \                      -          \CAP
19576 \                        ---      \OUTMOD \ 011 = set/reset
19577 \                           -     \CCIE
19578 \                             -   \CCI
19579 \                              -  \OUT
19580 \                               - \COV
19581 \                                -\CCIFG
19582 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
19583 \ TB0EX0                          \$3E0 
19584 \ ------------------------------\
19585 \ set TimerB to make 50kHz PWM  \
19586 \ ------------------------------\
19587 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
19588 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
19589 \ ------------------------------\
19590 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
19591 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
19592 \ ------------------------------\
19593     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
19594     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
19595 \ ------------------------------\
19596 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
19597 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
19598 \ ------------------------------\
19599 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
19600 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
19601 \ ------------------------------\
19602     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
19603 \ ------------------------------\
19604 \ set TimerB to generate PWM for LCD_Vo
19605 \ ------------------------------\
19606     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
19607 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
19608     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
19609 \ ------------------------------\
19610     BIS.B #LCDVo,&LCDVo_DIR     \
19611     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
19612 \ ------------------------------\
19613     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
19614     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
19615 \ ------------------------------\
19616     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
19617     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
19618 \ ------------------------------\
19619 \ WDT interval init part        \
19620 \ ------------------------------\
19621     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
19622 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
19623 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
19624     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
19625 \ ------------------------------\
19626 \ init RC5_Int                  \
19627 \ ------------------------------\
19628     BIS.B #RC5,&IR_IE           \ enable RC5_Int
19629     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
19630 \ ------------------------------\
19631 \ init interrupt vectors
19632 \ ------------------------------\
19633     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
19634     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
19635 \ ------------------------------\
19636 \ define LPM mode for ACCEPT    \
19637 \ ------------------------------\
19638 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
19639 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
19640 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
19641
19642 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
19643
19644 \ ------------------------------\
19645 \ Init LCD 2x20                 \
19646 \ ------------------------------\
19647     $03E8 20_US                \ 1-  wait 20 ms
19648     $03 TOP_LCD                \ 2- send DB5=DB4=1
19649     $CD 20_US                  \ 3- wait 4,1 ms
19650     $03 TOP_LCD                \ 4- send again DB5=DB4=1
19651     $5 20_US                   \ 5- wait 0,1 ms
19652     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
19653     $2 20_US                   \    wait 40 us = LCD cycle
19654     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
19655     $2 20_US                   \    wait 40 us = LCD cycle
19656     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
19657     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
19658     LCD_Clear                   \ 10- "LCD_Clear"
19659     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
19660     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
19661     LCD_Clear                   \ 10- "LCD_Clear"
19662     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
19663     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
19664     CR ." I love you"   
19665     ['] (CR) IS CR              \ ' (CR) is CR
19666     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
19667     CR
19668     ."    RC5toLCD is running. Type STOP to quit"
19669 \    NOECHO                      \ uncomment to run this app without terminal connexion
19670     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
19671     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
19672 ;
19673     \
19674
19675 : STOP                  \ stops multitasking, must to be used before downloading app
19676     ['] (WARM) IS WARM  \ remove START app from FORTH init process
19677     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
19678 ;
19679     \
19680
19681
19682 RST_STATE   ;
19683
19684
19685 CODE MAX    \    n1 n2 -- n3       signed maximum
19686             CMP     @PSP,TOS    \ n2-n1
19687             S<      ?GOTO FW1   \ n2<n1
19688 BW1         ADD     #2,PSP
19689             MOV     @IP+,PC
19690 ENDCODE
19691     \
19692
19693 CODE MIN    \    n1 n2 -- n3       signed minimum
19694             CMP     @PSP,TOS     \ n2-n1
19695             S<      ?GOTO BW1    \ n2<n1
19696 FW1         MOV     @PSP+,TOS
19697             MOV     @IP+,PC
19698 ENDCODE
19699     \
19700
19701 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
19702   >R  <# 0 # #S #>  
19703   R> OVER - 0 MAX SPACES TYPE
19704 ;
19705     \
19706
19707 CODE 20_US                      \ n --      n * 20 us
19708 BEGIN                           \ 3 cycles loop + 6~  
19709 \    MOV     #5,W                \ 3 MCLK = 1 MHz
19710 \    MOV     #23,W               \ 3 MCLK = 4 MHz
19711     MOV     #51,W               \ 3 MCLK = 8 MHz
19712 \    MOV     #104,W              \ 3 MCLK = 16 MHz
19713 \    MOV     #158,W              \ 3 MCLK = 24 MHz
19714     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
19715         SUB #1,W                \ 1
19716     0= UNTIL                    \ 2
19717     SUB     #1,TOS              \ 1
19718 0= UNTIL                        \ 2
19719     MOV     @PSP+,TOS           \ 2
19720     MOV     @IP+,PC             \ 4
19721 ENDCODE
19722     \
19723
19724 CODE TOP_LCD                    \ LCD Sample
19725 \                               \ if write : %xxxxWWWW --
19726 \                               \ if read  : -- %0000RRRR
19727     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
19728     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
19729 0= IF                           \ write LCD bits pattern
19730     AND.B #LCD_DB,TOS           \ 
19731     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
19732     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
19733     MOV @PSP+,TOS               \
19734     MOV @IP+,PC
19735 THEN                            \ read LCD bits pattern
19736     SUB #2,PSP
19737     MOV TOS,0(PSP)
19738     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
19739     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
19740     AND.B #LCD_DB,TOS           \
19741     MOV @IP+,PC
19742 ENDCODE
19743     \
19744
19745 CODE LCD_W                      \ byte --       write byte to LCD 
19746     SUB #2,PSP                  \
19747     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
19748     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
19749     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
19750     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
19751 COLON                           \ high level word starts here 
19752     TOP_LCD 2 20_US             \ write high nibble first
19753     TOP_LCD 2 20_US 
19754 ;
19755     \
19756
19757 CODE LCD_WrC                    \ char --         Write Char
19758     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
19759     JMP LCD_W 
19760 ENDCODE
19761     \
19762
19763 CODE LCD_WrF                    \ func --         Write Fonction
19764     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
19765     JMP LCD_W 
19766 ENDCODE
19767     \
19768
19769 : LCD_Clear 
19770     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
19771 ;
19772     \
19773
19774 : LCD_Home 
19775     $02 LCD_WrF 100 20_us 
19776 ;
19777     \
19778
19779 \ : LCD_Entry_set       $04 OR LCD_WrF ;
19780
19781 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
19782
19783 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
19784
19785 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
19786
19787 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
19788
19789 \ : LCD_Goto            $80 OR LCD_WrF ;
19790
19791 \ CODE LCD_R                      \ -- byte       read byte from LCD
19792 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
19793 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
19794 \ COLON                           \ starts a FORTH word
19795 \     TOP_LCD 2 20_us             \ -- %0000HHHH
19796 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
19797 \ HI2LO                           \ switch from FORTH to assembler
19798 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
19799 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
19800 \     MOV @RSP+,IP                \ restore IP saved by COLON
19801 \     MOV @IP+,PC                 \
19802 \ ENDCODE
19803 \     \
19804
19805 \ CODE LCD_RdS                    \ -- status       Read Status
19806 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
19807 \     JMP LCD_R
19808 \ ENDCODE
19809 \     \
19810
19811 \ CODE LCD_RdC                    \ -- char         Read Char
19812 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
19813 \     JMP LCD_R
19814 \ ENDCODE
19815 \     \
19816
19817 \ -------------+------+------+------+------++---+---+---+---+---------+
19818 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
19819 \ -------------+------+------+------+------++---+---+---+---+---------+
19820 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
19821 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
19822 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
19823 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
19824 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
19825 \ -------------+------+------+------+------++---+---+---+---+---------+
19826
19827
19828 \ ******************************\
19829 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
19830 \ ******************************\
19831 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
19832 \ ------------------------------\
19833 \ define LPM mode for ACCEPT    \
19834 \ ------------------------------\
19835 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
19836 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
19837 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
19838 BIT.B #SW2,&SW2_IN              \ test switch S2
19839 0= IF                           \ case of switch S2 pressed
19840     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
19841     U< IF
19842         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
19843     THEN
19844 ELSE
19845     BIT.B #SW1,&SW1_IN          \ test switch S1 input
19846     0= IF                       \ case of Switch S1 pressed
19847         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
19848         U>= IF                  \
19849             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
19850         THEN                    \
19851     THEN                        \
19852 THEN                            \
19853 RETI                            \ CPU is ON, GIE is OFF
19854 ENDASM                          \
19855     \
19856
19857
19858 \ ------------------------------\
19859 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
19860 \ ******************************\
19861 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
19862 \ ******************************\
19863 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
19864 \                               \       SMclock = 8|16|24 MHz
19865 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
19866 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
19867 \                               \       SR(9)=new Toggle bit memory (ADD on)
19868 \ ------------------------------\
19869 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
19870 \ ------------------------------\
19871 \ define LPM mode for ACCEPT    \
19872 \ ------------------------------\
19873 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
19874 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
19875 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
19876 \ ------------------------------\
19877 \ RC5_FirstStartBitHalfCycle:   \
19878 \ ------------------------------\
19879 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
19880 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
19881 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
19882 MOV     #1778,X                 \ RC5_Period in us
19883 MOV     #14,W                   \ count of loop
19884 BEGIN                           \
19885 \ ------------------------------\
19886 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
19887 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
19888     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
19889 \ RC5_Compute_3/4_Period:       \                   |
19890     RRUM    #1,X                \ X=1/2 cycle       |
19891     MOV     X,Y                 \ Y=1/2             ^
19892     RRUM    #1,Y                \ Y=1/4
19893     ADD     X,Y                 \ Y=3/4
19894 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
19895     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
19896     0= UNTIL                    \
19897 \ ------------------------------\
19898 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
19899 \ ------------------------------\
19900     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
19901     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
19902     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
19903     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
19904     SUB     #1,W                \ decrement count loop
19905 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
19906 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
19907 0<> WHILE                       \ ----> out of loop ----+
19908 \ RC5_compute_7/4_Time_out:     \                       |
19909     ADD     X,Y                 \                       |   out of bound = 7/4 period 
19910 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
19911     BEGIN                       \                       |
19912         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
19913         0>= IF                  \                       |   if cycle time out of bound
19914             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
19915             RETI                \                       |   then quit to do nothing
19916         THEN                    \                       |
19917 \ ------------------------------\                       |
19918         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
19919     0<> UNTIL                   \                   |   |
19920     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
19921 REPEAT                          \ ----> loop back --+   |
19922 \ ------------------------------\                       |
19923 \ RC5_SampleEndOf:              \ <---------------------+
19924 \ ------------------------------\
19925 BIC     #$30,&TA0CTL           \ stop timer_A0
19926 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
19927 \ ******************************\
19928 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
19929 \ ******************************\
19930 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
19931 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
19932 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
19933 BIT     #BIT13,X                \ X(13) = New_RC5_command
19934 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
19935 THEN                            \
19936 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
19937 \ ******************************\
19938 \ RC5_ComputeNewRC5word         \
19939 \ ******************************\
19940 SUB     #4,PSP                  \
19941 MOV     &BASE,2(PSP)            \ save variable BASE before use
19942 MOV     TOS,0(PSP)              \ save TOS before use
19943 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
19944 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
19945 \ ******************************\
19946 \ RC5_ComputeC6bit              \
19947 \ ******************************\
19948 BIT     #$4000,IP              \ test /C6 bit in IP
19949 0= IF   BIS #$40,TOS           \ set C6 bit in S
19950 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
19951 \ ******************************\
19952 \ RC5_CommandByteIsDone         \ RC5_code --
19953 \ ******************************\
19954
19955 \ ------------------------------\
19956 \ Display IR_RC5 code           \
19957 \ ------------------------------\
19958 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
19959 \ ------------------------------\
19960 LO2HI                           \ switch from assembler to FORTH
19961     ['] LCD_CLEAR IS CR         \ redirects CR
19962     ['] LCD_WrC  IS EMIT        \ redirects EMIT
19963     $10 BASE !                 \ change BASE to hexadecimal
19964     CR ." $" 2 U.R             \ print IR_RC5 code
19965     ['] (CR) IS CR              \ restore CR
19966     ['] (EMIT) IS EMIT          \ restore EMIT
19967 HI2LO                           \ switch from FORTH to assembler
19968 \ ------------------------------\
19969 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
19970 \ ------------------------------\
19971 MOV @PSP+,&BASE                 \ restore variable BASE
19972 RETI                            \ CPU is ON, GIE is OFF
19973 ENDASM                          \
19974     \ 
19975
19976 CODE START                      \
19977 \ ------------------------------\
19978 \ TB0CTL = %0000 0010 1001 0100\$3C0
19979 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
19980 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
19981 \                      --       \ID input divider \ 10 = /4
19982 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
19983 \                            -  \TBCLR TimerB Clear
19984 \                             - \TBIE
19985 \                              -\TBIFG
19986 \ --------------------------------\\
19987 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
19988 \              --                 \CM Capture Mode
19989 \                --               \CCIS
19990 \                   -             \SCS
19991 \                    --           \CLLD
19992 \                      -          \CAP
19993 \                        ---      \OUTMOD \ 011 = set/reset
19994 \                           -     \CCIE
19995 \                             -   \CCI
19996 \                              -  \OUT
19997 \                               - \COV
19998 \                                -\CCIFG
19999 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
20000 \ TB0EX0                          \$3E0 
20001 \ ------------------------------\
20002 \ set TimerB to make 50kHz PWM  \
20003 \ ------------------------------\
20004 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
20005 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
20006 \ ------------------------------\
20007 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
20008 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
20009 \ ------------------------------\
20010     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
20011     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
20012 \ ------------------------------\
20013 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
20014 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
20015 \ ------------------------------\
20016 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
20017 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
20018 \ ------------------------------\
20019     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
20020 \ ------------------------------\
20021 \ set TimerB to generate PWM for LCD_Vo
20022 \ ------------------------------\
20023     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
20024 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
20025     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
20026 \ ------------------------------\
20027     BIS.B #LCDVo,&LCDVo_DIR     \
20028     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
20029 \ ------------------------------\
20030     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
20031     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
20032 \ ------------------------------\
20033     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
20034     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
20035 \ ------------------------------\
20036 \ WDT interval init part        \
20037 \ ------------------------------\
20038     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
20039 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
20040 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
20041     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
20042 \ ------------------------------\
20043 \ init RC5_Int                  \
20044 \ ------------------------------\
20045     BIS.B #RC5,&IR_IE           \ enable RC5_Int
20046     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
20047 \ ------------------------------\
20048 \ init interrupt vectors
20049 \ ------------------------------\
20050     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
20051     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
20052 \ ------------------------------\
20053 \ define LPM mode for ACCEPT    \
20054 \ ------------------------------\
20055 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
20056 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
20057 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
20058
20059 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
20060
20061 \ ------------------------------\
20062 \ Init LCD 2x20                 \
20063 \ ------------------------------\
20064     $03E8 20_US                \ 1-  wait 20 ms
20065     $03 TOP_LCD                \ 2- send DB5=DB4=1
20066     $CD 20_US                  \ 3- wait 4,1 ms
20067     $03 TOP_LCD                \ 4- send again DB5=DB4=1
20068     $5 20_US                   \ 5- wait 0,1 ms
20069     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
20070     $2 20_US                   \    wait 40 us = LCD cycle
20071     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
20072     $2 20_US                   \    wait 40 us = LCD cycle
20073     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
20074     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
20075     LCD_Clear                   \ 10- "LCD_Clear"
20076     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
20077     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
20078     LCD_Clear                   \ 10- "LCD_Clear"
20079     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
20080     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
20081     CR ." I love you"   
20082     ['] (CR) IS CR              \ ' (CR) is CR
20083     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
20084     CR
20085     ."    RC5toLCD is running. Type STOP to quit"
20086 \    NOECHO                      \ uncomment to run this app without terminal connexion
20087     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
20088     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
20089 ;
20090     \
20091
20092 : STOP                  \ stops multitasking, must to be used before downloading app
20093     ['] (WARM) IS WARM  \ remove START app from FORTH init process
20094     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
20095 ;
20096     \
20097
20098
20099 RST_STATE   ;
20100
20101
20102 CODE MAX    \    n1 n2 -- n3       signed maximum
20103             CMP     @PSP,TOS    \ n2-n1
20104             S<      ?GOTO FW1   \ n2<n1
20105 BW1         ADD     #2,PSP
20106             MOV     @IP+,PC
20107 ENDCODE
20108     \
20109
20110 CODE MIN    \    n1 n2 -- n3       signed minimum
20111             CMP     @PSP,TOS     \ n2-n1
20112             S<      ?GOTO BW1    \ n2<n1
20113 FW1         MOV     @PSP+,TOS
20114             MOV     @IP+,PC
20115 ENDCODE
20116     \
20117
20118 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
20119   >R  <# 0 # #S #>  
20120   R> OVER - 0 MAX SPACES TYPE
20121 ;
20122     \
20123
20124 CODE 20_US                      \ n --      n * 20 us
20125 BEGIN                           \ 3 cycles loop + 6~  
20126 \    MOV     #5,W                \ 3 MCLK = 1 MHz
20127 \    MOV     #23,W               \ 3 MCLK = 4 MHz
20128     MOV     #51,W               \ 3 MCLK = 8 MHz
20129 \    MOV     #104,W              \ 3 MCLK = 16 MHz
20130 \    MOV     #158,W              \ 3 MCLK = 24 MHz
20131     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
20132         SUB #1,W                \ 1
20133     0= UNTIL                    \ 2
20134     SUB     #1,TOS              \ 1
20135 0= UNTIL                        \ 2
20136     MOV     @PSP+,TOS           \ 2
20137     MOV     @IP+,PC             \ 4
20138 ENDCODE
20139     \
20140
20141 CODE TOP_LCD                    \ LCD Sample
20142 \                               \ if write : %xxxxWWWW --
20143 \                               \ if read  : -- %0000RRRR
20144     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
20145     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
20146 0= IF                           \ write LCD bits pattern
20147     AND.B #LCD_DB,TOS           \ 
20148     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
20149     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
20150     MOV @PSP+,TOS               \
20151     MOV @IP+,PC
20152 THEN                            \ read LCD bits pattern
20153     SUB #2,PSP
20154     MOV TOS,0(PSP)
20155     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
20156     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
20157     AND.B #LCD_DB,TOS           \
20158     MOV @IP+,PC
20159 ENDCODE
20160     \
20161
20162 CODE LCD_W                      \ byte --       write byte to LCD 
20163     SUB #2,PSP                  \
20164     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
20165     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
20166     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
20167     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
20168 COLON                           \ high level word starts here 
20169     TOP_LCD 2 20_US             \ write high nibble first
20170     TOP_LCD 2 20_US 
20171 ;
20172     \
20173
20174 CODE LCD_WrC                    \ char --         Write Char
20175     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
20176     JMP LCD_W 
20177 ENDCODE
20178     \
20179
20180 CODE LCD_WrF                    \ func --         Write Fonction
20181     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
20182     JMP LCD_W 
20183 ENDCODE
20184     \
20185
20186 : LCD_Clear 
20187     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
20188 ;
20189     \
20190
20191 : LCD_Home 
20192     $02 LCD_WrF 100 20_us 
20193 ;
20194     \
20195
20196 \ : LCD_Entry_set       $04 OR LCD_WrF ;
20197
20198 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
20199
20200 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
20201
20202 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
20203
20204 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
20205
20206 \ : LCD_Goto            $80 OR LCD_WrF ;
20207
20208 \ CODE LCD_R                      \ -- byte       read byte from LCD
20209 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
20210 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
20211 \ COLON                           \ starts a FORTH word
20212 \     TOP_LCD 2 20_us             \ -- %0000HHHH
20213 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
20214 \ HI2LO                           \ switch from FORTH to assembler
20215 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
20216 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
20217 \     MOV @RSP+,IP                \ restore IP saved by COLON
20218 \     MOV @IP+,PC                 \
20219 \ ENDCODE
20220 \     \
20221
20222 \ CODE LCD_RdS                    \ -- status       Read Status
20223 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
20224 \     JMP LCD_R
20225 \ ENDCODE
20226 \     \
20227
20228 \ CODE LCD_RdC                    \ -- char         Read Char
20229 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
20230 \     JMP LCD_R
20231 \ ENDCODE
20232 \     \
20233
20234 \ -------------+------+------+------+------++---+---+---+---+---------+
20235 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
20236 \ -------------+------+------+------+------++---+---+---+---+---------+
20237 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
20238 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
20239 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
20240 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
20241 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
20242 \ -------------+------+------+------+------++---+---+---+---+---------+
20243
20244
20245 \ ******************************\
20246 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
20247 \ ******************************\
20248 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
20249 \ ------------------------------\
20250 \ define LPM mode for ACCEPT    \
20251 \ ------------------------------\
20252 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
20253 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
20254 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
20255 BIT.B #SW2,&SW2_IN              \ test switch S2
20256 0= IF                           \ case of switch S2 pressed
20257     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
20258     U< IF
20259         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
20260     THEN
20261 ELSE
20262     BIT.B #SW1,&SW1_IN          \ test switch S1 input
20263     0= IF                       \ case of Switch S1 pressed
20264         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
20265         U>= IF                  \
20266             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
20267         THEN                    \
20268     THEN                        \
20269 THEN                            \
20270 RETI                            \ CPU is ON, GIE is OFF
20271 ENDASM                          \
20272     \
20273
20274
20275 \ ------------------------------\
20276 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
20277 \ ******************************\
20278 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
20279 \ ******************************\
20280 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
20281 \                               \       SMclock = 8|16|24 MHz
20282 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
20283 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
20284 \                               \       SR(9)=new Toggle bit memory (ADD on)
20285 \ ------------------------------\
20286 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
20287 \ ------------------------------\
20288 \ define LPM mode for ACCEPT    \
20289 \ ------------------------------\
20290 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
20291 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
20292 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
20293 \ ------------------------------\
20294 \ RC5_FirstStartBitHalfCycle:   \
20295 \ ------------------------------\
20296 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
20297 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
20298 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
20299 MOV     #1778,X                 \ RC5_Period in us
20300 MOV     #14,W                   \ count of loop
20301 BEGIN                           \
20302 \ ------------------------------\
20303 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
20304 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
20305     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
20306 \ RC5_Compute_3/4_Period:       \                   |
20307     RRUM    #1,X                \ X=1/2 cycle       |
20308     MOV     X,Y                 \ Y=1/2             ^
20309     RRUM    #1,Y                \ Y=1/4
20310     ADD     X,Y                 \ Y=3/4
20311 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
20312     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
20313     0= UNTIL                    \
20314 \ ------------------------------\
20315 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
20316 \ ------------------------------\
20317     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
20318     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
20319     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
20320     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
20321     SUB     #1,W                \ decrement count loop
20322 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
20323 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
20324 0<> WHILE                       \ ----> out of loop ----+
20325 \ RC5_compute_7/4_Time_out:     \                       |
20326     ADD     X,Y                 \                       |   out of bound = 7/4 period 
20327 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
20328     BEGIN                       \                       |
20329         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
20330         0>= IF                  \                       |   if cycle time out of bound
20331             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
20332             RETI                \                       |   then quit to do nothing
20333         THEN                    \                       |
20334 \ ------------------------------\                       |
20335         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
20336     0<> UNTIL                   \                   |   |
20337     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
20338 REPEAT                          \ ----> loop back --+   |
20339 \ ------------------------------\                       |
20340 \ RC5_SampleEndOf:              \ <---------------------+
20341 \ ------------------------------\
20342 BIC     #$30,&TA0CTL           \ stop timer_A0
20343 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
20344 \ ******************************\
20345 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
20346 \ ******************************\
20347 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
20348 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
20349 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
20350 BIT     #BIT13,X                \ X(13) = New_RC5_command
20351 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
20352 THEN                            \
20353 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
20354 \ ******************************\
20355 \ RC5_ComputeNewRC5word         \
20356 \ ******************************\
20357 SUB     #4,PSP                  \
20358 MOV     &BASE,2(PSP)            \ save variable BASE before use
20359 MOV     TOS,0(PSP)              \ save TOS before use
20360 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
20361 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
20362 \ ******************************\
20363 \ RC5_ComputeC6bit              \
20364 \ ******************************\
20365 BIT     #$4000,IP              \ test /C6 bit in IP
20366 0= IF   BIS #$40,TOS           \ set C6 bit in S
20367 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
20368 \ ******************************\
20369 \ RC5_CommandByteIsDone         \ RC5_code --
20370 \ ******************************\
20371
20372 \ ------------------------------\
20373 \ Display IR_RC5 code           \
20374 \ ------------------------------\
20375 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
20376 \ ------------------------------\
20377 LO2HI                           \ switch from assembler to FORTH
20378     ['] LCD_CLEAR IS CR         \ redirects CR
20379     ['] LCD_WrC  IS EMIT        \ redirects EMIT
20380     $10 BASE !                 \ change BASE to hexadecimal
20381     CR ." $" 2 U.R             \ print IR_RC5 code
20382     ['] (CR) IS CR              \ restore CR
20383     ['] (EMIT) IS EMIT          \ restore EMIT
20384 HI2LO                           \ switch from FORTH to assembler
20385 \ ------------------------------\
20386 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
20387 \ ------------------------------\
20388 MOV @PSP+,&BASE                 \ restore variable BASE
20389 RETI                            \ CPU is ON, GIE is OFF
20390 ENDASM                          \
20391     \ 
20392
20393 CODE START                      \
20394 \ ------------------------------\
20395 \ TB0CTL = %0000 0010 1001 0100\$3C0
20396 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
20397 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
20398 \                      --       \ID input divider \ 10 = /4
20399 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
20400 \                            -  \TBCLR TimerB Clear
20401 \                             - \TBIE
20402 \                              -\TBIFG
20403 \ --------------------------------\\
20404 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
20405 \              --                 \CM Capture Mode
20406 \                --               \CCIS
20407 \                   -             \SCS
20408 \                    --           \CLLD
20409 \                      -          \CAP
20410 \                        ---      \OUTMOD \ 011 = set/reset
20411 \                           -     \CCIE
20412 \                             -   \CCI
20413 \                              -  \OUT
20414 \                               - \COV
20415 \                                -\CCIFG
20416 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
20417 \ TB0EX0                          \$3E0 
20418 \ ------------------------------\
20419 \ set TimerB to make 50kHz PWM  \
20420 \ ------------------------------\
20421 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
20422 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
20423 \ ------------------------------\
20424 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
20425 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
20426 \ ------------------------------\
20427     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
20428     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
20429 \ ------------------------------\
20430 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
20431 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
20432 \ ------------------------------\
20433 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
20434 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
20435 \ ------------------------------\
20436     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
20437 \ ------------------------------\
20438 \ set TimerB to generate PWM for LCD_Vo
20439 \ ------------------------------\
20440     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
20441 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
20442     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
20443 \ ------------------------------\
20444     BIS.B #LCDVo,&LCDVo_DIR     \
20445     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
20446 \ ------------------------------\
20447     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
20448     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
20449 \ ------------------------------\
20450     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
20451     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
20452 \ ------------------------------\
20453 \ WDT interval init part        \
20454 \ ------------------------------\
20455     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
20456 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
20457 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
20458     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
20459 \ ------------------------------\
20460 \ init RC5_Int                  \
20461 \ ------------------------------\
20462     BIS.B #RC5,&IR_IE           \ enable RC5_Int
20463     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
20464 \ ------------------------------\
20465 \ init interrupt vectors
20466 \ ------------------------------\
20467     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
20468     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
20469 \ ------------------------------\
20470 \ define LPM mode for ACCEPT    \
20471 \ ------------------------------\
20472 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
20473 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
20474 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
20475
20476 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
20477
20478 \ ------------------------------\
20479 \ Init LCD 2x20                 \
20480 \ ------------------------------\
20481     $03E8 20_US                \ 1-  wait 20 ms
20482     $03 TOP_LCD                \ 2- send DB5=DB4=1
20483     $CD 20_US                  \ 3- wait 4,1 ms
20484     $03 TOP_LCD                \ 4- send again DB5=DB4=1
20485     $5 20_US                   \ 5- wait 0,1 ms
20486     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
20487     $2 20_US                   \    wait 40 us = LCD cycle
20488     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
20489     $2 20_US                   \    wait 40 us = LCD cycle
20490     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
20491     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
20492     LCD_Clear                   \ 10- "LCD_Clear"
20493     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
20494     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
20495     LCD_Clear                   \ 10- "LCD_Clear"
20496     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
20497     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
20498     CR ." I love you"   
20499     ['] (CR) IS CR              \ ' (CR) is CR
20500     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
20501     CR
20502     ."    RC5toLCD is running. Type STOP to quit"
20503 \    NOECHO                      \ uncomment to run this app without terminal connexion
20504     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
20505     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
20506 ;
20507     \
20508
20509 : STOP                  \ stops multitasking, must to be used before downloading app
20510     ['] (WARM) IS WARM  \ remove START app from FORTH init process
20511     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
20512 ;
20513     \
20514
20515
20516 RST_STATE   ;
20517
20518
20519 CODE MAX    \    n1 n2 -- n3       signed maximum
20520             CMP     @PSP,TOS    \ n2-n1
20521             S<      ?GOTO FW1   \ n2<n1
20522 BW1         ADD     #2,PSP
20523             MOV     @IP+,PC
20524 ENDCODE
20525     \
20526
20527 CODE MIN    \    n1 n2 -- n3       signed minimum
20528             CMP     @PSP,TOS     \ n2-n1
20529             S<      ?GOTO BW1    \ n2<n1
20530 FW1         MOV     @PSP+,TOS
20531             MOV     @IP+,PC
20532 ENDCODE
20533     \
20534
20535 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
20536   >R  <# 0 # #S #>  
20537   R> OVER - 0 MAX SPACES TYPE
20538 ;
20539     \
20540
20541 CODE 20_US                      \ n --      n * 20 us
20542 BEGIN                           \ 3 cycles loop + 6~  
20543 \    MOV     #5,W                \ 3 MCLK = 1 MHz
20544 \    MOV     #23,W               \ 3 MCLK = 4 MHz
20545     MOV     #51,W               \ 3 MCLK = 8 MHz
20546 \    MOV     #104,W              \ 3 MCLK = 16 MHz
20547 \    MOV     #158,W              \ 3 MCLK = 24 MHz
20548     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
20549         SUB #1,W                \ 1
20550     0= UNTIL                    \ 2
20551     SUB     #1,TOS              \ 1
20552 0= UNTIL                        \ 2
20553     MOV     @PSP+,TOS           \ 2
20554     MOV     @IP+,PC             \ 4
20555 ENDCODE
20556     \
20557
20558 CODE TOP_LCD                    \ LCD Sample
20559 \                               \ if write : %xxxxWWWW --
20560 \                               \ if read  : -- %0000RRRR
20561     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
20562     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
20563 0= IF                           \ write LCD bits pattern
20564     AND.B #LCD_DB,TOS           \ 
20565     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
20566     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
20567     MOV @PSP+,TOS               \
20568     MOV @IP+,PC
20569 THEN                            \ read LCD bits pattern
20570     SUB #2,PSP
20571     MOV TOS,0(PSP)
20572     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
20573     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
20574     AND.B #LCD_DB,TOS           \
20575     MOV @IP+,PC
20576 ENDCODE
20577     \
20578
20579 CODE LCD_W                      \ byte --       write byte to LCD 
20580     SUB #2,PSP                  \
20581     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
20582     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
20583     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
20584     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
20585 COLON                           \ high level word starts here 
20586     TOP_LCD 2 20_US             \ write high nibble first
20587     TOP_LCD 2 20_US 
20588 ;
20589     \
20590
20591 CODE LCD_WrC                    \ char --         Write Char
20592     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
20593     JMP LCD_W 
20594 ENDCODE
20595     \
20596
20597 CODE LCD_WrF                    \ func --         Write Fonction
20598     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
20599     JMP LCD_W 
20600 ENDCODE
20601     \
20602
20603 : LCD_Clear 
20604     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
20605 ;
20606     \
20607
20608 : LCD_Home 
20609     $02 LCD_WrF 100 20_us 
20610 ;
20611     \
20612
20613 \ : LCD_Entry_set       $04 OR LCD_WrF ;
20614
20615 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
20616
20617 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
20618
20619 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
20620
20621 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
20622
20623 \ : LCD_Goto            $80 OR LCD_WrF ;
20624
20625 \ CODE LCD_R                      \ -- byte       read byte from LCD
20626 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
20627 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
20628 \ COLON                           \ starts a FORTH word
20629 \     TOP_LCD 2 20_us             \ -- %0000HHHH
20630 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
20631 \ HI2LO                           \ switch from FORTH to assembler
20632 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
20633 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
20634 \     MOV @RSP+,IP                \ restore IP saved by COLON
20635 \     MOV @IP+,PC                 \
20636 \ ENDCODE
20637 \     \
20638
20639 \ CODE LCD_RdS                    \ -- status       Read Status
20640 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
20641 \     JMP LCD_R
20642 \ ENDCODE
20643 \     \
20644
20645 \ CODE LCD_RdC                    \ -- char         Read Char
20646 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
20647 \     JMP LCD_R
20648 \ ENDCODE
20649 \     \
20650
20651 \ -------------+------+------+------+------++---+---+---+---+---------+
20652 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
20653 \ -------------+------+------+------+------++---+---+---+---+---------+
20654 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
20655 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
20656 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
20657 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
20658 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
20659 \ -------------+------+------+------+------++---+---+---+---+---------+
20660
20661
20662 \ ******************************\
20663 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
20664 \ ******************************\
20665 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
20666 \ ------------------------------\
20667 \ define LPM mode for ACCEPT    \
20668 \ ------------------------------\
20669 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
20670 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
20671 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
20672 BIT.B #SW2,&SW2_IN              \ test switch S2
20673 0= IF                           \ case of switch S2 pressed
20674     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
20675     U< IF
20676         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
20677     THEN
20678 ELSE
20679     BIT.B #SW1,&SW1_IN          \ test switch S1 input
20680     0= IF                       \ case of Switch S1 pressed
20681         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
20682         U>= IF                  \
20683             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
20684         THEN                    \
20685     THEN                        \
20686 THEN                            \
20687 RETI                            \ CPU is ON, GIE is OFF
20688 ENDASM                          \
20689     \
20690
20691
20692 \ ------------------------------\
20693 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
20694 \ ******************************\
20695 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
20696 \ ******************************\
20697 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
20698 \                               \       SMclock = 8|16|24 MHz
20699 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
20700 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
20701 \                               \       SR(9)=new Toggle bit memory (ADD on)
20702 \ ------------------------------\
20703 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
20704 \ ------------------------------\
20705 \ define LPM mode for ACCEPT    \
20706 \ ------------------------------\
20707 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
20708 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
20709 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
20710 \ ------------------------------\
20711 \ RC5_FirstStartBitHalfCycle:   \
20712 \ ------------------------------\
20713 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
20714 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
20715 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
20716 MOV     #1778,X                 \ RC5_Period in us
20717 MOV     #14,W                   \ count of loop
20718 BEGIN                           \
20719 \ ------------------------------\
20720 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
20721 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
20722     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
20723 \ RC5_Compute_3/4_Period:       \                   |
20724     RRUM    #1,X                \ X=1/2 cycle       |
20725     MOV     X,Y                 \ Y=1/2             ^
20726     RRUM    #1,Y                \ Y=1/4
20727     ADD     X,Y                 \ Y=3/4
20728 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
20729     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
20730     0= UNTIL                    \
20731 \ ------------------------------\
20732 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
20733 \ ------------------------------\
20734     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
20735     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
20736     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
20737     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
20738     SUB     #1,W                \ decrement count loop
20739 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
20740 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
20741 0<> WHILE                       \ ----> out of loop ----+
20742 \ RC5_compute_7/4_Time_out:     \                       |
20743     ADD     X,Y                 \                       |   out of bound = 7/4 period 
20744 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
20745     BEGIN                       \                       |
20746         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
20747         0>= IF                  \                       |   if cycle time out of bound
20748             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
20749             RETI                \                       |   then quit to do nothing
20750         THEN                    \                       |
20751 \ ------------------------------\                       |
20752         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
20753     0<> UNTIL                   \                   |   |
20754     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
20755 REPEAT                          \ ----> loop back --+   |
20756 \ ------------------------------\                       |
20757 \ RC5_SampleEndOf:              \ <---------------------+
20758 \ ------------------------------\
20759 BIC     #$30,&TA0CTL           \ stop timer_A0
20760 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
20761 \ ******************************\
20762 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
20763 \ ******************************\
20764 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
20765 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
20766 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
20767 BIT     #BIT13,X                \ X(13) = New_RC5_command
20768 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
20769 THEN                            \
20770 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
20771 \ ******************************\
20772 \ RC5_ComputeNewRC5word         \
20773 \ ******************************\
20774 SUB     #4,PSP                  \
20775 MOV     &BASE,2(PSP)            \ save variable BASE before use
20776 MOV     TOS,0(PSP)              \ save TOS before use
20777 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
20778 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
20779 \ ******************************\
20780 \ RC5_ComputeC6bit              \
20781 \ ******************************\
20782 BIT     #$4000,IP              \ test /C6 bit in IP
20783 0= IF   BIS #$40,TOS           \ set C6 bit in S
20784 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
20785 \ ******************************\
20786 \ RC5_CommandByteIsDone         \ RC5_code --
20787 \ ******************************\
20788
20789 \ ------------------------------\
20790 \ Display IR_RC5 code           \
20791 \ ------------------------------\
20792 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
20793 \ ------------------------------\
20794 LO2HI                           \ switch from assembler to FORTH
20795     ['] LCD_CLEAR IS CR         \ redirects CR
20796     ['] LCD_WrC  IS EMIT        \ redirects EMIT
20797     $10 BASE !                 \ change BASE to hexadecimal
20798     CR ." $" 2 U.R             \ print IR_RC5 code
20799     ['] (CR) IS CR              \ restore CR
20800     ['] (EMIT) IS EMIT          \ restore EMIT
20801 HI2LO                           \ switch from FORTH to assembler
20802 \ ------------------------------\
20803 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
20804 \ ------------------------------\
20805 MOV @PSP+,&BASE                 \ restore variable BASE
20806 RETI                            \ CPU is ON, GIE is OFF
20807 ENDASM                          \
20808     \ 
20809
20810 CODE START                      \
20811 \ ------------------------------\
20812 \ TB0CTL = %0000 0010 1001 0100\$3C0
20813 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
20814 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
20815 \                      --       \ID input divider \ 10 = /4
20816 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
20817 \                            -  \TBCLR TimerB Clear
20818 \                             - \TBIE
20819 \                              -\TBIFG
20820 \ --------------------------------\\
20821 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
20822 \              --                 \CM Capture Mode
20823 \                --               \CCIS
20824 \                   -             \SCS
20825 \                    --           \CLLD
20826 \                      -          \CAP
20827 \                        ---      \OUTMOD \ 011 = set/reset
20828 \                           -     \CCIE
20829 \                             -   \CCI
20830 \                              -  \OUT
20831 \                               - \COV
20832 \                                -\CCIFG
20833 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
20834 \ TB0EX0                          \$3E0 
20835 \ ------------------------------\
20836 \ set TimerB to make 50kHz PWM  \
20837 \ ------------------------------\
20838 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
20839 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
20840 \ ------------------------------\
20841 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
20842 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
20843 \ ------------------------------\
20844     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
20845     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
20846 \ ------------------------------\
20847 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
20848 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
20849 \ ------------------------------\
20850 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
20851 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
20852 \ ------------------------------\
20853     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
20854 \ ------------------------------\
20855 \ set TimerB to generate PWM for LCD_Vo
20856 \ ------------------------------\
20857     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
20858 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
20859     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
20860 \ ------------------------------\
20861     BIS.B #LCDVo,&LCDVo_DIR     \
20862     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
20863 \ ------------------------------\
20864     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
20865     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
20866 \ ------------------------------\
20867     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
20868     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
20869 \ ------------------------------\
20870 \ WDT interval init part        \
20871 \ ------------------------------\
20872     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
20873 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
20874 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
20875     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
20876 \ ------------------------------\
20877 \ init RC5_Int                  \
20878 \ ------------------------------\
20879     BIS.B #RC5,&IR_IE           \ enable RC5_Int
20880     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
20881 \ ------------------------------\
20882 \ init interrupt vectors
20883 \ ------------------------------\
20884     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
20885     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
20886 \ ------------------------------\
20887 \ define LPM mode for ACCEPT    \
20888 \ ------------------------------\
20889 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
20890 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
20891 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
20892
20893 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
20894
20895 \ ------------------------------\
20896 \ Init LCD 2x20                 \
20897 \ ------------------------------\
20898     $03E8 20_US                \ 1-  wait 20 ms
20899     $03 TOP_LCD                \ 2- send DB5=DB4=1
20900     $CD 20_US                  \ 3- wait 4,1 ms
20901     $03 TOP_LCD                \ 4- send again DB5=DB4=1
20902     $5 20_US                   \ 5- wait 0,1 ms
20903     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
20904     $2 20_US                   \    wait 40 us = LCD cycle
20905     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
20906     $2 20_US                   \    wait 40 us = LCD cycle
20907     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
20908     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
20909     LCD_Clear                   \ 10- "LCD_Clear"
20910     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
20911     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
20912     LCD_Clear                   \ 10- "LCD_Clear"
20913     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
20914     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
20915     CR ." I love you"   
20916     ['] (CR) IS CR              \ ' (CR) is CR
20917     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
20918     CR
20919     ."    RC5toLCD is running. Type STOP to quit"
20920 \    NOECHO                      \ uncomment to run this app without terminal connexion
20921     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
20922     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
20923 ;
20924     \
20925
20926 : STOP                  \ stops multitasking, must to be used before downloading app
20927     ['] (WARM) IS WARM  \ remove START app from FORTH init process
20928     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
20929 ;
20930     \
20931
20932
20933 RST_STATE   ;
20934
20935
20936 CODE MAX    \    n1 n2 -- n3       signed maximum
20937             CMP     @PSP,TOS    \ n2-n1
20938             S<      ?GOTO FW1   \ n2<n1
20939 BW1         ADD     #2,PSP
20940             MOV     @IP+,PC
20941 ENDCODE
20942     \
20943
20944 CODE MIN    \    n1 n2 -- n3       signed minimum
20945             CMP     @PSP,TOS     \ n2-n1
20946             S<      ?GOTO BW1    \ n2<n1
20947 FW1         MOV     @PSP+,TOS
20948             MOV     @IP+,PC
20949 ENDCODE
20950     \
20951
20952 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
20953   >R  <# 0 # #S #>  
20954   R> OVER - 0 MAX SPACES TYPE
20955 ;
20956     \
20957
20958 CODE 20_US                      \ n --      n * 20 us
20959 BEGIN                           \ 3 cycles loop + 6~  
20960 \    MOV     #5,W                \ 3 MCLK = 1 MHz
20961 \    MOV     #23,W               \ 3 MCLK = 4 MHz
20962     MOV     #51,W               \ 3 MCLK = 8 MHz
20963 \    MOV     #104,W              \ 3 MCLK = 16 MHz
20964 \    MOV     #158,W              \ 3 MCLK = 24 MHz
20965     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
20966         SUB #1,W                \ 1
20967     0= UNTIL                    \ 2
20968     SUB     #1,TOS              \ 1
20969 0= UNTIL                        \ 2
20970     MOV     @PSP+,TOS           \ 2
20971     MOV     @IP+,PC             \ 4
20972 ENDCODE
20973     \
20974
20975 CODE TOP_LCD                    \ LCD Sample
20976 \                               \ if write : %xxxxWWWW --
20977 \                               \ if read  : -- %0000RRRR
20978     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
20979     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
20980 0= IF                           \ write LCD bits pattern
20981     AND.B #LCD_DB,TOS           \ 
20982     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
20983     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
20984     MOV @PSP+,TOS               \
20985     MOV @IP+,PC
20986 THEN                            \ read LCD bits pattern
20987     SUB #2,PSP
20988     MOV TOS,0(PSP)
20989     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
20990     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
20991     AND.B #LCD_DB,TOS           \
20992     MOV @IP+,PC
20993 ENDCODE
20994     \
20995
20996 CODE LCD_W                      \ byte --       write byte to LCD 
20997     SUB #2,PSP                  \
20998     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
20999     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
21000     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
21001     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
21002 COLON                           \ high level word starts here 
21003     TOP_LCD 2 20_US             \ write high nibble first
21004     TOP_LCD 2 20_US 
21005 ;
21006     \
21007
21008 CODE LCD_WrC                    \ char --         Write Char
21009     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
21010     JMP LCD_W 
21011 ENDCODE
21012     \
21013
21014 CODE LCD_WrF                    \ func --         Write Fonction
21015     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
21016     JMP LCD_W 
21017 ENDCODE
21018     \
21019
21020 : LCD_Clear 
21021     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
21022 ;
21023     \
21024
21025 : LCD_Home 
21026     $02 LCD_WrF 100 20_us 
21027 ;
21028     \
21029
21030 \ : LCD_Entry_set       $04 OR LCD_WrF ;
21031
21032 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
21033
21034 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
21035
21036 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
21037
21038 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
21039
21040 \ : LCD_Goto            $80 OR LCD_WrF ;
21041
21042 \ CODE LCD_R                      \ -- byte       read byte from LCD
21043 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
21044 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
21045 \ COLON                           \ starts a FORTH word
21046 \     TOP_LCD 2 20_us             \ -- %0000HHHH
21047 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
21048 \ HI2LO                           \ switch from FORTH to assembler
21049 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
21050 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
21051 \     MOV @RSP+,IP                \ restore IP saved by COLON
21052 \     MOV @IP+,PC                 \
21053 \ ENDCODE
21054 \     \
21055
21056 \ CODE LCD_RdS                    \ -- status       Read Status
21057 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
21058 \     JMP LCD_R
21059 \ ENDCODE
21060 \     \
21061
21062 \ CODE LCD_RdC                    \ -- char         Read Char
21063 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
21064 \     JMP LCD_R
21065 \ ENDCODE
21066 \     \
21067
21068 \ -------------+------+------+------+------++---+---+---+---+---------+
21069 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
21070 \ -------------+------+------+------+------++---+---+---+---+---------+
21071 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
21072 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
21073 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
21074 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
21075 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
21076 \ -------------+------+------+------+------++---+---+---+---+---------+
21077
21078
21079 \ ******************************\
21080 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
21081 \ ******************************\
21082 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
21083 \ ------------------------------\
21084 \ define LPM mode for ACCEPT    \
21085 \ ------------------------------\
21086 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
21087 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
21088 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
21089 BIT.B #SW2,&SW2_IN              \ test switch S2
21090 0= IF                           \ case of switch S2 pressed
21091     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
21092     U< IF
21093         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
21094     THEN
21095 ELSE
21096     BIT.B #SW1,&SW1_IN          \ test switch S1 input
21097     0= IF                       \ case of Switch S1 pressed
21098         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
21099         U>= IF                  \
21100             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
21101         THEN                    \
21102     THEN                        \
21103 THEN                            \
21104 RETI                            \ CPU is ON, GIE is OFF
21105 ENDASM                          \
21106     \
21107
21108
21109 \ ------------------------------\
21110 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
21111 \ ******************************\
21112 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
21113 \ ******************************\
21114 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
21115 \                               \       SMclock = 8|16|24 MHz
21116 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
21117 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
21118 \                               \       SR(9)=new Toggle bit memory (ADD on)
21119 \ ------------------------------\
21120 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
21121 \ ------------------------------\
21122 \ define LPM mode for ACCEPT    \
21123 \ ------------------------------\
21124 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
21125 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
21126 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
21127 \ ------------------------------\
21128 \ RC5_FirstStartBitHalfCycle:   \
21129 \ ------------------------------\
21130 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
21131 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
21132 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
21133 MOV     #1778,X                 \ RC5_Period in us
21134 MOV     #14,W                   \ count of loop
21135 BEGIN                           \
21136 \ ------------------------------\
21137 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
21138 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
21139     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
21140 \ RC5_Compute_3/4_Period:       \                   |
21141     RRUM    #1,X                \ X=1/2 cycle       |
21142     MOV     X,Y                 \ Y=1/2             ^
21143     RRUM    #1,Y                \ Y=1/4
21144     ADD     X,Y                 \ Y=3/4
21145 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
21146     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
21147     0= UNTIL                    \
21148 \ ------------------------------\
21149 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
21150 \ ------------------------------\
21151     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
21152     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
21153     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
21154     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
21155     SUB     #1,W                \ decrement count loop
21156 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
21157 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
21158 0<> WHILE                       \ ----> out of loop ----+
21159 \ RC5_compute_7/4_Time_out:     \                       |
21160     ADD     X,Y                 \                       |   out of bound = 7/4 period 
21161 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
21162     BEGIN                       \                       |
21163         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
21164         0>= IF                  \                       |   if cycle time out of bound
21165             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
21166             RETI                \                       |   then quit to do nothing
21167         THEN                    \                       |
21168 \ ------------------------------\                       |
21169         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
21170     0<> UNTIL                   \                   |   |
21171     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
21172 REPEAT                          \ ----> loop back --+   |
21173 \ ------------------------------\                       |
21174 \ RC5_SampleEndOf:              \ <---------------------+
21175 \ ------------------------------\
21176 BIC     #$30,&TA0CTL           \ stop timer_A0
21177 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
21178 \ ******************************\
21179 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
21180 \ ******************************\
21181 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
21182 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
21183 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
21184 BIT     #BIT13,X                \ X(13) = New_RC5_command
21185 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
21186 THEN                            \
21187 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
21188 \ ******************************\
21189 \ RC5_ComputeNewRC5word         \
21190 \ ******************************\
21191 SUB     #4,PSP                  \
21192 MOV     &BASE,2(PSP)            \ save variable BASE before use
21193 MOV     TOS,0(PSP)              \ save TOS before use
21194 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
21195 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
21196 \ ******************************\
21197 \ RC5_ComputeC6bit              \
21198 \ ******************************\
21199 BIT     #$4000,IP              \ test /C6 bit in IP
21200 0= IF   BIS #$40,TOS           \ set C6 bit in S
21201 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
21202 \ ******************************\
21203 \ RC5_CommandByteIsDone         \ RC5_code --
21204 \ ******************************\
21205
21206 \ ------------------------------\
21207 \ Display IR_RC5 code           \
21208 \ ------------------------------\
21209 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
21210 \ ------------------------------\
21211 LO2HI                           \ switch from assembler to FORTH
21212     ['] LCD_CLEAR IS CR         \ redirects CR
21213     ['] LCD_WrC  IS EMIT        \ redirects EMIT
21214     $10 BASE !                 \ change BASE to hexadecimal
21215     CR ." $" 2 U.R             \ print IR_RC5 code
21216     ['] (CR) IS CR              \ restore CR
21217     ['] (EMIT) IS EMIT          \ restore EMIT
21218 HI2LO                           \ switch from FORTH to assembler
21219 \ ------------------------------\
21220 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
21221 \ ------------------------------\
21222 MOV @PSP+,&BASE                 \ restore variable BASE
21223 RETI                            \ CPU is ON, GIE is OFF
21224 ENDASM                          \
21225     \ 
21226
21227 CODE START                      \
21228 \ ------------------------------\
21229 \ TB0CTL = %0000 0010 1001 0100\$3C0
21230 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
21231 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
21232 \                      --       \ID input divider \ 10 = /4
21233 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
21234 \                            -  \TBCLR TimerB Clear
21235 \                             - \TBIE
21236 \                              -\TBIFG
21237 \ --------------------------------\\
21238 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
21239 \              --                 \CM Capture Mode
21240 \                --               \CCIS
21241 \                   -             \SCS
21242 \                    --           \CLLD
21243 \                      -          \CAP
21244 \                        ---      \OUTMOD \ 011 = set/reset
21245 \                           -     \CCIE
21246 \                             -   \CCI
21247 \                              -  \OUT
21248 \                               - \COV
21249 \                                -\CCIFG
21250 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
21251 \ TB0EX0                          \$3E0 
21252 \ ------------------------------\
21253 \ set TimerB to make 50kHz PWM  \
21254 \ ------------------------------\
21255 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
21256 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
21257 \ ------------------------------\
21258 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
21259 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
21260 \ ------------------------------\
21261     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
21262     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
21263 \ ------------------------------\
21264 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
21265 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
21266 \ ------------------------------\
21267 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
21268 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
21269 \ ------------------------------\
21270     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
21271 \ ------------------------------\
21272 \ set TimerB to generate PWM for LCD_Vo
21273 \ ------------------------------\
21274     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
21275 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
21276     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
21277 \ ------------------------------\
21278     BIS.B #LCDVo,&LCDVo_DIR     \
21279     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
21280 \ ------------------------------\
21281     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
21282     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
21283 \ ------------------------------\
21284     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
21285     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
21286 \ ------------------------------\
21287 \ WDT interval init part        \
21288 \ ------------------------------\
21289     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
21290 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
21291 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
21292     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
21293 \ ------------------------------\
21294 \ init RC5_Int                  \
21295 \ ------------------------------\
21296     BIS.B #RC5,&IR_IE           \ enable RC5_Int
21297     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
21298 \ ------------------------------\
21299 \ init interrupt vectors
21300 \ ------------------------------\
21301     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
21302     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
21303 \ ------------------------------\
21304 \ define LPM mode for ACCEPT    \
21305 \ ------------------------------\
21306 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
21307 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
21308 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
21309
21310 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
21311
21312 \ ------------------------------\
21313 \ Init LCD 2x20                 \
21314 \ ------------------------------\
21315     $03E8 20_US                \ 1-  wait 20 ms
21316     $03 TOP_LCD                \ 2- send DB5=DB4=1
21317     $CD 20_US                  \ 3- wait 4,1 ms
21318     $03 TOP_LCD                \ 4- send again DB5=DB4=1
21319     $5 20_US                   \ 5- wait 0,1 ms
21320     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
21321     $2 20_US                   \    wait 40 us = LCD cycle
21322     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
21323     $2 20_US                   \    wait 40 us = LCD cycle
21324     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
21325     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
21326     LCD_Clear                   \ 10- "LCD_Clear"
21327     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
21328     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
21329     LCD_Clear                   \ 10- "LCD_Clear"
21330     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
21331     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
21332     CR ." I love you"   
21333     ['] (CR) IS CR              \ ' (CR) is CR
21334     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
21335     CR
21336     ."    RC5toLCD is running. Type STOP to quit"
21337 \    NOECHO                      \ uncomment to run this app without terminal connexion
21338     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
21339     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
21340 ;
21341     \
21342
21343 : STOP                  \ stops multitasking, must to be used before downloading app
21344     ['] (WARM) IS WARM  \ remove START app from FORTH init process
21345     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
21346 ;
21347     \
21348
21349
21350 RST_STATE   ;
21351
21352
21353 CODE MAX    \    n1 n2 -- n3       signed maximum
21354             CMP     @PSP,TOS    \ n2-n1
21355             S<      ?GOTO FW1   \ n2<n1
21356 BW1         ADD     #2,PSP
21357             MOV     @IP+,PC
21358 ENDCODE
21359     \
21360
21361 CODE MIN    \    n1 n2 -- n3       signed minimum
21362             CMP     @PSP,TOS     \ n2-n1
21363             S<      ?GOTO BW1    \ n2<n1
21364 FW1         MOV     @PSP+,TOS
21365             MOV     @IP+,PC
21366 ENDCODE
21367     \
21368
21369 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
21370   >R  <# 0 # #S #>  
21371   R> OVER - 0 MAX SPACES TYPE
21372 ;
21373     \
21374
21375 CODE 20_US                      \ n --      n * 20 us
21376 BEGIN                           \ 3 cycles loop + 6~  
21377 \    MOV     #5,W                \ 3 MCLK = 1 MHz
21378 \    MOV     #23,W               \ 3 MCLK = 4 MHz
21379     MOV     #51,W               \ 3 MCLK = 8 MHz
21380 \    MOV     #104,W              \ 3 MCLK = 16 MHz
21381 \    MOV     #158,W              \ 3 MCLK = 24 MHz
21382     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
21383         SUB #1,W                \ 1
21384     0= UNTIL                    \ 2
21385     SUB     #1,TOS              \ 1
21386 0= UNTIL                        \ 2
21387     MOV     @PSP+,TOS           \ 2
21388     MOV     @IP+,PC             \ 4
21389 ENDCODE
21390     \
21391
21392 CODE TOP_LCD                    \ LCD Sample
21393 \                               \ if write : %xxxxWWWW --
21394 \                               \ if read  : -- %0000RRRR
21395     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
21396     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
21397 0= IF                           \ write LCD bits pattern
21398     AND.B #LCD_DB,TOS           \ 
21399     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
21400     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
21401     MOV @PSP+,TOS               \
21402     MOV @IP+,PC
21403 THEN                            \ read LCD bits pattern
21404     SUB #2,PSP
21405     MOV TOS,0(PSP)
21406     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
21407     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
21408     AND.B #LCD_DB,TOS           \
21409     MOV @IP+,PC
21410 ENDCODE
21411     \
21412
21413 CODE LCD_W                      \ byte --       write byte to LCD 
21414     SUB #2,PSP                  \
21415     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
21416     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
21417     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
21418     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
21419 COLON                           \ high level word starts here 
21420     TOP_LCD 2 20_US             \ write high nibble first
21421     TOP_LCD 2 20_US 
21422 ;
21423     \
21424
21425 CODE LCD_WrC                    \ char --         Write Char
21426     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
21427     JMP LCD_W 
21428 ENDCODE
21429     \
21430
21431 CODE LCD_WrF                    \ func --         Write Fonction
21432     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
21433     JMP LCD_W 
21434 ENDCODE
21435     \
21436
21437 : LCD_Clear 
21438     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
21439 ;
21440     \
21441
21442 : LCD_Home 
21443     $02 LCD_WrF 100 20_us 
21444 ;
21445     \
21446
21447 \ : LCD_Entry_set       $04 OR LCD_WrF ;
21448
21449 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
21450
21451 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
21452
21453 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
21454
21455 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
21456
21457 \ : LCD_Goto            $80 OR LCD_WrF ;
21458
21459 \ CODE LCD_R                      \ -- byte       read byte from LCD
21460 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
21461 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
21462 \ COLON                           \ starts a FORTH word
21463 \     TOP_LCD 2 20_us             \ -- %0000HHHH
21464 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
21465 \ HI2LO                           \ switch from FORTH to assembler
21466 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
21467 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
21468 \     MOV @RSP+,IP                \ restore IP saved by COLON
21469 \     MOV @IP+,PC                 \
21470 \ ENDCODE
21471 \     \
21472
21473 \ CODE LCD_RdS                    \ -- status       Read Status
21474 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
21475 \     JMP LCD_R
21476 \ ENDCODE
21477 \     \
21478
21479 \ CODE LCD_RdC                    \ -- char         Read Char
21480 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
21481 \     JMP LCD_R
21482 \ ENDCODE
21483 \     \
21484
21485 \ -------------+------+------+------+------++---+---+---+---+---------+
21486 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
21487 \ -------------+------+------+------+------++---+---+---+---+---------+
21488 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
21489 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
21490 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
21491 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
21492 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
21493 \ -------------+------+------+------+------++---+---+---+---+---------+
21494
21495
21496 \ ******************************\
21497 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
21498 \ ******************************\
21499 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
21500 \ ------------------------------\
21501 \ define LPM mode for ACCEPT    \
21502 \ ------------------------------\
21503 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
21504 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
21505 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
21506 BIT.B #SW2,&SW2_IN              \ test switch S2
21507 0= IF                           \ case of switch S2 pressed
21508     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
21509     U< IF
21510         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
21511     THEN
21512 ELSE
21513     BIT.B #SW1,&SW1_IN          \ test switch S1 input
21514     0= IF                       \ case of Switch S1 pressed
21515         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
21516         U>= IF                  \
21517             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
21518         THEN                    \
21519     THEN                        \
21520 THEN                            \
21521 RETI                            \ CPU is ON, GIE is OFF
21522 ENDASM                          \
21523     \
21524
21525
21526 \ ------------------------------\
21527 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
21528 \ ******************************\
21529 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
21530 \ ******************************\
21531 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
21532 \                               \       SMclock = 8|16|24 MHz
21533 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
21534 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
21535 \                               \       SR(9)=new Toggle bit memory (ADD on)
21536 \ ------------------------------\
21537 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
21538 \ ------------------------------\
21539 \ define LPM mode for ACCEPT    \
21540 \ ------------------------------\
21541 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
21542 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
21543 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
21544 \ ------------------------------\
21545 \ RC5_FirstStartBitHalfCycle:   \
21546 \ ------------------------------\
21547 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
21548 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
21549 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
21550 MOV     #1778,X                 \ RC5_Period in us
21551 MOV     #14,W                   \ count of loop
21552 BEGIN                           \
21553 \ ------------------------------\
21554 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
21555 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
21556     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
21557 \ RC5_Compute_3/4_Period:       \                   |
21558     RRUM    #1,X                \ X=1/2 cycle       |
21559     MOV     X,Y                 \ Y=1/2             ^
21560     RRUM    #1,Y                \ Y=1/4
21561     ADD     X,Y                 \ Y=3/4
21562 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
21563     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
21564     0= UNTIL                    \
21565 \ ------------------------------\
21566 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
21567 \ ------------------------------\
21568     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
21569     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
21570     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
21571     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
21572     SUB     #1,W                \ decrement count loop
21573 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
21574 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
21575 0<> WHILE                       \ ----> out of loop ----+
21576 \ RC5_compute_7/4_Time_out:     \                       |
21577     ADD     X,Y                 \                       |   out of bound = 7/4 period 
21578 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
21579     BEGIN                       \                       |
21580         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
21581         0>= IF                  \                       |   if cycle time out of bound
21582             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
21583             RETI                \                       |   then quit to do nothing
21584         THEN                    \                       |
21585 \ ------------------------------\                       |
21586         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
21587     0<> UNTIL                   \                   |   |
21588     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
21589 REPEAT                          \ ----> loop back --+   |
21590 \ ------------------------------\                       |
21591 \ RC5_SampleEndOf:              \ <---------------------+
21592 \ ------------------------------\
21593 BIC     #$30,&TA0CTL           \ stop timer_A0
21594 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
21595 \ ******************************\
21596 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
21597 \ ******************************\
21598 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
21599 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
21600 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
21601 BIT     #BIT13,X                \ X(13) = New_RC5_command
21602 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
21603 THEN                            \
21604 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
21605 \ ******************************\
21606 \ RC5_ComputeNewRC5word         \
21607 \ ******************************\
21608 SUB     #4,PSP                  \
21609 MOV     &BASE,2(PSP)            \ save variable BASE before use
21610 MOV     TOS,0(PSP)              \ save TOS before use
21611 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
21612 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
21613 \ ******************************\
21614 \ RC5_ComputeC6bit              \
21615 \ ******************************\
21616 BIT     #$4000,IP              \ test /C6 bit in IP
21617 0= IF   BIS #$40,TOS           \ set C6 bit in S
21618 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
21619 \ ******************************\
21620 \ RC5_CommandByteIsDone         \ RC5_code --
21621 \ ******************************\
21622
21623 \ ------------------------------\
21624 \ Display IR_RC5 code           \
21625 \ ------------------------------\
21626 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
21627 \ ------------------------------\
21628 LO2HI                           \ switch from assembler to FORTH
21629     ['] LCD_CLEAR IS CR         \ redirects CR
21630     ['] LCD_WrC  IS EMIT        \ redirects EMIT
21631     $10 BASE !                 \ change BASE to hexadecimal
21632     CR ." $" 2 U.R             \ print IR_RC5 code
21633     ['] (CR) IS CR              \ restore CR
21634     ['] (EMIT) IS EMIT          \ restore EMIT
21635 HI2LO                           \ switch from FORTH to assembler
21636 \ ------------------------------\
21637 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
21638 \ ------------------------------\
21639 MOV @PSP+,&BASE                 \ restore variable BASE
21640 RETI                            \ CPU is ON, GIE is OFF
21641 ENDASM                          \
21642     \ 
21643
21644 CODE START                      \
21645 \ ------------------------------\
21646 \ TB0CTL = %0000 0010 1001 0100\$3C0
21647 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
21648 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
21649 \                      --       \ID input divider \ 10 = /4
21650 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
21651 \                            -  \TBCLR TimerB Clear
21652 \                             - \TBIE
21653 \                              -\TBIFG
21654 \ --------------------------------\\
21655 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
21656 \              --                 \CM Capture Mode
21657 \                --               \CCIS
21658 \                   -             \SCS
21659 \                    --           \CLLD
21660 \                      -          \CAP
21661 \                        ---      \OUTMOD \ 011 = set/reset
21662 \                           -     \CCIE
21663 \                             -   \CCI
21664 \                              -  \OUT
21665 \                               - \COV
21666 \                                -\CCIFG
21667 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
21668 \ TB0EX0                          \$3E0 
21669 \ ------------------------------\
21670 \ set TimerB to make 50kHz PWM  \
21671 \ ------------------------------\
21672 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
21673 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
21674 \ ------------------------------\
21675 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
21676 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
21677 \ ------------------------------\
21678     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
21679     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
21680 \ ------------------------------\
21681 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
21682 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
21683 \ ------------------------------\
21684 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
21685 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
21686 \ ------------------------------\
21687     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
21688 \ ------------------------------\
21689 \ set TimerB to generate PWM for LCD_Vo
21690 \ ------------------------------\
21691     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
21692 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
21693     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
21694 \ ------------------------------\
21695     BIS.B #LCDVo,&LCDVo_DIR     \
21696     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
21697 \ ------------------------------\
21698     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
21699     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
21700 \ ------------------------------\
21701     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
21702     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
21703 \ ------------------------------\
21704 \ WDT interval init part        \
21705 \ ------------------------------\
21706     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
21707 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
21708 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
21709     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
21710 \ ------------------------------\
21711 \ init RC5_Int                  \
21712 \ ------------------------------\
21713     BIS.B #RC5,&IR_IE           \ enable RC5_Int
21714     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
21715 \ ------------------------------\
21716 \ init interrupt vectors
21717 \ ------------------------------\
21718     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
21719     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
21720 \ ------------------------------\
21721 \ define LPM mode for ACCEPT    \
21722 \ ------------------------------\
21723 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
21724 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
21725 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
21726
21727 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
21728
21729 \ ------------------------------\
21730 \ Init LCD 2x20                 \
21731 \ ------------------------------\
21732     $03E8 20_US                \ 1-  wait 20 ms
21733     $03 TOP_LCD                \ 2- send DB5=DB4=1
21734     $CD 20_US                  \ 3- wait 4,1 ms
21735     $03 TOP_LCD                \ 4- send again DB5=DB4=1
21736     $5 20_US                   \ 5- wait 0,1 ms
21737     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
21738     $2 20_US                   \    wait 40 us = LCD cycle
21739     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
21740     $2 20_US                   \    wait 40 us = LCD cycle
21741     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
21742     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
21743     LCD_Clear                   \ 10- "LCD_Clear"
21744     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
21745     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
21746     LCD_Clear                   \ 10- "LCD_Clear"
21747     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
21748     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
21749     CR ." I love you"   
21750     ['] (CR) IS CR              \ ' (CR) is CR
21751     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
21752     CR
21753     ."    RC5toLCD is running. Type STOP to quit"
21754 \    NOECHO                      \ uncomment to run this app without terminal connexion
21755     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
21756     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
21757 ;
21758     \
21759
21760 : STOP                  \ stops multitasking, must to be used before downloading app
21761     ['] (WARM) IS WARM  \ remove START app from FORTH init process
21762     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
21763 ;
21764     \
21765
21766
21767 RST_STATE   ;
21768
21769
21770 CODE MAX    \    n1 n2 -- n3       signed maximum
21771             CMP     @PSP,TOS    \ n2-n1
21772             S<      ?GOTO FW1   \ n2<n1
21773 BW1         ADD     #2,PSP
21774             MOV     @IP+,PC
21775 ENDCODE
21776     \
21777
21778 CODE MIN    \    n1 n2 -- n3       signed minimum
21779             CMP     @PSP,TOS     \ n2-n1
21780             S<      ?GOTO BW1    \ n2<n1
21781 FW1         MOV     @PSP+,TOS
21782             MOV     @IP+,PC
21783 ENDCODE
21784     \
21785
21786 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
21787   >R  <# 0 # #S #>  
21788   R> OVER - 0 MAX SPACES TYPE
21789 ;
21790     \
21791
21792 CODE 20_US                      \ n --      n * 20 us
21793 BEGIN                           \ 3 cycles loop + 6~  
21794 \    MOV     #5,W                \ 3 MCLK = 1 MHz
21795 \    MOV     #23,W               \ 3 MCLK = 4 MHz
21796     MOV     #51,W               \ 3 MCLK = 8 MHz
21797 \    MOV     #104,W              \ 3 MCLK = 16 MHz
21798 \    MOV     #158,W              \ 3 MCLK = 24 MHz
21799     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
21800         SUB #1,W                \ 1
21801     0= UNTIL                    \ 2
21802     SUB     #1,TOS              \ 1
21803 0= UNTIL                        \ 2
21804     MOV     @PSP+,TOS           \ 2
21805     MOV     @IP+,PC             \ 4
21806 ENDCODE
21807     \
21808
21809 CODE TOP_LCD                    \ LCD Sample
21810 \                               \ if write : %xxxxWWWW --
21811 \                               \ if read  : -- %0000RRRR
21812     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
21813     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
21814 0= IF                           \ write LCD bits pattern
21815     AND.B #LCD_DB,TOS           \ 
21816     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
21817     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
21818     MOV @PSP+,TOS               \
21819     MOV @IP+,PC
21820 THEN                            \ read LCD bits pattern
21821     SUB #2,PSP
21822     MOV TOS,0(PSP)
21823     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
21824     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
21825     AND.B #LCD_DB,TOS           \
21826     MOV @IP+,PC
21827 ENDCODE
21828     \
21829
21830 CODE LCD_W                      \ byte --       write byte to LCD 
21831     SUB #2,PSP                  \
21832     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
21833     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
21834     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
21835     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
21836 COLON                           \ high level word starts here 
21837     TOP_LCD 2 20_US             \ write high nibble first
21838     TOP_LCD 2 20_US 
21839 ;
21840     \
21841
21842 CODE LCD_WrC                    \ char --         Write Char
21843     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
21844     JMP LCD_W 
21845 ENDCODE
21846     \
21847
21848 CODE LCD_WrF                    \ func --         Write Fonction
21849     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
21850     JMP LCD_W 
21851 ENDCODE
21852     \
21853
21854 : LCD_Clear 
21855     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
21856 ;
21857     \
21858
21859 : LCD_Home 
21860     $02 LCD_WrF 100 20_us 
21861 ;
21862     \
21863
21864 \ : LCD_Entry_set       $04 OR LCD_WrF ;
21865
21866 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
21867
21868 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
21869
21870 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
21871
21872 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
21873
21874 \ : LCD_Goto            $80 OR LCD_WrF ;
21875
21876 \ CODE LCD_R                      \ -- byte       read byte from LCD
21877 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
21878 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
21879 \ COLON                           \ starts a FORTH word
21880 \     TOP_LCD 2 20_us             \ -- %0000HHHH
21881 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
21882 \ HI2LO                           \ switch from FORTH to assembler
21883 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
21884 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
21885 \     MOV @RSP+,IP                \ restore IP saved by COLON
21886 \     MOV @IP+,PC                 \
21887 \ ENDCODE
21888 \     \
21889
21890 \ CODE LCD_RdS                    \ -- status       Read Status
21891 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
21892 \     JMP LCD_R
21893 \ ENDCODE
21894 \     \
21895
21896 \ CODE LCD_RdC                    \ -- char         Read Char
21897 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
21898 \     JMP LCD_R
21899 \ ENDCODE
21900 \     \
21901
21902 \ -------------+------+------+------+------++---+---+---+---+---------+
21903 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
21904 \ -------------+------+------+------+------++---+---+---+---+---------+
21905 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
21906 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
21907 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
21908 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
21909 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
21910 \ -------------+------+------+------+------++---+---+---+---+---------+
21911
21912
21913 \ ******************************\
21914 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
21915 \ ******************************\
21916 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
21917 \ ------------------------------\
21918 \ define LPM mode for ACCEPT    \
21919 \ ------------------------------\
21920 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
21921 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
21922 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
21923 BIT.B #SW2,&SW2_IN              \ test switch S2
21924 0= IF                           \ case of switch S2 pressed
21925     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
21926     U< IF
21927         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
21928     THEN
21929 ELSE
21930     BIT.B #SW1,&SW1_IN          \ test switch S1 input
21931     0= IF                       \ case of Switch S1 pressed
21932         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
21933         U>= IF                  \
21934             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
21935         THEN                    \
21936     THEN                        \
21937 THEN                            \
21938 RETI                            \ CPU is ON, GIE is OFF
21939 ENDASM                          \
21940     \
21941
21942
21943 \ ------------------------------\
21944 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
21945 \ ******************************\
21946 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
21947 \ ******************************\
21948 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
21949 \                               \       SMclock = 8|16|24 MHz
21950 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
21951 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
21952 \                               \       SR(9)=new Toggle bit memory (ADD on)
21953 \ ------------------------------\
21954 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
21955 \ ------------------------------\
21956 \ define LPM mode for ACCEPT    \
21957 \ ------------------------------\
21958 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
21959 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
21960 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
21961 \ ------------------------------\
21962 \ RC5_FirstStartBitHalfCycle:   \
21963 \ ------------------------------\
21964 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
21965 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
21966 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
21967 MOV     #1778,X                 \ RC5_Period in us
21968 MOV     #14,W                   \ count of loop
21969 BEGIN                           \
21970 \ ------------------------------\
21971 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
21972 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
21973     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
21974 \ RC5_Compute_3/4_Period:       \                   |
21975     RRUM    #1,X                \ X=1/2 cycle       |
21976     MOV     X,Y                 \ Y=1/2             ^
21977     RRUM    #1,Y                \ Y=1/4
21978     ADD     X,Y                 \ Y=3/4
21979 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
21980     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
21981     0= UNTIL                    \
21982 \ ------------------------------\
21983 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
21984 \ ------------------------------\
21985     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
21986     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
21987     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
21988     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
21989     SUB     #1,W                \ decrement count loop
21990 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
21991 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
21992 0<> WHILE                       \ ----> out of loop ----+
21993 \ RC5_compute_7/4_Time_out:     \                       |
21994     ADD     X,Y                 \                       |   out of bound = 7/4 period 
21995 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
21996     BEGIN                       \                       |
21997         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
21998         0>= IF                  \                       |   if cycle time out of bound
21999             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
22000             RETI                \                       |   then quit to do nothing
22001         THEN                    \                       |
22002 \ ------------------------------\                       |
22003         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
22004     0<> UNTIL                   \                   |   |
22005     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
22006 REPEAT                          \ ----> loop back --+   |
22007 \ ------------------------------\                       |
22008 \ RC5_SampleEndOf:              \ <---------------------+
22009 \ ------------------------------\
22010 BIC     #$30,&TA0CTL           \ stop timer_A0
22011 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
22012 \ ******************************\
22013 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
22014 \ ******************************\
22015 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
22016 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
22017 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
22018 BIT     #BIT13,X                \ X(13) = New_RC5_command
22019 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
22020 THEN                            \
22021 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
22022 \ ******************************\
22023 \ RC5_ComputeNewRC5word         \
22024 \ ******************************\
22025 SUB     #4,PSP                  \
22026 MOV     &BASE,2(PSP)            \ save variable BASE before use
22027 MOV     TOS,0(PSP)              \ save TOS before use
22028 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
22029 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
22030 \ ******************************\
22031 \ RC5_ComputeC6bit              \
22032 \ ******************************\
22033 BIT     #$4000,IP              \ test /C6 bit in IP
22034 0= IF   BIS #$40,TOS           \ set C6 bit in S
22035 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
22036 \ ******************************\
22037 \ RC5_CommandByteIsDone         \ RC5_code --
22038 \ ******************************\
22039
22040 \ ------------------------------\
22041 \ Display IR_RC5 code           \
22042 \ ------------------------------\
22043 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
22044 \ ------------------------------\
22045 LO2HI                           \ switch from assembler to FORTH
22046     ['] LCD_CLEAR IS CR         \ redirects CR
22047     ['] LCD_WrC  IS EMIT        \ redirects EMIT
22048     $10 BASE !                 \ change BASE to hexadecimal
22049     CR ." $" 2 U.R             \ print IR_RC5 code
22050     ['] (CR) IS CR              \ restore CR
22051     ['] (EMIT) IS EMIT          \ restore EMIT
22052 HI2LO                           \ switch from FORTH to assembler
22053 \ ------------------------------\
22054 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
22055 \ ------------------------------\
22056 MOV @PSP+,&BASE                 \ restore variable BASE
22057 RETI                            \ CPU is ON, GIE is OFF
22058 ENDASM                          \
22059     \ 
22060
22061 CODE START                      \
22062 \ ------------------------------\
22063 \ TB0CTL = %0000 0010 1001 0100\$3C0
22064 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
22065 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
22066 \                      --       \ID input divider \ 10 = /4
22067 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
22068 \                            -  \TBCLR TimerB Clear
22069 \                             - \TBIE
22070 \                              -\TBIFG
22071 \ --------------------------------\\
22072 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
22073 \              --                 \CM Capture Mode
22074 \                --               \CCIS
22075 \                   -             \SCS
22076 \                    --           \CLLD
22077 \                      -          \CAP
22078 \                        ---      \OUTMOD \ 011 = set/reset
22079 \                           -     \CCIE
22080 \                             -   \CCI
22081 \                              -  \OUT
22082 \                               - \COV
22083 \                                -\CCIFG
22084 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
22085 \ TB0EX0                          \$3E0 
22086 \ ------------------------------\
22087 \ set TimerB to make 50kHz PWM  \
22088 \ ------------------------------\
22089 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
22090 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
22091 \ ------------------------------\
22092 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
22093 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
22094 \ ------------------------------\
22095     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
22096     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
22097 \ ------------------------------\
22098 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
22099 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
22100 \ ------------------------------\
22101 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
22102 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
22103 \ ------------------------------\
22104     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
22105 \ ------------------------------\
22106 \ set TimerB to generate PWM for LCD_Vo
22107 \ ------------------------------\
22108     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
22109 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
22110     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
22111 \ ------------------------------\
22112     BIS.B #LCDVo,&LCDVo_DIR     \
22113     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
22114 \ ------------------------------\
22115     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
22116     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
22117 \ ------------------------------\
22118     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
22119     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
22120 \ ------------------------------\
22121 \ WDT interval init part        \
22122 \ ------------------------------\
22123     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
22124 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
22125 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
22126     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
22127 \ ------------------------------\
22128 \ init RC5_Int                  \
22129 \ ------------------------------\
22130     BIS.B #RC5,&IR_IE           \ enable RC5_Int
22131     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
22132 \ ------------------------------\
22133 \ init interrupt vectors
22134 \ ------------------------------\
22135     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
22136     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
22137 \ ------------------------------\
22138 \ define LPM mode for ACCEPT    \
22139 \ ------------------------------\
22140 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
22141 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
22142 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
22143
22144 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
22145
22146 \ ------------------------------\
22147 \ Init LCD 2x20                 \
22148 \ ------------------------------\
22149     $03E8 20_US                \ 1-  wait 20 ms
22150     $03 TOP_LCD                \ 2- send DB5=DB4=1
22151     $CD 20_US                  \ 3- wait 4,1 ms
22152     $03 TOP_LCD                \ 4- send again DB5=DB4=1
22153     $5 20_US                   \ 5- wait 0,1 ms
22154     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
22155     $2 20_US                   \    wait 40 us = LCD cycle
22156     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
22157     $2 20_US                   \    wait 40 us = LCD cycle
22158     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
22159     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
22160     LCD_Clear                   \ 10- "LCD_Clear"
22161     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
22162     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
22163     LCD_Clear                   \ 10- "LCD_Clear"
22164     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
22165     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
22166     CR ." I love you"   
22167     ['] (CR) IS CR              \ ' (CR) is CR
22168     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
22169     CR
22170     ."    RC5toLCD is running. Type STOP to quit"
22171 \    NOECHO                      \ uncomment to run this app without terminal connexion
22172     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
22173     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
22174 ;
22175     \
22176
22177 : STOP                  \ stops multitasking, must to be used before downloading app
22178     ['] (WARM) IS WARM  \ remove START app from FORTH init process
22179     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
22180 ;
22181     \
22182
22183
22184 RST_STATE   ;
22185
22186
22187 CODE MAX    \    n1 n2 -- n3       signed maximum
22188             CMP     @PSP,TOS    \ n2-n1
22189             S<      ?GOTO FW1   \ n2<n1
22190 BW1         ADD     #2,PSP
22191             MOV     @IP+,PC
22192 ENDCODE
22193     \
22194
22195 CODE MIN    \    n1 n2 -- n3       signed minimum
22196             CMP     @PSP,TOS     \ n2-n1
22197             S<      ?GOTO BW1    \ n2<n1
22198 FW1         MOV     @PSP+,TOS
22199             MOV     @IP+,PC
22200 ENDCODE
22201     \
22202
22203 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
22204   >R  <# 0 # #S #>  
22205   R> OVER - 0 MAX SPACES TYPE
22206 ;
22207     \
22208
22209 CODE 20_US                      \ n --      n * 20 us
22210 BEGIN                           \ 3 cycles loop + 6~  
22211 \    MOV     #5,W                \ 3 MCLK = 1 MHz
22212 \    MOV     #23,W               \ 3 MCLK = 4 MHz
22213     MOV     #51,W               \ 3 MCLK = 8 MHz
22214 \    MOV     #104,W              \ 3 MCLK = 16 MHz
22215 \    MOV     #158,W              \ 3 MCLK = 24 MHz
22216     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
22217         SUB #1,W                \ 1
22218     0= UNTIL                    \ 2
22219     SUB     #1,TOS              \ 1
22220 0= UNTIL                        \ 2
22221     MOV     @PSP+,TOS           \ 2
22222     MOV     @IP+,PC             \ 4
22223 ENDCODE
22224     \
22225
22226 CODE TOP_LCD                    \ LCD Sample
22227 \                               \ if write : %xxxxWWWW --
22228 \                               \ if read  : -- %0000RRRR
22229     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
22230     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
22231 0= IF                           \ write LCD bits pattern
22232     AND.B #LCD_DB,TOS           \ 
22233     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
22234     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
22235     MOV @PSP+,TOS               \
22236     MOV @IP+,PC
22237 THEN                            \ read LCD bits pattern
22238     SUB #2,PSP
22239     MOV TOS,0(PSP)
22240     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
22241     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
22242     AND.B #LCD_DB,TOS           \
22243     MOV @IP+,PC
22244 ENDCODE
22245     \
22246
22247 CODE LCD_W                      \ byte --       write byte to LCD 
22248     SUB #2,PSP                  \
22249     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
22250     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
22251     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
22252     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
22253 COLON                           \ high level word starts here 
22254     TOP_LCD 2 20_US             \ write high nibble first
22255     TOP_LCD 2 20_US 
22256 ;
22257     \
22258
22259 CODE LCD_WrC                    \ char --         Write Char
22260     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
22261     JMP LCD_W 
22262 ENDCODE
22263     \
22264
22265 CODE LCD_WrF                    \ func --         Write Fonction
22266     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
22267     JMP LCD_W 
22268 ENDCODE
22269     \
22270
22271 : LCD_Clear 
22272     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
22273 ;
22274     \
22275
22276 : LCD_Home 
22277     $02 LCD_WrF 100 20_us 
22278 ;
22279     \
22280
22281 \ : LCD_Entry_set       $04 OR LCD_WrF ;
22282
22283 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
22284
22285 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
22286
22287 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
22288
22289 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
22290
22291 \ : LCD_Goto            $80 OR LCD_WrF ;
22292
22293 \ CODE LCD_R                      \ -- byte       read byte from LCD
22294 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
22295 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
22296 \ COLON                           \ starts a FORTH word
22297 \     TOP_LCD 2 20_us             \ -- %0000HHHH
22298 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
22299 \ HI2LO                           \ switch from FORTH to assembler
22300 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
22301 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
22302 \     MOV @RSP+,IP                \ restore IP saved by COLON
22303 \     MOV @IP+,PC                 \
22304 \ ENDCODE
22305 \     \
22306
22307 \ CODE LCD_RdS                    \ -- status       Read Status
22308 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
22309 \     JMP LCD_R
22310 \ ENDCODE
22311 \     \
22312
22313 \ CODE LCD_RdC                    \ -- char         Read Char
22314 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
22315 \     JMP LCD_R
22316 \ ENDCODE
22317 \     \
22318
22319 \ -------------+------+------+------+------++---+---+---+---+---------+
22320 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
22321 \ -------------+------+------+------+------++---+---+---+---+---------+
22322 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
22323 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
22324 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
22325 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
22326 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
22327 \ -------------+------+------+------+------++---+---+---+---+---------+
22328
22329
22330 \ ******************************\
22331 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
22332 \ ******************************\
22333 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
22334 \ ------------------------------\
22335 \ define LPM mode for ACCEPT    \
22336 \ ------------------------------\
22337 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
22338 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
22339 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
22340 BIT.B #SW2,&SW2_IN              \ test switch S2
22341 0= IF                           \ case of switch S2 pressed
22342     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
22343     U< IF
22344         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
22345     THEN
22346 ELSE
22347     BIT.B #SW1,&SW1_IN          \ test switch S1 input
22348     0= IF                       \ case of Switch S1 pressed
22349         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
22350         U>= IF                  \
22351             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
22352         THEN                    \
22353     THEN                        \
22354 THEN                            \
22355 RETI                            \ CPU is ON, GIE is OFF
22356 ENDASM                          \
22357     \
22358
22359
22360 \ ------------------------------\
22361 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
22362 \ ******************************\
22363 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
22364 \ ******************************\
22365 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
22366 \                               \       SMclock = 8|16|24 MHz
22367 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
22368 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
22369 \                               \       SR(9)=new Toggle bit memory (ADD on)
22370 \ ------------------------------\
22371 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
22372 \ ------------------------------\
22373 \ define LPM mode for ACCEPT    \
22374 \ ------------------------------\
22375 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
22376 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
22377 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
22378 \ ------------------------------\
22379 \ RC5_FirstStartBitHalfCycle:   \
22380 \ ------------------------------\
22381 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
22382 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
22383 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
22384 MOV     #1778,X                 \ RC5_Period in us
22385 MOV     #14,W                   \ count of loop
22386 BEGIN                           \
22387 \ ------------------------------\
22388 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
22389 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
22390     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
22391 \ RC5_Compute_3/4_Period:       \                   |
22392     RRUM    #1,X                \ X=1/2 cycle       |
22393     MOV     X,Y                 \ Y=1/2             ^
22394     RRUM    #1,Y                \ Y=1/4
22395     ADD     X,Y                 \ Y=3/4
22396 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
22397     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
22398     0= UNTIL                    \
22399 \ ------------------------------\
22400 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
22401 \ ------------------------------\
22402     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
22403     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
22404     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
22405     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
22406     SUB     #1,W                \ decrement count loop
22407 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
22408 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
22409 0<> WHILE                       \ ----> out of loop ----+
22410 \ RC5_compute_7/4_Time_out:     \                       |
22411     ADD     X,Y                 \                       |   out of bound = 7/4 period 
22412 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
22413     BEGIN                       \                       |
22414         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
22415         0>= IF                  \                       |   if cycle time out of bound
22416             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
22417             RETI                \                       |   then quit to do nothing
22418         THEN                    \                       |
22419 \ ------------------------------\                       |
22420         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
22421     0<> UNTIL                   \                   |   |
22422     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
22423 REPEAT                          \ ----> loop back --+   |
22424 \ ------------------------------\                       |
22425 \ RC5_SampleEndOf:              \ <---------------------+
22426 \ ------------------------------\
22427 BIC     #$30,&TA0CTL           \ stop timer_A0
22428 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
22429 \ ******************************\
22430 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
22431 \ ******************************\
22432 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
22433 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
22434 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
22435 BIT     #BIT13,X                \ X(13) = New_RC5_command
22436 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
22437 THEN                            \
22438 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
22439 \ ******************************\
22440 \ RC5_ComputeNewRC5word         \
22441 \ ******************************\
22442 SUB     #4,PSP                  \
22443 MOV     &BASE,2(PSP)            \ save variable BASE before use
22444 MOV     TOS,0(PSP)              \ save TOS before use
22445 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
22446 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
22447 \ ******************************\
22448 \ RC5_ComputeC6bit              \
22449 \ ******************************\
22450 BIT     #$4000,IP              \ test /C6 bit in IP
22451 0= IF   BIS #$40,TOS           \ set C6 bit in S
22452 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
22453 \ ******************************\
22454 \ RC5_CommandByteIsDone         \ RC5_code --
22455 \ ******************************\
22456
22457 \ ------------------------------\
22458 \ Display IR_RC5 code           \
22459 \ ------------------------------\
22460 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
22461 \ ------------------------------\
22462 LO2HI                           \ switch from assembler to FORTH
22463     ['] LCD_CLEAR IS CR         \ redirects CR
22464     ['] LCD_WrC  IS EMIT        \ redirects EMIT
22465     $10 BASE !                 \ change BASE to hexadecimal
22466     CR ." $" 2 U.R             \ print IR_RC5 code
22467     ['] (CR) IS CR              \ restore CR
22468     ['] (EMIT) IS EMIT          \ restore EMIT
22469 HI2LO                           \ switch from FORTH to assembler
22470 \ ------------------------------\
22471 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
22472 \ ------------------------------\
22473 MOV @PSP+,&BASE                 \ restore variable BASE
22474 RETI                            \ CPU is ON, GIE is OFF
22475 ENDASM                          \
22476     \ 
22477
22478 CODE START                      \
22479 \ ------------------------------\
22480 \ TB0CTL = %0000 0010 1001 0100\$3C0
22481 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
22482 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
22483 \                      --       \ID input divider \ 10 = /4
22484 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
22485 \                            -  \TBCLR TimerB Clear
22486 \                             - \TBIE
22487 \                              -\TBIFG
22488 \ --------------------------------\\
22489 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
22490 \              --                 \CM Capture Mode
22491 \                --               \CCIS
22492 \                   -             \SCS
22493 \                    --           \CLLD
22494 \                      -          \CAP
22495 \                        ---      \OUTMOD \ 011 = set/reset
22496 \                           -     \CCIE
22497 \                             -   \CCI
22498 \                              -  \OUT
22499 \                               - \COV
22500 \                                -\CCIFG
22501 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
22502 \ TB0EX0                          \$3E0 
22503 \ ------------------------------\
22504 \ set TimerB to make 50kHz PWM  \
22505 \ ------------------------------\
22506 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
22507 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
22508 \ ------------------------------\
22509 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
22510 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
22511 \ ------------------------------\
22512     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
22513     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
22514 \ ------------------------------\
22515 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
22516 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
22517 \ ------------------------------\
22518 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
22519 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
22520 \ ------------------------------\
22521     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
22522 \ ------------------------------\
22523 \ set TimerB to generate PWM for LCD_Vo
22524 \ ------------------------------\
22525     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
22526 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
22527     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
22528 \ ------------------------------\
22529     BIS.B #LCDVo,&LCDVo_DIR     \
22530     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
22531 \ ------------------------------\
22532     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
22533     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
22534 \ ------------------------------\
22535     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
22536     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
22537 \ ------------------------------\
22538 \ WDT interval init part        \
22539 \ ------------------------------\
22540     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
22541 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
22542 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
22543     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
22544 \ ------------------------------\
22545 \ init RC5_Int                  \
22546 \ ------------------------------\
22547     BIS.B #RC5,&IR_IE           \ enable RC5_Int
22548     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
22549 \ ------------------------------\
22550 \ init interrupt vectors
22551 \ ------------------------------\
22552     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
22553     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
22554 \ ------------------------------\
22555 \ define LPM mode for ACCEPT    \
22556 \ ------------------------------\
22557 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
22558 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
22559 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
22560
22561 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
22562
22563 \ ------------------------------\
22564 \ Init LCD 2x20                 \
22565 \ ------------------------------\
22566     $03E8 20_US                \ 1-  wait 20 ms
22567     $03 TOP_LCD                \ 2- send DB5=DB4=1
22568     $CD 20_US                  \ 3- wait 4,1 ms
22569     $03 TOP_LCD                \ 4- send again DB5=DB4=1
22570     $5 20_US                   \ 5- wait 0,1 ms
22571     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
22572     $2 20_US                   \    wait 40 us = LCD cycle
22573     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
22574     $2 20_US                   \    wait 40 us = LCD cycle
22575     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
22576     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
22577     LCD_Clear                   \ 10- "LCD_Clear"
22578     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
22579     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
22580     LCD_Clear                   \ 10- "LCD_Clear"
22581     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
22582     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
22583     CR ." I love you"   
22584     ['] (CR) IS CR              \ ' (CR) is CR
22585     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
22586     CR
22587     ."    RC5toLCD is running. Type STOP to quit"
22588 \    NOECHO                      \ uncomment to run this app without terminal connexion
22589     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
22590     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
22591 ;
22592     \
22593
22594 : STOP                  \ stops multitasking, must to be used before downloading app
22595     ['] (WARM) IS WARM  \ remove START app from FORTH init process
22596     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
22597 ;
22598     \
22599
22600
22601 RST_STATE   ;
22602
22603
22604 CODE MAX    \    n1 n2 -- n3       signed maximum
22605             CMP     @PSP,TOS    \ n2-n1
22606             S<      ?GOTO FW1   \ n2<n1
22607 BW1         ADD     #2,PSP
22608             MOV     @IP+,PC
22609 ENDCODE
22610     \
22611
22612 CODE MIN    \    n1 n2 -- n3       signed minimum
22613             CMP     @PSP,TOS     \ n2-n1
22614             S<      ?GOTO BW1    \ n2<n1
22615 FW1         MOV     @PSP+,TOS
22616             MOV     @IP+,PC
22617 ENDCODE
22618     \
22619
22620 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
22621   >R  <# 0 # #S #>  
22622   R> OVER - 0 MAX SPACES TYPE
22623 ;
22624     \
22625
22626 CODE 20_US                      \ n --      n * 20 us
22627 BEGIN                           \ 3 cycles loop + 6~  
22628 \    MOV     #5,W                \ 3 MCLK = 1 MHz
22629 \    MOV     #23,W               \ 3 MCLK = 4 MHz
22630     MOV     #51,W               \ 3 MCLK = 8 MHz
22631 \    MOV     #104,W              \ 3 MCLK = 16 MHz
22632 \    MOV     #158,W              \ 3 MCLK = 24 MHz
22633     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
22634         SUB #1,W                \ 1
22635     0= UNTIL                    \ 2
22636     SUB     #1,TOS              \ 1
22637 0= UNTIL                        \ 2
22638     MOV     @PSP+,TOS           \ 2
22639     MOV     @IP+,PC             \ 4
22640 ENDCODE
22641     \
22642
22643 CODE TOP_LCD                    \ LCD Sample
22644 \                               \ if write : %xxxxWWWW --
22645 \                               \ if read  : -- %0000RRRR
22646     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
22647     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
22648 0= IF                           \ write LCD bits pattern
22649     AND.B #LCD_DB,TOS           \ 
22650     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
22651     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
22652     MOV @PSP+,TOS               \
22653     MOV @IP+,PC
22654 THEN                            \ read LCD bits pattern
22655     SUB #2,PSP
22656     MOV TOS,0(PSP)
22657     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
22658     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
22659     AND.B #LCD_DB,TOS           \
22660     MOV @IP+,PC
22661 ENDCODE
22662     \
22663
22664 CODE LCD_W                      \ byte --       write byte to LCD 
22665     SUB #2,PSP                  \
22666     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
22667     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
22668     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
22669     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
22670 COLON                           \ high level word starts here 
22671     TOP_LCD 2 20_US             \ write high nibble first
22672     TOP_LCD 2 20_US 
22673 ;
22674     \
22675
22676 CODE LCD_WrC                    \ char --         Write Char
22677     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
22678     JMP LCD_W 
22679 ENDCODE
22680     \
22681
22682 CODE LCD_WrF                    \ func --         Write Fonction
22683     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
22684     JMP LCD_W 
22685 ENDCODE
22686     \
22687
22688 : LCD_Clear 
22689     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
22690 ;
22691     \
22692
22693 : LCD_Home 
22694     $02 LCD_WrF 100 20_us 
22695 ;
22696     \
22697
22698 \ : LCD_Entry_set       $04 OR LCD_WrF ;
22699
22700 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
22701
22702 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
22703
22704 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
22705
22706 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
22707
22708 \ : LCD_Goto            $80 OR LCD_WrF ;
22709
22710 \ CODE LCD_R                      \ -- byte       read byte from LCD
22711 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
22712 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
22713 \ COLON                           \ starts a FORTH word
22714 \     TOP_LCD 2 20_us             \ -- %0000HHHH
22715 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
22716 \ HI2LO                           \ switch from FORTH to assembler
22717 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
22718 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
22719 \     MOV @RSP+,IP                \ restore IP saved by COLON
22720 \     MOV @IP+,PC                 \
22721 \ ENDCODE
22722 \     \
22723
22724 \ CODE LCD_RdS                    \ -- status       Read Status
22725 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
22726 \     JMP LCD_R
22727 \ ENDCODE
22728 \     \
22729
22730 \ CODE LCD_RdC                    \ -- char         Read Char
22731 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
22732 \     JMP LCD_R
22733 \ ENDCODE
22734 \     \
22735
22736 \ -------------+------+------+------+------++---+---+---+---+---------+
22737 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
22738 \ -------------+------+------+------+------++---+---+---+---+---------+
22739 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
22740 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
22741 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
22742 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
22743 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
22744 \ -------------+------+------+------+------++---+---+---+---+---------+
22745
22746
22747 \ ******************************\
22748 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
22749 \ ******************************\
22750 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
22751 \ ------------------------------\
22752 \ define LPM mode for ACCEPT    \
22753 \ ------------------------------\
22754 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
22755 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
22756 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
22757 BIT.B #SW2,&SW2_IN              \ test switch S2
22758 0= IF                           \ case of switch S2 pressed
22759     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
22760     U< IF
22761         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
22762     THEN
22763 ELSE
22764     BIT.B #SW1,&SW1_IN          \ test switch S1 input
22765     0= IF                       \ case of Switch S1 pressed
22766         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
22767         U>= IF                  \
22768             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
22769         THEN                    \
22770     THEN                        \
22771 THEN                            \
22772 RETI                            \ CPU is ON, GIE is OFF
22773 ENDASM                          \
22774     \
22775
22776
22777 \ ------------------------------\
22778 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
22779 \ ******************************\
22780 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
22781 \ ******************************\
22782 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
22783 \                               \       SMclock = 8|16|24 MHz
22784 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
22785 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
22786 \                               \       SR(9)=new Toggle bit memory (ADD on)
22787 \ ------------------------------\
22788 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
22789 \ ------------------------------\
22790 \ define LPM mode for ACCEPT    \
22791 \ ------------------------------\
22792 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
22793 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
22794 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
22795 \ ------------------------------\
22796 \ RC5_FirstStartBitHalfCycle:   \
22797 \ ------------------------------\
22798 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
22799 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
22800 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
22801 MOV     #1778,X                 \ RC5_Period in us
22802 MOV     #14,W                   \ count of loop
22803 BEGIN                           \
22804 \ ------------------------------\
22805 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
22806 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
22807     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
22808 \ RC5_Compute_3/4_Period:       \                   |
22809     RRUM    #1,X                \ X=1/2 cycle       |
22810     MOV     X,Y                 \ Y=1/2             ^
22811     RRUM    #1,Y                \ Y=1/4
22812     ADD     X,Y                 \ Y=3/4
22813 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
22814     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
22815     0= UNTIL                    \
22816 \ ------------------------------\
22817 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
22818 \ ------------------------------\
22819     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
22820     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
22821     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
22822     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
22823     SUB     #1,W                \ decrement count loop
22824 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
22825 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
22826 0<> WHILE                       \ ----> out of loop ----+
22827 \ RC5_compute_7/4_Time_out:     \                       |
22828     ADD     X,Y                 \                       |   out of bound = 7/4 period 
22829 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
22830     BEGIN                       \                       |
22831         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
22832         0>= IF                  \                       |   if cycle time out of bound
22833             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
22834             RETI                \                       |   then quit to do nothing
22835         THEN                    \                       |
22836 \ ------------------------------\                       |
22837         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
22838     0<> UNTIL                   \                   |   |
22839     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
22840 REPEAT                          \ ----> loop back --+   |
22841 \ ------------------------------\                       |
22842 \ RC5_SampleEndOf:              \ <---------------------+
22843 \ ------------------------------\
22844 BIC     #$30,&TA0CTL           \ stop timer_A0
22845 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
22846 \ ******************************\
22847 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
22848 \ ******************************\
22849 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
22850 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
22851 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
22852 BIT     #BIT13,X                \ X(13) = New_RC5_command
22853 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
22854 THEN                            \
22855 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
22856 \ ******************************\
22857 \ RC5_ComputeNewRC5word         \
22858 \ ******************************\
22859 SUB     #4,PSP                  \
22860 MOV     &BASE,2(PSP)            \ save variable BASE before use
22861 MOV     TOS,0(PSP)              \ save TOS before use
22862 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
22863 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
22864 \ ******************************\
22865 \ RC5_ComputeC6bit              \
22866 \ ******************************\
22867 BIT     #$4000,IP              \ test /C6 bit in IP
22868 0= IF   BIS #$40,TOS           \ set C6 bit in S
22869 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
22870 \ ******************************\
22871 \ RC5_CommandByteIsDone         \ RC5_code --
22872 \ ******************************\
22873
22874 \ ------------------------------\
22875 \ Display IR_RC5 code           \
22876 \ ------------------------------\
22877 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
22878 \ ------------------------------\
22879 LO2HI                           \ switch from assembler to FORTH
22880     ['] LCD_CLEAR IS CR         \ redirects CR
22881     ['] LCD_WrC  IS EMIT        \ redirects EMIT
22882     $10 BASE !                 \ change BASE to hexadecimal
22883     CR ." $" 2 U.R             \ print IR_RC5 code
22884     ['] (CR) IS CR              \ restore CR
22885     ['] (EMIT) IS EMIT          \ restore EMIT
22886 HI2LO                           \ switch from FORTH to assembler
22887 \ ------------------------------\
22888 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
22889 \ ------------------------------\
22890 MOV @PSP+,&BASE                 \ restore variable BASE
22891 RETI                            \ CPU is ON, GIE is OFF
22892 ENDASM                          \
22893     \ 
22894
22895 CODE START                      \
22896 \ ------------------------------\
22897 \ TB0CTL = %0000 0010 1001 0100\$3C0
22898 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
22899 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
22900 \                      --       \ID input divider \ 10 = /4
22901 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
22902 \                            -  \TBCLR TimerB Clear
22903 \                             - \TBIE
22904 \                              -\TBIFG
22905 \ --------------------------------\\
22906 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
22907 \              --                 \CM Capture Mode
22908 \                --               \CCIS
22909 \                   -             \SCS
22910 \                    --           \CLLD
22911 \                      -          \CAP
22912 \                        ---      \OUTMOD \ 011 = set/reset
22913 \                           -     \CCIE
22914 \                             -   \CCI
22915 \                              -  \OUT
22916 \                               - \COV
22917 \                                -\CCIFG
22918 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
22919 \ TB0EX0                          \$3E0 
22920 \ ------------------------------\
22921 \ set TimerB to make 50kHz PWM  \
22922 \ ------------------------------\
22923 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
22924 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
22925 \ ------------------------------\
22926 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
22927 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
22928 \ ------------------------------\
22929     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
22930     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
22931 \ ------------------------------\
22932 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
22933 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
22934 \ ------------------------------\
22935 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
22936 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
22937 \ ------------------------------\
22938     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
22939 \ ------------------------------\
22940 \ set TimerB to generate PWM for LCD_Vo
22941 \ ------------------------------\
22942     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
22943 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
22944     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
22945 \ ------------------------------\
22946     BIS.B #LCDVo,&LCDVo_DIR     \
22947     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
22948 \ ------------------------------\
22949     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
22950     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
22951 \ ------------------------------\
22952     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
22953     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
22954 \ ------------------------------\
22955 \ WDT interval init part        \
22956 \ ------------------------------\
22957     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
22958 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
22959 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
22960     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
22961 \ ------------------------------\
22962 \ init RC5_Int                  \
22963 \ ------------------------------\
22964     BIS.B #RC5,&IR_IE           \ enable RC5_Int
22965     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
22966 \ ------------------------------\
22967 \ init interrupt vectors
22968 \ ------------------------------\
22969     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
22970     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
22971 \ ------------------------------\
22972 \ define LPM mode for ACCEPT    \
22973 \ ------------------------------\
22974 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
22975 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
22976 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
22977
22978 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
22979
22980 \ ------------------------------\
22981 \ Init LCD 2x20                 \
22982 \ ------------------------------\
22983     $03E8 20_US                \ 1-  wait 20 ms
22984     $03 TOP_LCD                \ 2- send DB5=DB4=1
22985     $CD 20_US                  \ 3- wait 4,1 ms
22986     $03 TOP_LCD                \ 4- send again DB5=DB4=1
22987     $5 20_US                   \ 5- wait 0,1 ms
22988     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
22989     $2 20_US                   \    wait 40 us = LCD cycle
22990     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
22991     $2 20_US                   \    wait 40 us = LCD cycle
22992     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
22993     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
22994     LCD_Clear                   \ 10- "LCD_Clear"
22995     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
22996     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
22997     LCD_Clear                   \ 10- "LCD_Clear"
22998     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
22999     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
23000     CR ." I love you"   
23001     ['] (CR) IS CR              \ ' (CR) is CR
23002     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
23003     CR
23004     ."    RC5toLCD is running. Type STOP to quit"
23005 \    NOECHO                      \ uncomment to run this app without terminal connexion
23006     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
23007     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
23008 ;
23009     \
23010
23011 : STOP                  \ stops multitasking, must to be used before downloading app
23012     ['] (WARM) IS WARM  \ remove START app from FORTH init process
23013     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
23014 ;
23015     \
23016
23017
23018 RST_STATE   ;
23019
23020
23021 CODE MAX    \    n1 n2 -- n3       signed maximum
23022             CMP     @PSP,TOS    \ n2-n1
23023             S<      ?GOTO FW1   \ n2<n1
23024 BW1         ADD     #2,PSP
23025             MOV     @IP+,PC
23026 ENDCODE
23027     \
23028
23029 CODE MIN    \    n1 n2 -- n3       signed minimum
23030             CMP     @PSP,TOS     \ n2-n1
23031             S<      ?GOTO BW1    \ n2<n1
23032 FW1         MOV     @PSP+,TOS
23033             MOV     @IP+,PC
23034 ENDCODE
23035     \
23036
23037 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
23038   >R  <# 0 # #S #>  
23039   R> OVER - 0 MAX SPACES TYPE
23040 ;
23041     \
23042
23043 CODE 20_US                      \ n --      n * 20 us
23044 BEGIN                           \ 3 cycles loop + 6~  
23045 \    MOV     #5,W                \ 3 MCLK = 1 MHz
23046 \    MOV     #23,W               \ 3 MCLK = 4 MHz
23047     MOV     #51,W               \ 3 MCLK = 8 MHz
23048 \    MOV     #104,W              \ 3 MCLK = 16 MHz
23049 \    MOV     #158,W              \ 3 MCLK = 24 MHz
23050     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
23051         SUB #1,W                \ 1
23052     0= UNTIL                    \ 2
23053     SUB     #1,TOS              \ 1
23054 0= UNTIL                        \ 2
23055     MOV     @PSP+,TOS           \ 2
23056     MOV     @IP+,PC             \ 4
23057 ENDCODE
23058     \
23059
23060 CODE TOP_LCD                    \ LCD Sample
23061 \                               \ if write : %xxxxWWWW --
23062 \                               \ if read  : -- %0000RRRR
23063     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
23064     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
23065 0= IF                           \ write LCD bits pattern
23066     AND.B #LCD_DB,TOS           \ 
23067     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
23068     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
23069     MOV @PSP+,TOS               \
23070     MOV @IP+,PC
23071 THEN                            \ read LCD bits pattern
23072     SUB #2,PSP
23073     MOV TOS,0(PSP)
23074     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
23075     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
23076     AND.B #LCD_DB,TOS           \
23077     MOV @IP+,PC
23078 ENDCODE
23079     \
23080
23081 CODE LCD_W                      \ byte --       write byte to LCD 
23082     SUB #2,PSP                  \
23083     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
23084     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
23085     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
23086     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
23087 COLON                           \ high level word starts here 
23088     TOP_LCD 2 20_US             \ write high nibble first
23089     TOP_LCD 2 20_US 
23090 ;
23091     \
23092
23093 CODE LCD_WrC                    \ char --         Write Char
23094     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
23095     JMP LCD_W 
23096 ENDCODE
23097     \
23098
23099 CODE LCD_WrF                    \ func --         Write Fonction
23100     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
23101     JMP LCD_W 
23102 ENDCODE
23103     \
23104
23105 : LCD_Clear 
23106     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
23107 ;
23108     \
23109
23110 : LCD_Home 
23111     $02 LCD_WrF 100 20_us 
23112 ;
23113     \
23114
23115 \ : LCD_Entry_set       $04 OR LCD_WrF ;
23116
23117 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
23118
23119 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
23120
23121 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
23122
23123 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
23124
23125 \ : LCD_Goto            $80 OR LCD_WrF ;
23126
23127 \ CODE LCD_R                      \ -- byte       read byte from LCD
23128 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
23129 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
23130 \ COLON                           \ starts a FORTH word
23131 \     TOP_LCD 2 20_us             \ -- %0000HHHH
23132 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
23133 \ HI2LO                           \ switch from FORTH to assembler
23134 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
23135 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
23136 \     MOV @RSP+,IP                \ restore IP saved by COLON
23137 \     MOV @IP+,PC                 \
23138 \ ENDCODE
23139 \     \
23140
23141 \ CODE LCD_RdS                    \ -- status       Read Status
23142 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
23143 \     JMP LCD_R
23144 \ ENDCODE
23145 \     \
23146
23147 \ CODE LCD_RdC                    \ -- char         Read Char
23148 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
23149 \     JMP LCD_R
23150 \ ENDCODE
23151 \     \
23152
23153 \ -------------+------+------+------+------++---+---+---+---+---------+
23154 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
23155 \ -------------+------+------+------+------++---+---+---+---+---------+
23156 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
23157 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
23158 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
23159 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
23160 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
23161 \ -------------+------+------+------+------++---+---+---+---+---------+
23162
23163
23164 \ ******************************\
23165 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
23166 \ ******************************\
23167 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
23168 \ ------------------------------\
23169 \ define LPM mode for ACCEPT    \
23170 \ ------------------------------\
23171 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
23172 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
23173 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
23174 BIT.B #SW2,&SW2_IN              \ test switch S2
23175 0= IF                           \ case of switch S2 pressed
23176     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
23177     U< IF
23178         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
23179     THEN
23180 ELSE
23181     BIT.B #SW1,&SW1_IN          \ test switch S1 input
23182     0= IF                       \ case of Switch S1 pressed
23183         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
23184         U>= IF                  \
23185             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
23186         THEN                    \
23187     THEN                        \
23188 THEN                            \
23189 RETI                            \ CPU is ON, GIE is OFF
23190 ENDASM                          \
23191     \
23192
23193
23194 \ ------------------------------\
23195 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
23196 \ ******************************\
23197 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
23198 \ ******************************\
23199 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
23200 \                               \       SMclock = 8|16|24 MHz
23201 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
23202 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
23203 \                               \       SR(9)=new Toggle bit memory (ADD on)
23204 \ ------------------------------\
23205 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
23206 \ ------------------------------\
23207 \ define LPM mode for ACCEPT    \
23208 \ ------------------------------\
23209 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
23210 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
23211 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
23212 \ ------------------------------\
23213 \ RC5_FirstStartBitHalfCycle:   \
23214 \ ------------------------------\
23215 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
23216 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
23217 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
23218 MOV     #1778,X                 \ RC5_Period in us
23219 MOV     #14,W                   \ count of loop
23220 BEGIN                           \
23221 \ ------------------------------\
23222 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
23223 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
23224     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
23225 \ RC5_Compute_3/4_Period:       \                   |
23226     RRUM    #1,X                \ X=1/2 cycle       |
23227     MOV     X,Y                 \ Y=1/2             ^
23228     RRUM    #1,Y                \ Y=1/4
23229     ADD     X,Y                 \ Y=3/4
23230 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
23231     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
23232     0= UNTIL                    \
23233 \ ------------------------------\
23234 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
23235 \ ------------------------------\
23236     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
23237     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
23238     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
23239     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
23240     SUB     #1,W                \ decrement count loop
23241 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
23242 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
23243 0<> WHILE                       \ ----> out of loop ----+
23244 \ RC5_compute_7/4_Time_out:     \                       |
23245     ADD     X,Y                 \                       |   out of bound = 7/4 period 
23246 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
23247     BEGIN                       \                       |
23248         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
23249         0>= IF                  \                       |   if cycle time out of bound
23250             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
23251             RETI                \                       |   then quit to do nothing
23252         THEN                    \                       |
23253 \ ------------------------------\                       |
23254         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
23255     0<> UNTIL                   \                   |   |
23256     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
23257 REPEAT                          \ ----> loop back --+   |
23258 \ ------------------------------\                       |
23259 \ RC5_SampleEndOf:              \ <---------------------+
23260 \ ------------------------------\
23261 BIC     #$30,&TA0CTL           \ stop timer_A0
23262 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
23263 \ ******************************\
23264 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
23265 \ ******************************\
23266 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
23267 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
23268 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
23269 BIT     #BIT13,X                \ X(13) = New_RC5_command
23270 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
23271 THEN                            \
23272 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
23273 \ ******************************\
23274 \ RC5_ComputeNewRC5word         \
23275 \ ******************************\
23276 SUB     #4,PSP                  \
23277 MOV     &BASE,2(PSP)            \ save variable BASE before use
23278 MOV     TOS,0(PSP)              \ save TOS before use
23279 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
23280 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
23281 \ ******************************\
23282 \ RC5_ComputeC6bit              \
23283 \ ******************************\
23284 BIT     #$4000,IP              \ test /C6 bit in IP
23285 0= IF   BIS #$40,TOS           \ set C6 bit in S
23286 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
23287 \ ******************************\
23288 \ RC5_CommandByteIsDone         \ RC5_code --
23289 \ ******************************\
23290
23291 \ ------------------------------\
23292 \ Display IR_RC5 code           \
23293 \ ------------------------------\
23294 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
23295 \ ------------------------------\
23296 LO2HI                           \ switch from assembler to FORTH
23297     ['] LCD_CLEAR IS CR         \ redirects CR
23298     ['] LCD_WrC  IS EMIT        \ redirects EMIT
23299     $10 BASE !                 \ change BASE to hexadecimal
23300     CR ." $" 2 U.R             \ print IR_RC5 code
23301     ['] (CR) IS CR              \ restore CR
23302     ['] (EMIT) IS EMIT          \ restore EMIT
23303 HI2LO                           \ switch from FORTH to assembler
23304 \ ------------------------------\
23305 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
23306 \ ------------------------------\
23307 MOV @PSP+,&BASE                 \ restore variable BASE
23308 RETI                            \ CPU is ON, GIE is OFF
23309 ENDASM                          \
23310     \ 
23311
23312 CODE START                      \
23313 \ ------------------------------\
23314 \ TB0CTL = %0000 0010 1001 0100\$3C0
23315 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
23316 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
23317 \                      --       \ID input divider \ 10 = /4
23318 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
23319 \                            -  \TBCLR TimerB Clear
23320 \                             - \TBIE
23321 \                              -\TBIFG
23322 \ --------------------------------\\
23323 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
23324 \              --                 \CM Capture Mode
23325 \                --               \CCIS
23326 \                   -             \SCS
23327 \                    --           \CLLD
23328 \                      -          \CAP
23329 \                        ---      \OUTMOD \ 011 = set/reset
23330 \                           -     \CCIE
23331 \                             -   \CCI
23332 \                              -  \OUT
23333 \                               - \COV
23334 \                                -\CCIFG
23335 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
23336 \ TB0EX0                          \$3E0 
23337 \ ------------------------------\
23338 \ set TimerB to make 50kHz PWM  \
23339 \ ------------------------------\
23340 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
23341 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
23342 \ ------------------------------\
23343 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
23344 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
23345 \ ------------------------------\
23346     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
23347     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
23348 \ ------------------------------\
23349 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
23350 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
23351 \ ------------------------------\
23352 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
23353 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
23354 \ ------------------------------\
23355     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
23356 \ ------------------------------\
23357 \ set TimerB to generate PWM for LCD_Vo
23358 \ ------------------------------\
23359     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
23360 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
23361     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
23362 \ ------------------------------\
23363     BIS.B #LCDVo,&LCDVo_DIR     \
23364     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
23365 \ ------------------------------\
23366     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
23367     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
23368 \ ------------------------------\
23369     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
23370     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
23371 \ ------------------------------\
23372 \ WDT interval init part        \
23373 \ ------------------------------\
23374     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
23375 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
23376 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
23377     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
23378 \ ------------------------------\
23379 \ init RC5_Int                  \
23380 \ ------------------------------\
23381     BIS.B #RC5,&IR_IE           \ enable RC5_Int
23382     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
23383 \ ------------------------------\
23384 \ init interrupt vectors
23385 \ ------------------------------\
23386     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
23387     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
23388 \ ------------------------------\
23389 \ define LPM mode for ACCEPT    \
23390 \ ------------------------------\
23391 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
23392 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
23393 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
23394
23395 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
23396
23397 \ ------------------------------\
23398 \ Init LCD 2x20                 \
23399 \ ------------------------------\
23400     $03E8 20_US                \ 1-  wait 20 ms
23401     $03 TOP_LCD                \ 2- send DB5=DB4=1
23402     $CD 20_US                  \ 3- wait 4,1 ms
23403     $03 TOP_LCD                \ 4- send again DB5=DB4=1
23404     $5 20_US                   \ 5- wait 0,1 ms
23405     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
23406     $2 20_US                   \    wait 40 us = LCD cycle
23407     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
23408     $2 20_US                   \    wait 40 us = LCD cycle
23409     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
23410     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
23411     LCD_Clear                   \ 10- "LCD_Clear"
23412     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
23413     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
23414     LCD_Clear                   \ 10- "LCD_Clear"
23415     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
23416     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
23417     CR ." I love you"   
23418     ['] (CR) IS CR              \ ' (CR) is CR
23419     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
23420     CR
23421     ."    RC5toLCD is running. Type STOP to quit"
23422 \    NOECHO                      \ uncomment to run this app without terminal connexion
23423     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
23424     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
23425 ;
23426     \
23427
23428 : STOP                  \ stops multitasking, must to be used before downloading app
23429     ['] (WARM) IS WARM  \ remove START app from FORTH init process
23430     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
23431 ;
23432     \
23433
23434
23435 RST_STATE   ;
23436
23437
23438 CODE MAX    \    n1 n2 -- n3       signed maximum
23439             CMP     @PSP,TOS    \ n2-n1
23440             S<      ?GOTO FW1   \ n2<n1
23441 BW1         ADD     #2,PSP
23442             MOV     @IP+,PC
23443 ENDCODE
23444     \
23445
23446 CODE MIN    \    n1 n2 -- n3       signed minimum
23447             CMP     @PSP,TOS     \ n2-n1
23448             S<      ?GOTO BW1    \ n2<n1
23449 FW1         MOV     @PSP+,TOS
23450             MOV     @IP+,PC
23451 ENDCODE
23452     \
23453
23454 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
23455   >R  <# 0 # #S #>  
23456   R> OVER - 0 MAX SPACES TYPE
23457 ;
23458     \
23459
23460 CODE 20_US                      \ n --      n * 20 us
23461 BEGIN                           \ 3 cycles loop + 6~  
23462 \    MOV     #5,W                \ 3 MCLK = 1 MHz
23463 \    MOV     #23,W               \ 3 MCLK = 4 MHz
23464     MOV     #51,W               \ 3 MCLK = 8 MHz
23465 \    MOV     #104,W              \ 3 MCLK = 16 MHz
23466 \    MOV     #158,W              \ 3 MCLK = 24 MHz
23467     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
23468         SUB #1,W                \ 1
23469     0= UNTIL                    \ 2
23470     SUB     #1,TOS              \ 1
23471 0= UNTIL                        \ 2
23472     MOV     @PSP+,TOS           \ 2
23473     MOV     @IP+,PC             \ 4
23474 ENDCODE
23475     \
23476
23477 CODE TOP_LCD                    \ LCD Sample
23478 \                               \ if write : %xxxxWWWW --
23479 \                               \ if read  : -- %0000RRRR
23480     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
23481     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
23482 0= IF                           \ write LCD bits pattern
23483     AND.B #LCD_DB,TOS           \ 
23484     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
23485     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
23486     MOV @PSP+,TOS               \
23487     MOV @IP+,PC
23488 THEN                            \ read LCD bits pattern
23489     SUB #2,PSP
23490     MOV TOS,0(PSP)
23491     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
23492     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
23493     AND.B #LCD_DB,TOS           \
23494     MOV @IP+,PC
23495 ENDCODE
23496     \
23497
23498 CODE LCD_W                      \ byte --       write byte to LCD 
23499     SUB #2,PSP                  \
23500     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
23501     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
23502     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
23503     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
23504 COLON                           \ high level word starts here 
23505     TOP_LCD 2 20_US             \ write high nibble first
23506     TOP_LCD 2 20_US 
23507 ;
23508     \
23509
23510 CODE LCD_WrC                    \ char --         Write Char
23511     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
23512     JMP LCD_W 
23513 ENDCODE
23514     \
23515
23516 CODE LCD_WrF                    \ func --         Write Fonction
23517     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
23518     JMP LCD_W 
23519 ENDCODE
23520     \
23521
23522 : LCD_Clear 
23523     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
23524 ;
23525     \
23526
23527 : LCD_Home 
23528     $02 LCD_WrF 100 20_us 
23529 ;
23530     \
23531
23532 \ : LCD_Entry_set       $04 OR LCD_WrF ;
23533
23534 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
23535
23536 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
23537
23538 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
23539
23540 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
23541
23542 \ : LCD_Goto            $80 OR LCD_WrF ;
23543
23544 \ CODE LCD_R                      \ -- byte       read byte from LCD
23545 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
23546 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
23547 \ COLON                           \ starts a FORTH word
23548 \     TOP_LCD 2 20_us             \ -- %0000HHHH
23549 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
23550 \ HI2LO                           \ switch from FORTH to assembler
23551 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
23552 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
23553 \     MOV @RSP+,IP                \ restore IP saved by COLON
23554 \     MOV @IP+,PC                 \
23555 \ ENDCODE
23556 \     \
23557
23558 \ CODE LCD_RdS                    \ -- status       Read Status
23559 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
23560 \     JMP LCD_R
23561 \ ENDCODE
23562 \     \
23563
23564 \ CODE LCD_RdC                    \ -- char         Read Char
23565 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
23566 \     JMP LCD_R
23567 \ ENDCODE
23568 \     \
23569
23570 \ -------------+------+------+------+------++---+---+---+---+---------+
23571 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
23572 \ -------------+------+------+------+------++---+---+---+---+---------+
23573 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
23574 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
23575 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
23576 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
23577 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
23578 \ -------------+------+------+------+------++---+---+---+---+---------+
23579
23580
23581 \ ******************************\
23582 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
23583 \ ******************************\
23584 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
23585 \ ------------------------------\
23586 \ define LPM mode for ACCEPT    \
23587 \ ------------------------------\
23588 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
23589 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
23590 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
23591 BIT.B #SW2,&SW2_IN              \ test switch S2
23592 0= IF                           \ case of switch S2 pressed
23593     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
23594     U< IF
23595         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
23596     THEN
23597 ELSE
23598     BIT.B #SW1,&SW1_IN          \ test switch S1 input
23599     0= IF                       \ case of Switch S1 pressed
23600         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
23601         U>= IF                  \
23602             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
23603         THEN                    \
23604     THEN                        \
23605 THEN                            \
23606 RETI                            \ CPU is ON, GIE is OFF
23607 ENDASM                          \
23608     \
23609
23610
23611 \ ------------------------------\
23612 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
23613 \ ******************************\
23614 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
23615 \ ******************************\
23616 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
23617 \                               \       SMclock = 8|16|24 MHz
23618 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
23619 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
23620 \                               \       SR(9)=new Toggle bit memory (ADD on)
23621 \ ------------------------------\
23622 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
23623 \ ------------------------------\
23624 \ define LPM mode for ACCEPT    \
23625 \ ------------------------------\
23626 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
23627 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
23628 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
23629 \ ------------------------------\
23630 \ RC5_FirstStartBitHalfCycle:   \
23631 \ ------------------------------\
23632 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
23633 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
23634 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
23635 MOV     #1778,X                 \ RC5_Period in us
23636 MOV     #14,W                   \ count of loop
23637 BEGIN                           \
23638 \ ------------------------------\
23639 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
23640 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
23641     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
23642 \ RC5_Compute_3/4_Period:       \                   |
23643     RRUM    #1,X                \ X=1/2 cycle       |
23644     MOV     X,Y                 \ Y=1/2             ^
23645     RRUM    #1,Y                \ Y=1/4
23646     ADD     X,Y                 \ Y=3/4
23647 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
23648     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
23649     0= UNTIL                    \
23650 \ ------------------------------\
23651 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
23652 \ ------------------------------\
23653     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
23654     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
23655     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
23656     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
23657     SUB     #1,W                \ decrement count loop
23658 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
23659 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
23660 0<> WHILE                       \ ----> out of loop ----+
23661 \ RC5_compute_7/4_Time_out:     \                       |
23662     ADD     X,Y                 \                       |   out of bound = 7/4 period 
23663 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
23664     BEGIN                       \                       |
23665         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
23666         0>= IF                  \                       |   if cycle time out of bound
23667             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
23668             RETI                \                       |   then quit to do nothing
23669         THEN                    \                       |
23670 \ ------------------------------\                       |
23671         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
23672     0<> UNTIL                   \                   |   |
23673     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
23674 REPEAT                          \ ----> loop back --+   |
23675 \ ------------------------------\                       |
23676 \ RC5_SampleEndOf:              \ <---------------------+
23677 \ ------------------------------\
23678 BIC     #$30,&TA0CTL           \ stop timer_A0
23679 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
23680 \ ******************************\
23681 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
23682 \ ******************************\
23683 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
23684 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
23685 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
23686 BIT     #BIT13,X                \ X(13) = New_RC5_command
23687 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
23688 THEN                            \
23689 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
23690 \ ******************************\
23691 \ RC5_ComputeNewRC5word         \
23692 \ ******************************\
23693 SUB     #4,PSP                  \
23694 MOV     &BASE,2(PSP)            \ save variable BASE before use
23695 MOV     TOS,0(PSP)              \ save TOS before use
23696 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
23697 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
23698 \ ******************************\
23699 \ RC5_ComputeC6bit              \
23700 \ ******************************\
23701 BIT     #$4000,IP              \ test /C6 bit in IP
23702 0= IF   BIS #$40,TOS           \ set C6 bit in S
23703 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
23704 \ ******************************\
23705 \ RC5_CommandByteIsDone         \ RC5_code --
23706 \ ******************************\
23707
23708 \ ------------------------------\
23709 \ Display IR_RC5 code           \
23710 \ ------------------------------\
23711 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
23712 \ ------------------------------\
23713 LO2HI                           \ switch from assembler to FORTH
23714     ['] LCD_CLEAR IS CR         \ redirects CR
23715     ['] LCD_WrC  IS EMIT        \ redirects EMIT
23716     $10 BASE !                 \ change BASE to hexadecimal
23717     CR ." $" 2 U.R             \ print IR_RC5 code
23718     ['] (CR) IS CR              \ restore CR
23719     ['] (EMIT) IS EMIT          \ restore EMIT
23720 HI2LO                           \ switch from FORTH to assembler
23721 \ ------------------------------\
23722 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
23723 \ ------------------------------\
23724 MOV @PSP+,&BASE                 \ restore variable BASE
23725 RETI                            \ CPU is ON, GIE is OFF
23726 ENDASM                          \
23727     \ 
23728
23729 CODE START                      \
23730 \ ------------------------------\
23731 \ TB0CTL = %0000 0010 1001 0100\$3C0
23732 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
23733 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
23734 \                      --       \ID input divider \ 10 = /4
23735 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
23736 \                            -  \TBCLR TimerB Clear
23737 \                             - \TBIE
23738 \                              -\TBIFG
23739 \ --------------------------------\\
23740 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
23741 \              --                 \CM Capture Mode
23742 \                --               \CCIS
23743 \                   -             \SCS
23744 \                    --           \CLLD
23745 \                      -          \CAP
23746 \                        ---      \OUTMOD \ 011 = set/reset
23747 \                           -     \CCIE
23748 \                             -   \CCI
23749 \                              -  \OUT
23750 \                               - \COV
23751 \                                -\CCIFG
23752 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
23753 \ TB0EX0                          \$3E0 
23754 \ ------------------------------\
23755 \ set TimerB to make 50kHz PWM  \
23756 \ ------------------------------\
23757 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
23758 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
23759 \ ------------------------------\
23760 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
23761 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
23762 \ ------------------------------\
23763     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
23764     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
23765 \ ------------------------------\
23766 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
23767 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
23768 \ ------------------------------\
23769 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
23770 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
23771 \ ------------------------------\
23772     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
23773 \ ------------------------------\
23774 \ set TimerB to generate PWM for LCD_Vo
23775 \ ------------------------------\
23776     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
23777 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
23778     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
23779 \ ------------------------------\
23780     BIS.B #LCDVo,&LCDVo_DIR     \
23781     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
23782 \ ------------------------------\
23783     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
23784     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
23785 \ ------------------------------\
23786     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
23787     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
23788 \ ------------------------------\
23789 \ WDT interval init part        \
23790 \ ------------------------------\
23791     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
23792 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
23793 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
23794     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
23795 \ ------------------------------\
23796 \ init RC5_Int                  \
23797 \ ------------------------------\
23798     BIS.B #RC5,&IR_IE           \ enable RC5_Int
23799     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
23800 \ ------------------------------\
23801 \ init interrupt vectors
23802 \ ------------------------------\
23803     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
23804     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
23805 \ ------------------------------\
23806 \ define LPM mode for ACCEPT    \
23807 \ ------------------------------\
23808 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
23809 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
23810 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
23811
23812 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
23813
23814 \ ------------------------------\
23815 \ Init LCD 2x20                 \
23816 \ ------------------------------\
23817     $03E8 20_US                \ 1-  wait 20 ms
23818     $03 TOP_LCD                \ 2- send DB5=DB4=1
23819     $CD 20_US                  \ 3- wait 4,1 ms
23820     $03 TOP_LCD                \ 4- send again DB5=DB4=1
23821     $5 20_US                   \ 5- wait 0,1 ms
23822     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
23823     $2 20_US                   \    wait 40 us = LCD cycle
23824     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
23825     $2 20_US                   \    wait 40 us = LCD cycle
23826     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
23827     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
23828     LCD_Clear                   \ 10- "LCD_Clear"
23829     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
23830     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
23831     LCD_Clear                   \ 10- "LCD_Clear"
23832     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
23833     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
23834     CR ." I love you"   
23835     ['] (CR) IS CR              \ ' (CR) is CR
23836     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
23837     CR
23838     ."    RC5toLCD is running. Type STOP to quit"
23839 \    NOECHO                      \ uncomment to run this app without terminal connexion
23840     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
23841     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
23842 ;
23843     \
23844
23845 : STOP                  \ stops multitasking, must to be used before downloading app
23846     ['] (WARM) IS WARM  \ remove START app from FORTH init process
23847     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
23848 ;
23849     \
23850
23851
23852 RST_STATE   ;
23853
23854
23855 CODE MAX    \    n1 n2 -- n3       signed maximum
23856             CMP     @PSP,TOS    \ n2-n1
23857             S<      ?GOTO FW1   \ n2<n1
23858 BW1         ADD     #2,PSP
23859             MOV     @IP+,PC
23860 ENDCODE
23861     \
23862
23863 CODE MIN    \    n1 n2 -- n3       signed minimum
23864             CMP     @PSP,TOS     \ n2-n1
23865             S<      ?GOTO BW1    \ n2<n1
23866 FW1         MOV     @PSP+,TOS
23867             MOV     @IP+,PC
23868 ENDCODE
23869     \
23870
23871 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
23872   >R  <# 0 # #S #>  
23873   R> OVER - 0 MAX SPACES TYPE
23874 ;
23875     \
23876
23877 CODE 20_US                      \ n --      n * 20 us
23878 BEGIN                           \ 3 cycles loop + 6~  
23879 \    MOV     #5,W                \ 3 MCLK = 1 MHz
23880 \    MOV     #23,W               \ 3 MCLK = 4 MHz
23881     MOV     #51,W               \ 3 MCLK = 8 MHz
23882 \    MOV     #104,W              \ 3 MCLK = 16 MHz
23883 \    MOV     #158,W              \ 3 MCLK = 24 MHz
23884     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
23885         SUB #1,W                \ 1
23886     0= UNTIL                    \ 2
23887     SUB     #1,TOS              \ 1
23888 0= UNTIL                        \ 2
23889     MOV     @PSP+,TOS           \ 2
23890     MOV     @IP+,PC             \ 4
23891 ENDCODE
23892     \
23893
23894 CODE TOP_LCD                    \ LCD Sample
23895 \                               \ if write : %xxxxWWWW --
23896 \                               \ if read  : -- %0000RRRR
23897     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
23898     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
23899 0= IF                           \ write LCD bits pattern
23900     AND.B #LCD_DB,TOS           \ 
23901     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
23902     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
23903     MOV @PSP+,TOS               \
23904     MOV @IP+,PC
23905 THEN                            \ read LCD bits pattern
23906     SUB #2,PSP
23907     MOV TOS,0(PSP)
23908     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
23909     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
23910     AND.B #LCD_DB,TOS           \
23911     MOV @IP+,PC
23912 ENDCODE
23913     \
23914
23915 CODE LCD_W                      \ byte --       write byte to LCD 
23916     SUB #2,PSP                  \
23917     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
23918     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
23919     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
23920     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
23921 COLON                           \ high level word starts here 
23922     TOP_LCD 2 20_US             \ write high nibble first
23923     TOP_LCD 2 20_US 
23924 ;
23925     \
23926
23927 CODE LCD_WrC                    \ char --         Write Char
23928     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
23929     JMP LCD_W 
23930 ENDCODE
23931     \
23932
23933 CODE LCD_WrF                    \ func --         Write Fonction
23934     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
23935     JMP LCD_W 
23936 ENDCODE
23937     \
23938
23939 : LCD_Clear 
23940     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
23941 ;
23942     \
23943
23944 : LCD_Home 
23945     $02 LCD_WrF 100 20_us 
23946 ;
23947     \
23948
23949 \ : LCD_Entry_set       $04 OR LCD_WrF ;
23950
23951 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
23952
23953 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
23954
23955 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
23956
23957 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
23958
23959 \ : LCD_Goto            $80 OR LCD_WrF ;
23960
23961 \ CODE LCD_R                      \ -- byte       read byte from LCD
23962 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
23963 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
23964 \ COLON                           \ starts a FORTH word
23965 \     TOP_LCD 2 20_us             \ -- %0000HHHH
23966 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
23967 \ HI2LO                           \ switch from FORTH to assembler
23968 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
23969 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
23970 \     MOV @RSP+,IP                \ restore IP saved by COLON
23971 \     MOV @IP+,PC                 \
23972 \ ENDCODE
23973 \     \
23974
23975 \ CODE LCD_RdS                    \ -- status       Read Status
23976 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
23977 \     JMP LCD_R
23978 \ ENDCODE
23979 \     \
23980
23981 \ CODE LCD_RdC                    \ -- char         Read Char
23982 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
23983 \     JMP LCD_R
23984 \ ENDCODE
23985 \     \
23986
23987 \ -------------+------+------+------+------++---+---+---+---+---------+
23988 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
23989 \ -------------+------+------+------+------++---+---+---+---+---------+
23990 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
23991 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
23992 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
23993 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
23994 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
23995 \ -------------+------+------+------+------++---+---+---+---+---------+
23996
23997
23998 \ ******************************\
23999 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
24000 \ ******************************\
24001 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
24002 \ ------------------------------\
24003 \ define LPM mode for ACCEPT    \
24004 \ ------------------------------\
24005 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
24006 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
24007 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
24008 BIT.B #SW2,&SW2_IN              \ test switch S2
24009 0= IF                           \ case of switch S2 pressed
24010     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
24011     U< IF
24012         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
24013     THEN
24014 ELSE
24015     BIT.B #SW1,&SW1_IN          \ test switch S1 input
24016     0= IF                       \ case of Switch S1 pressed
24017         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
24018         U>= IF                  \
24019             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
24020         THEN                    \
24021     THEN                        \
24022 THEN                            \
24023 RETI                            \ CPU is ON, GIE is OFF
24024 ENDASM                          \
24025     \
24026
24027
24028 \ ------------------------------\
24029 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
24030 \ ******************************\
24031 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
24032 \ ******************************\
24033 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
24034 \                               \       SMclock = 8|16|24 MHz
24035 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
24036 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
24037 \                               \       SR(9)=new Toggle bit memory (ADD on)
24038 \ ------------------------------\
24039 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
24040 \ ------------------------------\
24041 \ define LPM mode for ACCEPT    \
24042 \ ------------------------------\
24043 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
24044 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
24045 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
24046 \ ------------------------------\
24047 \ RC5_FirstStartBitHalfCycle:   \
24048 \ ------------------------------\
24049 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
24050 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
24051 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
24052 MOV     #1778,X                 \ RC5_Period in us
24053 MOV     #14,W                   \ count of loop
24054 BEGIN                           \
24055 \ ------------------------------\
24056 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
24057 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
24058     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
24059 \ RC5_Compute_3/4_Period:       \                   |
24060     RRUM    #1,X                \ X=1/2 cycle       |
24061     MOV     X,Y                 \ Y=1/2             ^
24062     RRUM    #1,Y                \ Y=1/4
24063     ADD     X,Y                 \ Y=3/4
24064 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
24065     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
24066     0= UNTIL                    \
24067 \ ------------------------------\
24068 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
24069 \ ------------------------------\
24070     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
24071     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
24072     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
24073     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
24074     SUB     #1,W                \ decrement count loop
24075 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
24076 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
24077 0<> WHILE                       \ ----> out of loop ----+
24078 \ RC5_compute_7/4_Time_out:     \                       |
24079     ADD     X,Y                 \                       |   out of bound = 7/4 period 
24080 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
24081     BEGIN                       \                       |
24082         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
24083         0>= IF                  \                       |   if cycle time out of bound
24084             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
24085             RETI                \                       |   then quit to do nothing
24086         THEN                    \                       |
24087 \ ------------------------------\                       |
24088         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
24089     0<> UNTIL                   \                   |   |
24090     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
24091 REPEAT                          \ ----> loop back --+   |
24092 \ ------------------------------\                       |
24093 \ RC5_SampleEndOf:              \ <---------------------+
24094 \ ------------------------------\
24095 BIC     #$30,&TA0CTL           \ stop timer_A0
24096 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
24097 \ ******************************\
24098 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
24099 \ ******************************\
24100 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
24101 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
24102 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
24103 BIT     #BIT13,X                \ X(13) = New_RC5_command
24104 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
24105 THEN                            \
24106 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
24107 \ ******************************\
24108 \ RC5_ComputeNewRC5word         \
24109 \ ******************************\
24110 SUB     #4,PSP                  \
24111 MOV     &BASE,2(PSP)            \ save variable BASE before use
24112 MOV     TOS,0(PSP)              \ save TOS before use
24113 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
24114 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
24115 \ ******************************\
24116 \ RC5_ComputeC6bit              \
24117 \ ******************************\
24118 BIT     #$4000,IP              \ test /C6 bit in IP
24119 0= IF   BIS #$40,TOS           \ set C6 bit in S
24120 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
24121 \ ******************************\
24122 \ RC5_CommandByteIsDone         \ RC5_code --
24123 \ ******************************\
24124
24125 \ ------------------------------\
24126 \ Display IR_RC5 code           \
24127 \ ------------------------------\
24128 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
24129 \ ------------------------------\
24130 LO2HI                           \ switch from assembler to FORTH
24131     ['] LCD_CLEAR IS CR         \ redirects CR
24132     ['] LCD_WrC  IS EMIT        \ redirects EMIT
24133     $10 BASE !                 \ change BASE to hexadecimal
24134     CR ." $" 2 U.R             \ print IR_RC5 code
24135     ['] (CR) IS CR              \ restore CR
24136     ['] (EMIT) IS EMIT          \ restore EMIT
24137 HI2LO                           \ switch from FORTH to assembler
24138 \ ------------------------------\
24139 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
24140 \ ------------------------------\
24141 MOV @PSP+,&BASE                 \ restore variable BASE
24142 RETI                            \ CPU is ON, GIE is OFF
24143 ENDASM                          \
24144     \ 
24145
24146 CODE START                      \
24147 \ ------------------------------\
24148 \ TB0CTL = %0000 0010 1001 0100\$3C0
24149 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
24150 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
24151 \                      --       \ID input divider \ 10 = /4
24152 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
24153 \                            -  \TBCLR TimerB Clear
24154 \                             - \TBIE
24155 \                              -\TBIFG
24156 \ --------------------------------\\
24157 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
24158 \              --                 \CM Capture Mode
24159 \                --               \CCIS
24160 \                   -             \SCS
24161 \                    --           \CLLD
24162 \                      -          \CAP
24163 \                        ---      \OUTMOD \ 011 = set/reset
24164 \                           -     \CCIE
24165 \                             -   \CCI
24166 \                              -  \OUT
24167 \                               - \COV
24168 \                                -\CCIFG
24169 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
24170 \ TB0EX0                          \$3E0 
24171 \ ------------------------------\
24172 \ set TimerB to make 50kHz PWM  \
24173 \ ------------------------------\
24174 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
24175 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
24176 \ ------------------------------\
24177 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
24178 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
24179 \ ------------------------------\
24180     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
24181     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
24182 \ ------------------------------\
24183 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
24184 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
24185 \ ------------------------------\
24186 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
24187 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
24188 \ ------------------------------\
24189     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
24190 \ ------------------------------\
24191 \ set TimerB to generate PWM for LCD_Vo
24192 \ ------------------------------\
24193     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
24194 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
24195     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
24196 \ ------------------------------\
24197     BIS.B #LCDVo,&LCDVo_DIR     \
24198     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
24199 \ ------------------------------\
24200     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
24201     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
24202 \ ------------------------------\
24203     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
24204     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
24205 \ ------------------------------\
24206 \ WDT interval init part        \
24207 \ ------------------------------\
24208     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
24209 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
24210 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
24211     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
24212 \ ------------------------------\
24213 \ init RC5_Int                  \
24214 \ ------------------------------\
24215     BIS.B #RC5,&IR_IE           \ enable RC5_Int
24216     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
24217 \ ------------------------------\
24218 \ init interrupt vectors
24219 \ ------------------------------\
24220     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
24221     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
24222 \ ------------------------------\
24223 \ define LPM mode for ACCEPT    \
24224 \ ------------------------------\
24225 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
24226 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
24227 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
24228
24229 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
24230
24231 \ ------------------------------\
24232 \ Init LCD 2x20                 \
24233 \ ------------------------------\
24234     $03E8 20_US                \ 1-  wait 20 ms
24235     $03 TOP_LCD                \ 2- send DB5=DB4=1
24236     $CD 20_US                  \ 3- wait 4,1 ms
24237     $03 TOP_LCD                \ 4- send again DB5=DB4=1
24238     $5 20_US                   \ 5- wait 0,1 ms
24239     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
24240     $2 20_US                   \    wait 40 us = LCD cycle
24241     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
24242     $2 20_US                   \    wait 40 us = LCD cycle
24243     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
24244     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
24245     LCD_Clear                   \ 10- "LCD_Clear"
24246     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
24247     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
24248     LCD_Clear                   \ 10- "LCD_Clear"
24249     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
24250     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
24251     CR ." I love you"   
24252     ['] (CR) IS CR              \ ' (CR) is CR
24253     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
24254     CR
24255     ."    RC5toLCD is running. Type STOP to quit"
24256 \    NOECHO                      \ uncomment to run this app without terminal connexion
24257     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
24258     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
24259 ;
24260     \
24261
24262 : STOP                  \ stops multitasking, must to be used before downloading app
24263     ['] (WARM) IS WARM  \ remove START app from FORTH init process
24264     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
24265 ;
24266     \
24267
24268
24269 RST_STATE   ;
24270
24271
24272 CODE MAX    \    n1 n2 -- n3       signed maximum
24273             CMP     @PSP,TOS    \ n2-n1
24274             S<      ?GOTO FW1   \ n2<n1
24275 BW1         ADD     #2,PSP
24276             MOV     @IP+,PC
24277 ENDCODE
24278     \
24279
24280 CODE MIN    \    n1 n2 -- n3       signed minimum
24281             CMP     @PSP,TOS     \ n2-n1
24282             S<      ?GOTO BW1    \ n2<n1
24283 FW1         MOV     @PSP+,TOS
24284             MOV     @IP+,PC
24285 ENDCODE
24286     \
24287
24288 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
24289   >R  <# 0 # #S #>  
24290   R> OVER - 0 MAX SPACES TYPE
24291 ;
24292     \
24293
24294 CODE 20_US                      \ n --      n * 20 us
24295 BEGIN                           \ 3 cycles loop + 6~  
24296 \    MOV     #5,W                \ 3 MCLK = 1 MHz
24297 \    MOV     #23,W               \ 3 MCLK = 4 MHz
24298     MOV     #51,W               \ 3 MCLK = 8 MHz
24299 \    MOV     #104,W              \ 3 MCLK = 16 MHz
24300 \    MOV     #158,W              \ 3 MCLK = 24 MHz
24301     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
24302         SUB #1,W                \ 1
24303     0= UNTIL                    \ 2
24304     SUB     #1,TOS              \ 1
24305 0= UNTIL                        \ 2
24306     MOV     @PSP+,TOS           \ 2
24307     MOV     @IP+,PC             \ 4
24308 ENDCODE
24309     \
24310
24311 CODE TOP_LCD                    \ LCD Sample
24312 \                               \ if write : %xxxxWWWW --
24313 \                               \ if read  : -- %0000RRRR
24314     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
24315     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
24316 0= IF                           \ write LCD bits pattern
24317     AND.B #LCD_DB,TOS           \ 
24318     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
24319     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
24320     MOV @PSP+,TOS               \
24321     MOV @IP+,PC
24322 THEN                            \ read LCD bits pattern
24323     SUB #2,PSP
24324     MOV TOS,0(PSP)
24325     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
24326     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
24327     AND.B #LCD_DB,TOS           \
24328     MOV @IP+,PC
24329 ENDCODE
24330     \
24331
24332 CODE LCD_W                      \ byte --       write byte to LCD 
24333     SUB #2,PSP                  \
24334     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
24335     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
24336     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
24337     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
24338 COLON                           \ high level word starts here 
24339     TOP_LCD 2 20_US             \ write high nibble first
24340     TOP_LCD 2 20_US 
24341 ;
24342     \
24343
24344 CODE LCD_WrC                    \ char --         Write Char
24345     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
24346     JMP LCD_W 
24347 ENDCODE
24348     \
24349
24350 CODE LCD_WrF                    \ func --         Write Fonction
24351     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
24352     JMP LCD_W 
24353 ENDCODE
24354     \
24355
24356 : LCD_Clear 
24357     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
24358 ;
24359     \
24360
24361 : LCD_Home 
24362     $02 LCD_WrF 100 20_us 
24363 ;
24364     \
24365
24366 \ : LCD_Entry_set       $04 OR LCD_WrF ;
24367
24368 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
24369
24370 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
24371
24372 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
24373
24374 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
24375
24376 \ : LCD_Goto            $80 OR LCD_WrF ;
24377
24378 \ CODE LCD_R                      \ -- byte       read byte from LCD
24379 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
24380 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
24381 \ COLON                           \ starts a FORTH word
24382 \     TOP_LCD 2 20_us             \ -- %0000HHHH
24383 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
24384 \ HI2LO                           \ switch from FORTH to assembler
24385 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
24386 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
24387 \     MOV @RSP+,IP                \ restore IP saved by COLON
24388 \     MOV @IP+,PC                 \
24389 \ ENDCODE
24390 \     \
24391
24392 \ CODE LCD_RdS                    \ -- status       Read Status
24393 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
24394 \     JMP LCD_R
24395 \ ENDCODE
24396 \     \
24397
24398 \ CODE LCD_RdC                    \ -- char         Read Char
24399 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
24400 \     JMP LCD_R
24401 \ ENDCODE
24402 \     \
24403
24404 \ -------------+------+------+------+------++---+---+---+---+---------+
24405 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
24406 \ -------------+------+------+------+------++---+---+---+---+---------+
24407 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
24408 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
24409 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
24410 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
24411 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
24412 \ -------------+------+------+------+------++---+---+---+---+---------+
24413
24414
24415 \ ******************************\
24416 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
24417 \ ******************************\
24418 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
24419 \ ------------------------------\
24420 \ define LPM mode for ACCEPT    \
24421 \ ------------------------------\
24422 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
24423 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
24424 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
24425 BIT.B #SW2,&SW2_IN              \ test switch S2
24426 0= IF                           \ case of switch S2 pressed
24427     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
24428     U< IF
24429         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
24430     THEN
24431 ELSE
24432     BIT.B #SW1,&SW1_IN          \ test switch S1 input
24433     0= IF                       \ case of Switch S1 pressed
24434         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
24435         U>= IF                  \
24436             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
24437         THEN                    \
24438     THEN                        \
24439 THEN                            \
24440 RETI                            \ CPU is ON, GIE is OFF
24441 ENDASM                          \
24442     \
24443
24444
24445 \ ------------------------------\
24446 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
24447 \ ******************************\
24448 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
24449 \ ******************************\
24450 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
24451 \                               \       SMclock = 8|16|24 MHz
24452 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
24453 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
24454 \                               \       SR(9)=new Toggle bit memory (ADD on)
24455 \ ------------------------------\
24456 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
24457 \ ------------------------------\
24458 \ define LPM mode for ACCEPT    \
24459 \ ------------------------------\
24460 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
24461 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
24462 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
24463 \ ------------------------------\
24464 \ RC5_FirstStartBitHalfCycle:   \
24465 \ ------------------------------\
24466 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
24467 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
24468 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
24469 MOV     #1778,X                 \ RC5_Period in us
24470 MOV     #14,W                   \ count of loop
24471 BEGIN                           \
24472 \ ------------------------------\
24473 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
24474 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
24475     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
24476 \ RC5_Compute_3/4_Period:       \                   |
24477     RRUM    #1,X                \ X=1/2 cycle       |
24478     MOV     X,Y                 \ Y=1/2             ^
24479     RRUM    #1,Y                \ Y=1/4
24480     ADD     X,Y                 \ Y=3/4
24481 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
24482     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
24483     0= UNTIL                    \
24484 \ ------------------------------\
24485 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
24486 \ ------------------------------\
24487     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
24488     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
24489     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
24490     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
24491     SUB     #1,W                \ decrement count loop
24492 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
24493 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
24494 0<> WHILE                       \ ----> out of loop ----+
24495 \ RC5_compute_7/4_Time_out:     \                       |
24496     ADD     X,Y                 \                       |   out of bound = 7/4 period 
24497 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
24498     BEGIN                       \                       |
24499         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
24500         0>= IF                  \                       |   if cycle time out of bound
24501             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
24502             RETI                \                       |   then quit to do nothing
24503         THEN                    \                       |
24504 \ ------------------------------\                       |
24505         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
24506     0<> UNTIL                   \                   |   |
24507     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
24508 REPEAT                          \ ----> loop back --+   |
24509 \ ------------------------------\                       |
24510 \ RC5_SampleEndOf:              \ <---------------------+
24511 \ ------------------------------\
24512 BIC     #$30,&TA0CTL           \ stop timer_A0
24513 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
24514 \ ******************************\
24515 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
24516 \ ******************************\
24517 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
24518 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
24519 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
24520 BIT     #BIT13,X                \ X(13) = New_RC5_command
24521 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
24522 THEN                            \
24523 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
24524 \ ******************************\
24525 \ RC5_ComputeNewRC5word         \
24526 \ ******************************\
24527 SUB     #4,PSP                  \
24528 MOV     &BASE,2(PSP)            \ save variable BASE before use
24529 MOV     TOS,0(PSP)              \ save TOS before use
24530 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
24531 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
24532 \ ******************************\
24533 \ RC5_ComputeC6bit              \
24534 \ ******************************\
24535 BIT     #$4000,IP              \ test /C6 bit in IP
24536 0= IF   BIS #$40,TOS           \ set C6 bit in S
24537 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
24538 \ ******************************\
24539 \ RC5_CommandByteIsDone         \ RC5_code --
24540 \ ******************************\
24541
24542 \ ------------------------------\
24543 \ Display IR_RC5 code           \
24544 \ ------------------------------\
24545 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
24546 \ ------------------------------\
24547 LO2HI                           \ switch from assembler to FORTH
24548     ['] LCD_CLEAR IS CR         \ redirects CR
24549     ['] LCD_WrC  IS EMIT        \ redirects EMIT
24550     $10 BASE !                 \ change BASE to hexadecimal
24551     CR ." $" 2 U.R             \ print IR_RC5 code
24552     ['] (CR) IS CR              \ restore CR
24553     ['] (EMIT) IS EMIT          \ restore EMIT
24554 HI2LO                           \ switch from FORTH to assembler
24555 \ ------------------------------\
24556 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
24557 \ ------------------------------\
24558 MOV @PSP+,&BASE                 \ restore variable BASE
24559 RETI                            \ CPU is ON, GIE is OFF
24560 ENDASM                          \
24561     \ 
24562
24563 CODE START                      \
24564 \ ------------------------------\
24565 \ TB0CTL = %0000 0010 1001 0100\$3C0
24566 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
24567 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
24568 \                      --       \ID input divider \ 10 = /4
24569 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
24570 \                            -  \TBCLR TimerB Clear
24571 \                             - \TBIE
24572 \                              -\TBIFG
24573 \ --------------------------------\\
24574 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
24575 \              --                 \CM Capture Mode
24576 \                --               \CCIS
24577 \                   -             \SCS
24578 \                    --           \CLLD
24579 \                      -          \CAP
24580 \                        ---      \OUTMOD \ 011 = set/reset
24581 \                           -     \CCIE
24582 \                             -   \CCI
24583 \                              -  \OUT
24584 \                               - \COV
24585 \                                -\CCIFG
24586 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
24587 \ TB0EX0                          \$3E0 
24588 \ ------------------------------\
24589 \ set TimerB to make 50kHz PWM  \
24590 \ ------------------------------\
24591 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
24592 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
24593 \ ------------------------------\
24594 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
24595 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
24596 \ ------------------------------\
24597     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
24598     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
24599 \ ------------------------------\
24600 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
24601 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
24602 \ ------------------------------\
24603 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
24604 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
24605 \ ------------------------------\
24606     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
24607 \ ------------------------------\
24608 \ set TimerB to generate PWM for LCD_Vo
24609 \ ------------------------------\
24610     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
24611 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
24612     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
24613 \ ------------------------------\
24614     BIS.B #LCDVo,&LCDVo_DIR     \
24615     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
24616 \ ------------------------------\
24617     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
24618     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
24619 \ ------------------------------\
24620     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
24621     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
24622 \ ------------------------------\
24623 \ WDT interval init part        \
24624 \ ------------------------------\
24625     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
24626 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
24627 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
24628     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
24629 \ ------------------------------\
24630 \ init RC5_Int                  \
24631 \ ------------------------------\
24632     BIS.B #RC5,&IR_IE           \ enable RC5_Int
24633     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
24634 \ ------------------------------\
24635 \ init interrupt vectors
24636 \ ------------------------------\
24637     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
24638     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
24639 \ ------------------------------\
24640 \ define LPM mode for ACCEPT    \
24641 \ ------------------------------\
24642 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
24643 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
24644 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
24645
24646 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
24647
24648 \ ------------------------------\
24649 \ Init LCD 2x20                 \
24650 \ ------------------------------\
24651     $03E8 20_US                \ 1-  wait 20 ms
24652     $03 TOP_LCD                \ 2- send DB5=DB4=1
24653     $CD 20_US                  \ 3- wait 4,1 ms
24654     $03 TOP_LCD                \ 4- send again DB5=DB4=1
24655     $5 20_US                   \ 5- wait 0,1 ms
24656     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
24657     $2 20_US                   \    wait 40 us = LCD cycle
24658     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
24659     $2 20_US                   \    wait 40 us = LCD cycle
24660     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
24661     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
24662     LCD_Clear                   \ 10- "LCD_Clear"
24663     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
24664     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
24665     LCD_Clear                   \ 10- "LCD_Clear"
24666     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
24667     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
24668     CR ." I love you"   
24669     ['] (CR) IS CR              \ ' (CR) is CR
24670     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
24671     CR
24672     ."    RC5toLCD is running. Type STOP to quit"
24673 \    NOECHO                      \ uncomment to run this app without terminal connexion
24674     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
24675     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
24676 ;
24677     \
24678
24679 : STOP                  \ stops multitasking, must to be used before downloading app
24680     ['] (WARM) IS WARM  \ remove START app from FORTH init process
24681     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
24682 ;
24683     \
24684
24685
24686 RST_STATE   ;
24687
24688
24689 CODE MAX    \    n1 n2 -- n3       signed maximum
24690             CMP     @PSP,TOS    \ n2-n1
24691             S<      ?GOTO FW1   \ n2<n1
24692 BW1         ADD     #2,PSP
24693             MOV     @IP+,PC
24694 ENDCODE
24695     \
24696
24697 CODE MIN    \    n1 n2 -- n3       signed minimum
24698             CMP     @PSP,TOS     \ n2-n1
24699             S<      ?GOTO BW1    \ n2<n1
24700 FW1         MOV     @PSP+,TOS
24701             MOV     @IP+,PC
24702 ENDCODE
24703     \
24704
24705 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
24706   >R  <# 0 # #S #>  
24707   R> OVER - 0 MAX SPACES TYPE
24708 ;
24709     \
24710
24711 CODE 20_US                      \ n --      n * 20 us
24712 BEGIN                           \ 3 cycles loop + 6~  
24713 \    MOV     #5,W                \ 3 MCLK = 1 MHz
24714 \    MOV     #23,W               \ 3 MCLK = 4 MHz
24715     MOV     #51,W               \ 3 MCLK = 8 MHz
24716 \    MOV     #104,W              \ 3 MCLK = 16 MHz
24717 \    MOV     #158,W              \ 3 MCLK = 24 MHz
24718     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
24719         SUB #1,W                \ 1
24720     0= UNTIL                    \ 2
24721     SUB     #1,TOS              \ 1
24722 0= UNTIL                        \ 2
24723     MOV     @PSP+,TOS           \ 2
24724     MOV     @IP+,PC             \ 4
24725 ENDCODE
24726     \
24727
24728 CODE TOP_LCD                    \ LCD Sample
24729 \                               \ if write : %xxxxWWWW --
24730 \                               \ if read  : -- %0000RRRR
24731     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
24732     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
24733 0= IF                           \ write LCD bits pattern
24734     AND.B #LCD_DB,TOS           \ 
24735     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
24736     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
24737     MOV @PSP+,TOS               \
24738     MOV @IP+,PC
24739 THEN                            \ read LCD bits pattern
24740     SUB #2,PSP
24741     MOV TOS,0(PSP)
24742     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
24743     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
24744     AND.B #LCD_DB,TOS           \
24745     MOV @IP+,PC
24746 ENDCODE
24747     \
24748
24749 CODE LCD_W                      \ byte --       write byte to LCD 
24750     SUB #2,PSP                  \
24751     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
24752     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
24753     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
24754     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
24755 COLON                           \ high level word starts here 
24756     TOP_LCD 2 20_US             \ write high nibble first
24757     TOP_LCD 2 20_US 
24758 ;
24759     \
24760
24761 CODE LCD_WrC                    \ char --         Write Char
24762     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
24763     JMP LCD_W 
24764 ENDCODE
24765     \
24766
24767 CODE LCD_WrF                    \ func --         Write Fonction
24768     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
24769     JMP LCD_W 
24770 ENDCODE
24771     \
24772
24773 : LCD_Clear 
24774     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
24775 ;
24776     \
24777
24778 : LCD_Home 
24779     $02 LCD_WrF 100 20_us 
24780 ;
24781     \
24782
24783 \ : LCD_Entry_set       $04 OR LCD_WrF ;
24784
24785 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
24786
24787 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
24788
24789 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
24790
24791 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
24792
24793 \ : LCD_Goto            $80 OR LCD_WrF ;
24794
24795 \ CODE LCD_R                      \ -- byte       read byte from LCD
24796 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
24797 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
24798 \ COLON                           \ starts a FORTH word
24799 \     TOP_LCD 2 20_us             \ -- %0000HHHH
24800 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
24801 \ HI2LO                           \ switch from FORTH to assembler
24802 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
24803 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
24804 \     MOV @RSP+,IP                \ restore IP saved by COLON
24805 \     MOV @IP+,PC                 \
24806 \ ENDCODE
24807 \     \
24808
24809 \ CODE LCD_RdS                    \ -- status       Read Status
24810 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
24811 \     JMP LCD_R
24812 \ ENDCODE
24813 \     \
24814
24815 \ CODE LCD_RdC                    \ -- char         Read Char
24816 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
24817 \     JMP LCD_R
24818 \ ENDCODE
24819 \     \
24820
24821 \ -------------+------+------+------+------++---+---+---+---+---------+
24822 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
24823 \ -------------+------+------+------+------++---+---+---+---+---------+
24824 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
24825 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
24826 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
24827 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
24828 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
24829 \ -------------+------+------+------+------++---+---+---+---+---------+
24830
24831
24832 \ ******************************\
24833 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
24834 \ ******************************\
24835 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
24836 \ ------------------------------\
24837 \ define LPM mode for ACCEPT    \
24838 \ ------------------------------\
24839 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
24840 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
24841 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
24842 BIT.B #SW2,&SW2_IN              \ test switch S2
24843 0= IF                           \ case of switch S2 pressed
24844     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
24845     U< IF
24846         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
24847     THEN
24848 ELSE
24849     BIT.B #SW1,&SW1_IN          \ test switch S1 input
24850     0= IF                       \ case of Switch S1 pressed
24851         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
24852         U>= IF                  \
24853             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
24854         THEN                    \
24855     THEN                        \
24856 THEN                            \
24857 RETI                            \ CPU is ON, GIE is OFF
24858 ENDASM                          \
24859     \
24860
24861
24862 \ ------------------------------\
24863 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
24864 \ ******************************\
24865 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
24866 \ ******************************\
24867 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
24868 \                               \       SMclock = 8|16|24 MHz
24869 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
24870 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
24871 \                               \       SR(9)=new Toggle bit memory (ADD on)
24872 \ ------------------------------\
24873 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
24874 \ ------------------------------\
24875 \ define LPM mode for ACCEPT    \
24876 \ ------------------------------\
24877 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
24878 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
24879 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
24880 \ ------------------------------\
24881 \ RC5_FirstStartBitHalfCycle:   \
24882 \ ------------------------------\
24883 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
24884 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
24885 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
24886 MOV     #1778,X                 \ RC5_Period in us
24887 MOV     #14,W                   \ count of loop
24888 BEGIN                           \
24889 \ ------------------------------\
24890 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
24891 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
24892     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
24893 \ RC5_Compute_3/4_Period:       \                   |
24894     RRUM    #1,X                \ X=1/2 cycle       |
24895     MOV     X,Y                 \ Y=1/2             ^
24896     RRUM    #1,Y                \ Y=1/4
24897     ADD     X,Y                 \ Y=3/4
24898 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
24899     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
24900     0= UNTIL                    \
24901 \ ------------------------------\
24902 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
24903 \ ------------------------------\
24904     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
24905     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
24906     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
24907     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
24908     SUB     #1,W                \ decrement count loop
24909 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
24910 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
24911 0<> WHILE                       \ ----> out of loop ----+
24912 \ RC5_compute_7/4_Time_out:     \                       |
24913     ADD     X,Y                 \                       |   out of bound = 7/4 period 
24914 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
24915     BEGIN                       \                       |
24916         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
24917         0>= IF                  \                       |   if cycle time out of bound
24918             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
24919             RETI                \                       |   then quit to do nothing
24920         THEN                    \                       |
24921 \ ------------------------------\                       |
24922         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
24923     0<> UNTIL                   \                   |   |
24924     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
24925 REPEAT                          \ ----> loop back --+   |
24926 \ ------------------------------\                       |
24927 \ RC5_SampleEndOf:              \ <---------------------+
24928 \ ------------------------------\
24929 BIC     #$30,&TA0CTL           \ stop timer_A0
24930 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
24931 \ ******************************\
24932 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
24933 \ ******************************\
24934 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
24935 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
24936 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
24937 BIT     #BIT13,X                \ X(13) = New_RC5_command
24938 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
24939 THEN                            \
24940 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
24941 \ ******************************\
24942 \ RC5_ComputeNewRC5word         \
24943 \ ******************************\
24944 SUB     #4,PSP                  \
24945 MOV     &BASE,2(PSP)            \ save variable BASE before use
24946 MOV     TOS,0(PSP)              \ save TOS before use
24947 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
24948 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
24949 \ ******************************\
24950 \ RC5_ComputeC6bit              \
24951 \ ******************************\
24952 BIT     #$4000,IP              \ test /C6 bit in IP
24953 0= IF   BIS #$40,TOS           \ set C6 bit in S
24954 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
24955 \ ******************************\
24956 \ RC5_CommandByteIsDone         \ RC5_code --
24957 \ ******************************\
24958
24959 \ ------------------------------\
24960 \ Display IR_RC5 code           \
24961 \ ------------------------------\
24962 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
24963 \ ------------------------------\
24964 LO2HI                           \ switch from assembler to FORTH
24965     ['] LCD_CLEAR IS CR         \ redirects CR
24966     ['] LCD_WrC  IS EMIT        \ redirects EMIT
24967     $10 BASE !                 \ change BASE to hexadecimal
24968     CR ." $" 2 U.R             \ print IR_RC5 code
24969     ['] (CR) IS CR              \ restore CR
24970     ['] (EMIT) IS EMIT          \ restore EMIT
24971 HI2LO                           \ switch from FORTH to assembler
24972 \ ------------------------------\
24973 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
24974 \ ------------------------------\
24975 MOV @PSP+,&BASE                 \ restore variable BASE
24976 RETI                            \ CPU is ON, GIE is OFF
24977 ENDASM                          \
24978     \ 
24979
24980 CODE START                      \
24981 \ ------------------------------\
24982 \ TB0CTL = %0000 0010 1001 0100\$3C0
24983 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
24984 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
24985 \                      --       \ID input divider \ 10 = /4
24986 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
24987 \                            -  \TBCLR TimerB Clear
24988 \                             - \TBIE
24989 \                              -\TBIFG
24990 \ --------------------------------\\
24991 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
24992 \              --                 \CM Capture Mode
24993 \                --               \CCIS
24994 \                   -             \SCS
24995 \                    --           \CLLD
24996 \                      -          \CAP
24997 \                        ---      \OUTMOD \ 011 = set/reset
24998 \                           -     \CCIE
24999 \                             -   \CCI
25000 \                              -  \OUT
25001 \                               - \COV
25002 \                                -\CCIFG
25003 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
25004 \ TB0EX0                          \$3E0 
25005 \ ------------------------------\
25006 \ set TimerB to make 50kHz PWM  \
25007 \ ------------------------------\
25008 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
25009 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
25010 \ ------------------------------\
25011 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
25012 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
25013 \ ------------------------------\
25014     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
25015     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
25016 \ ------------------------------\
25017 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
25018 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
25019 \ ------------------------------\
25020 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
25021 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
25022 \ ------------------------------\
25023     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
25024 \ ------------------------------\
25025 \ set TimerB to generate PWM for LCD_Vo
25026 \ ------------------------------\
25027     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
25028 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
25029     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
25030 \ ------------------------------\
25031     BIS.B #LCDVo,&LCDVo_DIR     \
25032     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
25033 \ ------------------------------\
25034     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
25035     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
25036 \ ------------------------------\
25037     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
25038     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
25039 \ ------------------------------\
25040 \ WDT interval init part        \
25041 \ ------------------------------\
25042     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
25043 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
25044 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
25045     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
25046 \ ------------------------------\
25047 \ init RC5_Int                  \
25048 \ ------------------------------\
25049     BIS.B #RC5,&IR_IE           \ enable RC5_Int
25050     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
25051 \ ------------------------------\
25052 \ init interrupt vectors
25053 \ ------------------------------\
25054     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
25055     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
25056 \ ------------------------------\
25057 \ define LPM mode for ACCEPT    \
25058 \ ------------------------------\
25059 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
25060 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
25061 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
25062
25063 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
25064
25065 \ ------------------------------\
25066 \ Init LCD 2x20                 \
25067 \ ------------------------------\
25068     $03E8 20_US                \ 1-  wait 20 ms
25069     $03 TOP_LCD                \ 2- send DB5=DB4=1
25070     $CD 20_US                  \ 3- wait 4,1 ms
25071     $03 TOP_LCD                \ 4- send again DB5=DB4=1
25072     $5 20_US                   \ 5- wait 0,1 ms
25073     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
25074     $2 20_US                   \    wait 40 us = LCD cycle
25075     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
25076     $2 20_US                   \    wait 40 us = LCD cycle
25077     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
25078     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
25079     LCD_Clear                   \ 10- "LCD_Clear"
25080     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
25081     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
25082     LCD_Clear                   \ 10- "LCD_Clear"
25083     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
25084     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
25085     CR ." I love you"   
25086     ['] (CR) IS CR              \ ' (CR) is CR
25087     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
25088     CR
25089     ."    RC5toLCD is running. Type STOP to quit"
25090 \    NOECHO                      \ uncomment to run this app without terminal connexion
25091     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
25092     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
25093 ;
25094     \
25095
25096 : STOP                  \ stops multitasking, must to be used before downloading app
25097     ['] (WARM) IS WARM  \ remove START app from FORTH init process
25098     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
25099 ;
25100     \
25101
25102
25103 RST_STATE   ;
25104
25105
25106 CODE MAX    \    n1 n2 -- n3       signed maximum
25107             CMP     @PSP,TOS    \ n2-n1
25108             S<      ?GOTO FW1   \ n2<n1
25109 BW1         ADD     #2,PSP
25110             MOV     @IP+,PC
25111 ENDCODE
25112     \
25113
25114 CODE MIN    \    n1 n2 -- n3       signed minimum
25115             CMP     @PSP,TOS     \ n2-n1
25116             S<      ?GOTO BW1    \ n2<n1
25117 FW1         MOV     @PSP+,TOS
25118             MOV     @IP+,PC
25119 ENDCODE
25120     \
25121
25122 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
25123   >R  <# 0 # #S #>  
25124   R> OVER - 0 MAX SPACES TYPE
25125 ;
25126     \
25127
25128 CODE 20_US                      \ n --      n * 20 us
25129 BEGIN                           \ 3 cycles loop + 6~  
25130 \    MOV     #5,W                \ 3 MCLK = 1 MHz
25131 \    MOV     #23,W               \ 3 MCLK = 4 MHz
25132     MOV     #51,W               \ 3 MCLK = 8 MHz
25133 \    MOV     #104,W              \ 3 MCLK = 16 MHz
25134 \    MOV     #158,W              \ 3 MCLK = 24 MHz
25135     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
25136         SUB #1,W                \ 1
25137     0= UNTIL                    \ 2
25138     SUB     #1,TOS              \ 1
25139 0= UNTIL                        \ 2
25140     MOV     @PSP+,TOS           \ 2
25141     MOV     @IP+,PC             \ 4
25142 ENDCODE
25143     \
25144
25145 CODE TOP_LCD                    \ LCD Sample
25146 \                               \ if write : %xxxxWWWW --
25147 \                               \ if read  : -- %0000RRRR
25148     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
25149     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
25150 0= IF                           \ write LCD bits pattern
25151     AND.B #LCD_DB,TOS           \ 
25152     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
25153     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
25154     MOV @PSP+,TOS               \
25155     MOV @IP+,PC
25156 THEN                            \ read LCD bits pattern
25157     SUB #2,PSP
25158     MOV TOS,0(PSP)
25159     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
25160     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
25161     AND.B #LCD_DB,TOS           \
25162     MOV @IP+,PC
25163 ENDCODE
25164     \
25165
25166 CODE LCD_W                      \ byte --       write byte to LCD 
25167     SUB #2,PSP                  \
25168     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
25169     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
25170     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
25171     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
25172 COLON                           \ high level word starts here 
25173     TOP_LCD 2 20_US             \ write high nibble first
25174     TOP_LCD 2 20_US 
25175 ;
25176     \
25177
25178 CODE LCD_WrC                    \ char --         Write Char
25179     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
25180     JMP LCD_W 
25181 ENDCODE
25182     \
25183
25184 CODE LCD_WrF                    \ func --         Write Fonction
25185     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
25186     JMP LCD_W 
25187 ENDCODE
25188     \
25189
25190 : LCD_Clear 
25191     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
25192 ;
25193     \
25194
25195 : LCD_Home 
25196     $02 LCD_WrF 100 20_us 
25197 ;
25198     \
25199
25200 \ : LCD_Entry_set       $04 OR LCD_WrF ;
25201
25202 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
25203
25204 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
25205
25206 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
25207
25208 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
25209
25210 \ : LCD_Goto            $80 OR LCD_WrF ;
25211
25212 \ CODE LCD_R                      \ -- byte       read byte from LCD
25213 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
25214 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
25215 \ COLON                           \ starts a FORTH word
25216 \     TOP_LCD 2 20_us             \ -- %0000HHHH
25217 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
25218 \ HI2LO                           \ switch from FORTH to assembler
25219 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
25220 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
25221 \     MOV @RSP+,IP                \ restore IP saved by COLON
25222 \     MOV @IP+,PC                 \
25223 \ ENDCODE
25224 \     \
25225
25226 \ CODE LCD_RdS                    \ -- status       Read Status
25227 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
25228 \     JMP LCD_R
25229 \ ENDCODE
25230 \     \
25231
25232 \ CODE LCD_RdC                    \ -- char         Read Char
25233 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
25234 \     JMP LCD_R
25235 \ ENDCODE
25236 \     \
25237
25238 \ -------------+------+------+------+------++---+---+---+---+---------+
25239 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
25240 \ -------------+------+------+------+------++---+---+---+---+---------+
25241 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
25242 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
25243 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
25244 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
25245 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
25246 \ -------------+------+------+------+------++---+---+---+---+---------+
25247
25248
25249 \ ******************************\
25250 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
25251 \ ******************************\
25252 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
25253 \ ------------------------------\
25254 \ define LPM mode for ACCEPT    \
25255 \ ------------------------------\
25256 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
25257 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
25258 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
25259 BIT.B #SW2,&SW2_IN              \ test switch S2
25260 0= IF                           \ case of switch S2 pressed
25261     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
25262     U< IF
25263         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
25264     THEN
25265 ELSE
25266     BIT.B #SW1,&SW1_IN          \ test switch S1 input
25267     0= IF                       \ case of Switch S1 pressed
25268         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
25269         U>= IF                  \
25270             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
25271         THEN                    \
25272     THEN                        \
25273 THEN                            \
25274 RETI                            \ CPU is ON, GIE is OFF
25275 ENDASM                          \
25276     \
25277
25278
25279 \ ------------------------------\
25280 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
25281 \ ******************************\
25282 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
25283 \ ******************************\
25284 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
25285 \                               \       SMclock = 8|16|24 MHz
25286 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
25287 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
25288 \                               \       SR(9)=new Toggle bit memory (ADD on)
25289 \ ------------------------------\
25290 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
25291 \ ------------------------------\
25292 \ define LPM mode for ACCEPT    \
25293 \ ------------------------------\
25294 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
25295 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
25296 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
25297 \ ------------------------------\
25298 \ RC5_FirstStartBitHalfCycle:   \
25299 \ ------------------------------\
25300 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
25301 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
25302 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
25303 MOV     #1778,X                 \ RC5_Period in us
25304 MOV     #14,W                   \ count of loop
25305 BEGIN                           \
25306 \ ------------------------------\
25307 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
25308 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
25309     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
25310 \ RC5_Compute_3/4_Period:       \                   |
25311     RRUM    #1,X                \ X=1/2 cycle       |
25312     MOV     X,Y                 \ Y=1/2             ^
25313     RRUM    #1,Y                \ Y=1/4
25314     ADD     X,Y                 \ Y=3/4
25315 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
25316     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
25317     0= UNTIL                    \
25318 \ ------------------------------\
25319 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
25320 \ ------------------------------\
25321     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
25322     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
25323     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
25324     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
25325     SUB     #1,W                \ decrement count loop
25326 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
25327 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
25328 0<> WHILE                       \ ----> out of loop ----+
25329 \ RC5_compute_7/4_Time_out:     \                       |
25330     ADD     X,Y                 \                       |   out of bound = 7/4 period 
25331 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
25332     BEGIN                       \                       |
25333         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
25334         0>= IF                  \                       |   if cycle time out of bound
25335             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
25336             RETI                \                       |   then quit to do nothing
25337         THEN                    \                       |
25338 \ ------------------------------\                       |
25339         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
25340     0<> UNTIL                   \                   |   |
25341     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
25342 REPEAT                          \ ----> loop back --+   |
25343 \ ------------------------------\                       |
25344 \ RC5_SampleEndOf:              \ <---------------------+
25345 \ ------------------------------\
25346 BIC     #$30,&TA0CTL           \ stop timer_A0
25347 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
25348 \ ******************************\
25349 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
25350 \ ******************************\
25351 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
25352 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
25353 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
25354 BIT     #BIT13,X                \ X(13) = New_RC5_command
25355 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
25356 THEN                            \
25357 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
25358 \ ******************************\
25359 \ RC5_ComputeNewRC5word         \
25360 \ ******************************\
25361 SUB     #4,PSP                  \
25362 MOV     &BASE,2(PSP)            \ save variable BASE before use
25363 MOV     TOS,0(PSP)              \ save TOS before use
25364 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
25365 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
25366 \ ******************************\
25367 \ RC5_ComputeC6bit              \
25368 \ ******************************\
25369 BIT     #$4000,IP              \ test /C6 bit in IP
25370 0= IF   BIS #$40,TOS           \ set C6 bit in S
25371 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
25372 \ ******************************\
25373 \ RC5_CommandByteIsDone         \ RC5_code --
25374 \ ******************************\
25375
25376 \ ------------------------------\
25377 \ Display IR_RC5 code           \
25378 \ ------------------------------\
25379 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
25380 \ ------------------------------\
25381 LO2HI                           \ switch from assembler to FORTH
25382     ['] LCD_CLEAR IS CR         \ redirects CR
25383     ['] LCD_WrC  IS EMIT        \ redirects EMIT
25384     $10 BASE !                 \ change BASE to hexadecimal
25385     CR ." $" 2 U.R             \ print IR_RC5 code
25386     ['] (CR) IS CR              \ restore CR
25387     ['] (EMIT) IS EMIT          \ restore EMIT
25388 HI2LO                           \ switch from FORTH to assembler
25389 \ ------------------------------\
25390 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
25391 \ ------------------------------\
25392 MOV @PSP+,&BASE                 \ restore variable BASE
25393 RETI                            \ CPU is ON, GIE is OFF
25394 ENDASM                          \
25395     \ 
25396
25397 CODE START                      \
25398 \ ------------------------------\
25399 \ TB0CTL = %0000 0010 1001 0100\$3C0
25400 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
25401 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
25402 \                      --       \ID input divider \ 10 = /4
25403 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
25404 \                            -  \TBCLR TimerB Clear
25405 \                             - \TBIE
25406 \                              -\TBIFG
25407 \ --------------------------------\\
25408 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
25409 \              --                 \CM Capture Mode
25410 \                --               \CCIS
25411 \                   -             \SCS
25412 \                    --           \CLLD
25413 \                      -          \CAP
25414 \                        ---      \OUTMOD \ 011 = set/reset
25415 \                           -     \CCIE
25416 \                             -   \CCI
25417 \                              -  \OUT
25418 \                               - \COV
25419 \                                -\CCIFG
25420 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
25421 \ TB0EX0                          \$3E0 
25422 \ ------------------------------\
25423 \ set TimerB to make 50kHz PWM  \
25424 \ ------------------------------\
25425 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
25426 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
25427 \ ------------------------------\
25428 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
25429 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
25430 \ ------------------------------\
25431     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
25432     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
25433 \ ------------------------------\
25434 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
25435 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
25436 \ ------------------------------\
25437 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
25438 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
25439 \ ------------------------------\
25440     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
25441 \ ------------------------------\
25442 \ set TimerB to generate PWM for LCD_Vo
25443 \ ------------------------------\
25444     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
25445 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
25446     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
25447 \ ------------------------------\
25448     BIS.B #LCDVo,&LCDVo_DIR     \
25449     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
25450 \ ------------------------------\
25451     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
25452     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
25453 \ ------------------------------\
25454     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
25455     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
25456 \ ------------------------------\
25457 \ WDT interval init part        \
25458 \ ------------------------------\
25459     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
25460 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
25461 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
25462     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
25463 \ ------------------------------\
25464 \ init RC5_Int                  \
25465 \ ------------------------------\
25466     BIS.B #RC5,&IR_IE           \ enable RC5_Int
25467     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
25468 \ ------------------------------\
25469 \ init interrupt vectors
25470 \ ------------------------------\
25471     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
25472     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
25473 \ ------------------------------\
25474 \ define LPM mode for ACCEPT    \
25475 \ ------------------------------\
25476 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
25477 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
25478 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
25479
25480 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
25481
25482 \ ------------------------------\
25483 \ Init LCD 2x20                 \
25484 \ ------------------------------\
25485     $03E8 20_US                \ 1-  wait 20 ms
25486     $03 TOP_LCD                \ 2- send DB5=DB4=1
25487     $CD 20_US                  \ 3- wait 4,1 ms
25488     $03 TOP_LCD                \ 4- send again DB5=DB4=1
25489     $5 20_US                   \ 5- wait 0,1 ms
25490     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
25491     $2 20_US                   \    wait 40 us = LCD cycle
25492     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
25493     $2 20_US                   \    wait 40 us = LCD cycle
25494     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
25495     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
25496     LCD_Clear                   \ 10- "LCD_Clear"
25497     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
25498     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
25499     LCD_Clear                   \ 10- "LCD_Clear"
25500     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
25501     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
25502     CR ." I love you"   
25503     ['] (CR) IS CR              \ ' (CR) is CR
25504     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
25505     CR
25506     ."    RC5toLCD is running. Type STOP to quit"
25507 \    NOECHO                      \ uncomment to run this app without terminal connexion
25508     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
25509     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
25510 ;
25511     \
25512
25513 : STOP                  \ stops multitasking, must to be used before downloading app
25514     ['] (WARM) IS WARM  \ remove START app from FORTH init process
25515     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
25516 ;
25517     \
25518
25519
25520 RST_STATE   ;
25521
25522
25523 CODE MAX    \    n1 n2 -- n3       signed maximum
25524             CMP     @PSP,TOS    \ n2-n1
25525             S<      ?GOTO FW1   \ n2<n1
25526 BW1         ADD     #2,PSP
25527             MOV     @IP+,PC
25528 ENDCODE
25529     \
25530
25531 CODE MIN    \    n1 n2 -- n3       signed minimum
25532             CMP     @PSP,TOS     \ n2-n1
25533             S<      ?GOTO BW1    \ n2<n1
25534 FW1         MOV     @PSP+,TOS
25535             MOV     @IP+,PC
25536 ENDCODE
25537     \
25538
25539 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
25540   >R  <# 0 # #S #>  
25541   R> OVER - 0 MAX SPACES TYPE
25542 ;
25543     \
25544
25545 CODE 20_US                      \ n --      n * 20 us
25546 BEGIN                           \ 3 cycles loop + 6~  
25547 \    MOV     #5,W                \ 3 MCLK = 1 MHz
25548 \    MOV     #23,W               \ 3 MCLK = 4 MHz
25549     MOV     #51,W               \ 3 MCLK = 8 MHz
25550 \    MOV     #104,W              \ 3 MCLK = 16 MHz
25551 \    MOV     #158,W              \ 3 MCLK = 24 MHz
25552     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
25553         SUB #1,W                \ 1
25554     0= UNTIL                    \ 2
25555     SUB     #1,TOS              \ 1
25556 0= UNTIL                        \ 2
25557     MOV     @PSP+,TOS           \ 2
25558     MOV     @IP+,PC             \ 4
25559 ENDCODE
25560     \
25561
25562 CODE TOP_LCD                    \ LCD Sample
25563 \                               \ if write : %xxxxWWWW --
25564 \                               \ if read  : -- %0000RRRR
25565     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
25566     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
25567 0= IF                           \ write LCD bits pattern
25568     AND.B #LCD_DB,TOS           \ 
25569     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
25570     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
25571     MOV @PSP+,TOS               \
25572     MOV @IP+,PC
25573 THEN                            \ read LCD bits pattern
25574     SUB #2,PSP
25575     MOV TOS,0(PSP)
25576     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
25577     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
25578     AND.B #LCD_DB,TOS           \
25579     MOV @IP+,PC
25580 ENDCODE
25581     \
25582
25583 CODE LCD_W                      \ byte --       write byte to LCD 
25584     SUB #2,PSP                  \
25585     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
25586     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
25587     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
25588     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
25589 COLON                           \ high level word starts here 
25590     TOP_LCD 2 20_US             \ write high nibble first
25591     TOP_LCD 2 20_US 
25592 ;
25593     \
25594
25595 CODE LCD_WrC                    \ char --         Write Char
25596     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
25597     JMP LCD_W 
25598 ENDCODE
25599     \
25600
25601 CODE LCD_WrF                    \ func --         Write Fonction
25602     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
25603     JMP LCD_W 
25604 ENDCODE
25605     \
25606
25607 : LCD_Clear 
25608     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
25609 ;
25610     \
25611
25612 : LCD_Home 
25613     $02 LCD_WrF 100 20_us 
25614 ;
25615     \
25616
25617 \ : LCD_Entry_set       $04 OR LCD_WrF ;
25618
25619 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
25620
25621 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
25622
25623 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
25624
25625 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
25626
25627 \ : LCD_Goto            $80 OR LCD_WrF ;
25628
25629 \ CODE LCD_R                      \ -- byte       read byte from LCD
25630 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
25631 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
25632 \ COLON                           \ starts a FORTH word
25633 \     TOP_LCD 2 20_us             \ -- %0000HHHH
25634 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
25635 \ HI2LO                           \ switch from FORTH to assembler
25636 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
25637 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
25638 \     MOV @RSP+,IP                \ restore IP saved by COLON
25639 \     MOV @IP+,PC                 \
25640 \ ENDCODE
25641 \     \
25642
25643 \ CODE LCD_RdS                    \ -- status       Read Status
25644 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
25645 \     JMP LCD_R
25646 \ ENDCODE
25647 \     \
25648
25649 \ CODE LCD_RdC                    \ -- char         Read Char
25650 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
25651 \     JMP LCD_R
25652 \ ENDCODE
25653 \     \
25654
25655 \ -------------+------+------+------+------++---+---+---+---+---------+
25656 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
25657 \ -------------+------+------+------+------++---+---+---+---+---------+
25658 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
25659 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
25660 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
25661 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
25662 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
25663 \ -------------+------+------+------+------++---+---+---+---+---------+
25664
25665
25666 \ ******************************\
25667 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
25668 \ ******************************\
25669 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
25670 \ ------------------------------\
25671 \ define LPM mode for ACCEPT    \
25672 \ ------------------------------\
25673 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
25674 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
25675 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
25676 BIT.B #SW2,&SW2_IN              \ test switch S2
25677 0= IF                           \ case of switch S2 pressed
25678     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
25679     U< IF
25680         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
25681     THEN
25682 ELSE
25683     BIT.B #SW1,&SW1_IN          \ test switch S1 input
25684     0= IF                       \ case of Switch S1 pressed
25685         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
25686         U>= IF                  \
25687             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
25688         THEN                    \
25689     THEN                        \
25690 THEN                            \
25691 RETI                            \ CPU is ON, GIE is OFF
25692 ENDASM                          \
25693     \
25694
25695
25696 \ ------------------------------\
25697 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
25698 \ ******************************\
25699 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
25700 \ ******************************\
25701 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
25702 \                               \       SMclock = 8|16|24 MHz
25703 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
25704 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
25705 \                               \       SR(9)=new Toggle bit memory (ADD on)
25706 \ ------------------------------\
25707 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
25708 \ ------------------------------\
25709 \ define LPM mode for ACCEPT    \
25710 \ ------------------------------\
25711 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
25712 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
25713 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
25714 \ ------------------------------\
25715 \ RC5_FirstStartBitHalfCycle:   \
25716 \ ------------------------------\
25717 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
25718 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
25719 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
25720 MOV     #1778,X                 \ RC5_Period in us
25721 MOV     #14,W                   \ count of loop
25722 BEGIN                           \
25723 \ ------------------------------\
25724 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
25725 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
25726     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
25727 \ RC5_Compute_3/4_Period:       \                   |
25728     RRUM    #1,X                \ X=1/2 cycle       |
25729     MOV     X,Y                 \ Y=1/2             ^
25730     RRUM    #1,Y                \ Y=1/4
25731     ADD     X,Y                 \ Y=3/4
25732 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
25733     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
25734     0= UNTIL                    \
25735 \ ------------------------------\
25736 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
25737 \ ------------------------------\
25738     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
25739     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
25740     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
25741     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
25742     SUB     #1,W                \ decrement count loop
25743 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
25744 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
25745 0<> WHILE                       \ ----> out of loop ----+
25746 \ RC5_compute_7/4_Time_out:     \                       |
25747     ADD     X,Y                 \                       |   out of bound = 7/4 period 
25748 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
25749     BEGIN                       \                       |
25750         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
25751         0>= IF                  \                       |   if cycle time out of bound
25752             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
25753             RETI                \                       |   then quit to do nothing
25754         THEN                    \                       |
25755 \ ------------------------------\                       |
25756         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
25757     0<> UNTIL                   \                   |   |
25758     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
25759 REPEAT                          \ ----> loop back --+   |
25760 \ ------------------------------\                       |
25761 \ RC5_SampleEndOf:              \ <---------------------+
25762 \ ------------------------------\
25763 BIC     #$30,&TA0CTL           \ stop timer_A0
25764 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
25765 \ ******************************\
25766 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
25767 \ ******************************\
25768 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
25769 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
25770 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
25771 BIT     #BIT13,X                \ X(13) = New_RC5_command
25772 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
25773 THEN                            \
25774 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
25775 \ ******************************\
25776 \ RC5_ComputeNewRC5word         \
25777 \ ******************************\
25778 SUB     #4,PSP                  \
25779 MOV     &BASE,2(PSP)            \ save variable BASE before use
25780 MOV     TOS,0(PSP)              \ save TOS before use
25781 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
25782 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
25783 \ ******************************\
25784 \ RC5_ComputeC6bit              \
25785 \ ******************************\
25786 BIT     #$4000,IP              \ test /C6 bit in IP
25787 0= IF   BIS #$40,TOS           \ set C6 bit in S
25788 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
25789 \ ******************************\
25790 \ RC5_CommandByteIsDone         \ RC5_code --
25791 \ ******************************\
25792
25793 \ ------------------------------\
25794 \ Display IR_RC5 code           \
25795 \ ------------------------------\
25796 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
25797 \ ------------------------------\
25798 LO2HI                           \ switch from assembler to FORTH
25799     ['] LCD_CLEAR IS CR         \ redirects CR
25800     ['] LCD_WrC  IS EMIT        \ redirects EMIT
25801     $10 BASE !                 \ change BASE to hexadecimal
25802     CR ." $" 2 U.R             \ print IR_RC5 code
25803     ['] (CR) IS CR              \ restore CR
25804     ['] (EMIT) IS EMIT          \ restore EMIT
25805 HI2LO                           \ switch from FORTH to assembler
25806 \ ------------------------------\
25807 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
25808 \ ------------------------------\
25809 MOV @PSP+,&BASE                 \ restore variable BASE
25810 RETI                            \ CPU is ON, GIE is OFF
25811 ENDASM                          \
25812     \ 
25813
25814 CODE START                      \
25815 \ ------------------------------\
25816 \ TB0CTL = %0000 0010 1001 0100\$3C0
25817 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
25818 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
25819 \                      --       \ID input divider \ 10 = /4
25820 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
25821 \                            -  \TBCLR TimerB Clear
25822 \                             - \TBIE
25823 \                              -\TBIFG
25824 \ --------------------------------\\
25825 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
25826 \              --                 \CM Capture Mode
25827 \                --               \CCIS
25828 \                   -             \SCS
25829 \                    --           \CLLD
25830 \                      -          \CAP
25831 \                        ---      \OUTMOD \ 011 = set/reset
25832 \                           -     \CCIE
25833 \                             -   \CCI
25834 \                              -  \OUT
25835 \                               - \COV
25836 \                                -\CCIFG
25837 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
25838 \ TB0EX0                          \$3E0 
25839 \ ------------------------------\
25840 \ set TimerB to make 50kHz PWM  \
25841 \ ------------------------------\
25842 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
25843 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
25844 \ ------------------------------\
25845 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
25846 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
25847 \ ------------------------------\
25848     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
25849     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
25850 \ ------------------------------\
25851 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
25852 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
25853 \ ------------------------------\
25854 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
25855 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
25856 \ ------------------------------\
25857     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
25858 \ ------------------------------\
25859 \ set TimerB to generate PWM for LCD_Vo
25860 \ ------------------------------\
25861     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
25862 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
25863     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
25864 \ ------------------------------\
25865     BIS.B #LCDVo,&LCDVo_DIR     \
25866     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
25867 \ ------------------------------\
25868     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
25869     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
25870 \ ------------------------------\
25871     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
25872     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
25873 \ ------------------------------\
25874 \ WDT interval init part        \
25875 \ ------------------------------\
25876     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
25877 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
25878 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
25879     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
25880 \ ------------------------------\
25881 \ init RC5_Int                  \
25882 \ ------------------------------\
25883     BIS.B #RC5,&IR_IE           \ enable RC5_Int
25884     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
25885 \ ------------------------------\
25886 \ init interrupt vectors
25887 \ ------------------------------\
25888     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
25889     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
25890 \ ------------------------------\
25891 \ define LPM mode for ACCEPT    \
25892 \ ------------------------------\
25893 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
25894 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
25895 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
25896
25897 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
25898
25899 \ ------------------------------\
25900 \ Init LCD 2x20                 \
25901 \ ------------------------------\
25902     $03E8 20_US                \ 1-  wait 20 ms
25903     $03 TOP_LCD                \ 2- send DB5=DB4=1
25904     $CD 20_US                  \ 3- wait 4,1 ms
25905     $03 TOP_LCD                \ 4- send again DB5=DB4=1
25906     $5 20_US                   \ 5- wait 0,1 ms
25907     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
25908     $2 20_US                   \    wait 40 us = LCD cycle
25909     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
25910     $2 20_US                   \    wait 40 us = LCD cycle
25911     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
25912     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
25913     LCD_Clear                   \ 10- "LCD_Clear"
25914     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
25915     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
25916     LCD_Clear                   \ 10- "LCD_Clear"
25917     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
25918     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
25919     CR ." I love you"   
25920     ['] (CR) IS CR              \ ' (CR) is CR
25921     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
25922     CR
25923     ."    RC5toLCD is running. Type STOP to quit"
25924 \    NOECHO                      \ uncomment to run this app without terminal connexion
25925     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
25926     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
25927 ;
25928     \
25929
25930 : STOP                  \ stops multitasking, must to be used before downloading app
25931     ['] (WARM) IS WARM  \ remove START app from FORTH init process
25932     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
25933 ;
25934     \
25935
25936
25937 RST_STATE   ;
25938
25939
25940 CODE MAX    \    n1 n2 -- n3       signed maximum
25941             CMP     @PSP,TOS    \ n2-n1
25942             S<      ?GOTO FW1   \ n2<n1
25943 BW1         ADD     #2,PSP
25944             MOV     @IP+,PC
25945 ENDCODE
25946     \
25947
25948 CODE MIN    \    n1 n2 -- n3       signed minimum
25949             CMP     @PSP,TOS     \ n2-n1
25950             S<      ?GOTO BW1    \ n2<n1
25951 FW1         MOV     @PSP+,TOS
25952             MOV     @IP+,PC
25953 ENDCODE
25954     \
25955
25956 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
25957   >R  <# 0 # #S #>  
25958   R> OVER - 0 MAX SPACES TYPE
25959 ;
25960     \
25961
25962 CODE 20_US                      \ n --      n * 20 us
25963 BEGIN                           \ 3 cycles loop + 6~  
25964 \    MOV     #5,W                \ 3 MCLK = 1 MHz
25965 \    MOV     #23,W               \ 3 MCLK = 4 MHz
25966     MOV     #51,W               \ 3 MCLK = 8 MHz
25967 \    MOV     #104,W              \ 3 MCLK = 16 MHz
25968 \    MOV     #158,W              \ 3 MCLK = 24 MHz
25969     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
25970         SUB #1,W                \ 1
25971     0= UNTIL                    \ 2
25972     SUB     #1,TOS              \ 1
25973 0= UNTIL                        \ 2
25974     MOV     @PSP+,TOS           \ 2
25975     MOV     @IP+,PC             \ 4
25976 ENDCODE
25977     \
25978
25979 CODE TOP_LCD                    \ LCD Sample
25980 \                               \ if write : %xxxxWWWW --
25981 \                               \ if read  : -- %0000RRRR
25982     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
25983     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
25984 0= IF                           \ write LCD bits pattern
25985     AND.B #LCD_DB,TOS           \ 
25986     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
25987     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
25988     MOV @PSP+,TOS               \
25989     MOV @IP+,PC
25990 THEN                            \ read LCD bits pattern
25991     SUB #2,PSP
25992     MOV TOS,0(PSP)
25993     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
25994     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
25995     AND.B #LCD_DB,TOS           \
25996     MOV @IP+,PC
25997 ENDCODE
25998     \
25999
26000 CODE LCD_W                      \ byte --       write byte to LCD 
26001     SUB #2,PSP                  \
26002     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
26003     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
26004     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
26005     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
26006 COLON                           \ high level word starts here 
26007     TOP_LCD 2 20_US             \ write high nibble first
26008     TOP_LCD 2 20_US 
26009 ;
26010     \
26011
26012 CODE LCD_WrC                    \ char --         Write Char
26013     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
26014     JMP LCD_W 
26015 ENDCODE
26016     \
26017
26018 CODE LCD_WrF                    \ func --         Write Fonction
26019     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
26020     JMP LCD_W 
26021 ENDCODE
26022     \
26023
26024 : LCD_Clear 
26025     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
26026 ;
26027     \
26028
26029 : LCD_Home 
26030     $02 LCD_WrF 100 20_us 
26031 ;
26032     \
26033
26034 \ : LCD_Entry_set       $04 OR LCD_WrF ;
26035
26036 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
26037
26038 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
26039
26040 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
26041
26042 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
26043
26044 \ : LCD_Goto            $80 OR LCD_WrF ;
26045
26046 \ CODE LCD_R                      \ -- byte       read byte from LCD
26047 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
26048 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
26049 \ COLON                           \ starts a FORTH word
26050 \     TOP_LCD 2 20_us             \ -- %0000HHHH
26051 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
26052 \ HI2LO                           \ switch from FORTH to assembler
26053 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
26054 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
26055 \     MOV @RSP+,IP                \ restore IP saved by COLON
26056 \     MOV @IP+,PC                 \
26057 \ ENDCODE
26058 \     \
26059
26060 \ CODE LCD_RdS                    \ -- status       Read Status
26061 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
26062 \     JMP LCD_R
26063 \ ENDCODE
26064 \     \
26065
26066 \ CODE LCD_RdC                    \ -- char         Read Char
26067 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
26068 \     JMP LCD_R
26069 \ ENDCODE
26070 \     \
26071
26072 \ -------------+------+------+------+------++---+---+---+---+---------+
26073 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
26074 \ -------------+------+------+------+------++---+---+---+---+---------+
26075 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
26076 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
26077 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
26078 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
26079 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
26080 \ -------------+------+------+------+------++---+---+---+---+---------+
26081
26082
26083 \ ******************************\
26084 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
26085 \ ******************************\
26086 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
26087 \ ------------------------------\
26088 \ define LPM mode for ACCEPT    \
26089 \ ------------------------------\
26090 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
26091 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
26092 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
26093 BIT.B #SW2,&SW2_IN              \ test switch S2
26094 0= IF                           \ case of switch S2 pressed
26095     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
26096     U< IF
26097         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
26098     THEN
26099 ELSE
26100     BIT.B #SW1,&SW1_IN          \ test switch S1 input
26101     0= IF                       \ case of Switch S1 pressed
26102         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
26103         U>= IF                  \
26104             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
26105         THEN                    \
26106     THEN                        \
26107 THEN                            \
26108 RETI                            \ CPU is ON, GIE is OFF
26109 ENDASM                          \
26110     \
26111
26112
26113 \ ------------------------------\
26114 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
26115 \ ******************************\
26116 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
26117 \ ******************************\
26118 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
26119 \                               \       SMclock = 8|16|24 MHz
26120 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
26121 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
26122 \                               \       SR(9)=new Toggle bit memory (ADD on)
26123 \ ------------------------------\
26124 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
26125 \ ------------------------------\
26126 \ define LPM mode for ACCEPT    \
26127 \ ------------------------------\
26128 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
26129 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
26130 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
26131 \ ------------------------------\
26132 \ RC5_FirstStartBitHalfCycle:   \
26133 \ ------------------------------\
26134 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
26135 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
26136 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
26137 MOV     #1778,X                 \ RC5_Period in us
26138 MOV     #14,W                   \ count of loop
26139 BEGIN                           \
26140 \ ------------------------------\
26141 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
26142 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
26143     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
26144 \ RC5_Compute_3/4_Period:       \                   |
26145     RRUM    #1,X                \ X=1/2 cycle       |
26146     MOV     X,Y                 \ Y=1/2             ^
26147     RRUM    #1,Y                \ Y=1/4
26148     ADD     X,Y                 \ Y=3/4
26149 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
26150     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
26151     0= UNTIL                    \
26152 \ ------------------------------\
26153 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
26154 \ ------------------------------\
26155     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
26156     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
26157     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
26158     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
26159     SUB     #1,W                \ decrement count loop
26160 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
26161 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
26162 0<> WHILE                       \ ----> out of loop ----+
26163 \ RC5_compute_7/4_Time_out:     \                       |
26164     ADD     X,Y                 \                       |   out of bound = 7/4 period 
26165 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
26166     BEGIN                       \                       |
26167         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
26168         0>= IF                  \                       |   if cycle time out of bound
26169             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
26170             RETI                \                       |   then quit to do nothing
26171         THEN                    \                       |
26172 \ ------------------------------\                       |
26173         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
26174     0<> UNTIL                   \                   |   |
26175     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
26176 REPEAT                          \ ----> loop back --+   |
26177 \ ------------------------------\                       |
26178 \ RC5_SampleEndOf:              \ <---------------------+
26179 \ ------------------------------\
26180 BIC     #$30,&TA0CTL           \ stop timer_A0
26181 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
26182 \ ******************************\
26183 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
26184 \ ******************************\
26185 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
26186 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
26187 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
26188 BIT     #BIT13,X                \ X(13) = New_RC5_command
26189 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
26190 THEN                            \
26191 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
26192 \ ******************************\
26193 \ RC5_ComputeNewRC5word         \
26194 \ ******************************\
26195 SUB     #4,PSP                  \
26196 MOV     &BASE,2(PSP)            \ save variable BASE before use
26197 MOV     TOS,0(PSP)              \ save TOS before use
26198 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
26199 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
26200 \ ******************************\
26201 \ RC5_ComputeC6bit              \
26202 \ ******************************\
26203 BIT     #$4000,IP              \ test /C6 bit in IP
26204 0= IF   BIS #$40,TOS           \ set C6 bit in S
26205 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
26206 \ ******************************\
26207 \ RC5_CommandByteIsDone         \ RC5_code --
26208 \ ******************************\
26209
26210 \ ------------------------------\
26211 \ Display IR_RC5 code           \
26212 \ ------------------------------\
26213 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
26214 \ ------------------------------\
26215 LO2HI                           \ switch from assembler to FORTH
26216     ['] LCD_CLEAR IS CR         \ redirects CR
26217     ['] LCD_WrC  IS EMIT        \ redirects EMIT
26218     $10 BASE !                 \ change BASE to hexadecimal
26219     CR ." $" 2 U.R             \ print IR_RC5 code
26220     ['] (CR) IS CR              \ restore CR
26221     ['] (EMIT) IS EMIT          \ restore EMIT
26222 HI2LO                           \ switch from FORTH to assembler
26223 \ ------------------------------\
26224 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
26225 \ ------------------------------\
26226 MOV @PSP+,&BASE                 \ restore variable BASE
26227 RETI                            \ CPU is ON, GIE is OFF
26228 ENDASM                          \
26229     \ 
26230
26231 CODE START                      \
26232 \ ------------------------------\
26233 \ TB0CTL = %0000 0010 1001 0100\$3C0
26234 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
26235 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
26236 \                      --       \ID input divider \ 10 = /4
26237 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
26238 \                            -  \TBCLR TimerB Clear
26239 \                             - \TBIE
26240 \                              -\TBIFG
26241 \ --------------------------------\\
26242 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
26243 \              --                 \CM Capture Mode
26244 \                --               \CCIS
26245 \                   -             \SCS
26246 \                    --           \CLLD
26247 \                      -          \CAP
26248 \                        ---      \OUTMOD \ 011 = set/reset
26249 \                           -     \CCIE
26250 \                             -   \CCI
26251 \                              -  \OUT
26252 \                               - \COV
26253 \                                -\CCIFG
26254 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
26255 \ TB0EX0                          \$3E0 
26256 \ ------------------------------\
26257 \ set TimerB to make 50kHz PWM  \
26258 \ ------------------------------\
26259 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
26260 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
26261 \ ------------------------------\
26262 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
26263 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
26264 \ ------------------------------\
26265     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
26266     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
26267 \ ------------------------------\
26268 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
26269 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
26270 \ ------------------------------\
26271 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
26272 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
26273 \ ------------------------------\
26274     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
26275 \ ------------------------------\
26276 \ set TimerB to generate PWM for LCD_Vo
26277 \ ------------------------------\
26278     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
26279 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
26280     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
26281 \ ------------------------------\
26282     BIS.B #LCDVo,&LCDVo_DIR     \
26283     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
26284 \ ------------------------------\
26285     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
26286     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
26287 \ ------------------------------\
26288     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
26289     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
26290 \ ------------------------------\
26291 \ WDT interval init part        \
26292 \ ------------------------------\
26293     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
26294 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
26295 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
26296     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
26297 \ ------------------------------\
26298 \ init RC5_Int                  \
26299 \ ------------------------------\
26300     BIS.B #RC5,&IR_IE           \ enable RC5_Int
26301     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
26302 \ ------------------------------\
26303 \ init interrupt vectors
26304 \ ------------------------------\
26305     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
26306     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
26307 \ ------------------------------\
26308 \ define LPM mode for ACCEPT    \
26309 \ ------------------------------\
26310 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
26311 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
26312 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
26313
26314 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
26315
26316 \ ------------------------------\
26317 \ Init LCD 2x20                 \
26318 \ ------------------------------\
26319     $03E8 20_US                \ 1-  wait 20 ms
26320     $03 TOP_LCD                \ 2- send DB5=DB4=1
26321     $CD 20_US                  \ 3- wait 4,1 ms
26322     $03 TOP_LCD                \ 4- send again DB5=DB4=1
26323     $5 20_US                   \ 5- wait 0,1 ms
26324     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
26325     $2 20_US                   \    wait 40 us = LCD cycle
26326     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
26327     $2 20_US                   \    wait 40 us = LCD cycle
26328     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
26329     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
26330     LCD_Clear                   \ 10- "LCD_Clear"
26331     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
26332     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
26333     LCD_Clear                   \ 10- "LCD_Clear"
26334     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
26335     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
26336     CR ." I love you"   
26337     ['] (CR) IS CR              \ ' (CR) is CR
26338     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
26339     CR
26340     ."    RC5toLCD is running. Type STOP to quit"
26341 \    NOECHO                      \ uncomment to run this app without terminal connexion
26342     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
26343     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
26344 ;
26345     \
26346
26347 : STOP                  \ stops multitasking, must to be used before downloading app
26348     ['] (WARM) IS WARM  \ remove START app from FORTH init process
26349     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
26350 ;
26351     \
26352
26353
26354 RST_STATE   ;
26355
26356
26357 CODE MAX    \    n1 n2 -- n3       signed maximum
26358             CMP     @PSP,TOS    \ n2-n1
26359             S<      ?GOTO FW1   \ n2<n1
26360 BW1         ADD     #2,PSP
26361             MOV     @IP+,PC
26362 ENDCODE
26363     \
26364
26365 CODE MIN    \    n1 n2 -- n3       signed minimum
26366             CMP     @PSP,TOS     \ n2-n1
26367             S<      ?GOTO BW1    \ n2<n1
26368 FW1         MOV     @PSP+,TOS
26369             MOV     @IP+,PC
26370 ENDCODE
26371     \
26372
26373 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
26374   >R  <# 0 # #S #>  
26375   R> OVER - 0 MAX SPACES TYPE
26376 ;
26377     \
26378
26379 CODE 20_US                      \ n --      n * 20 us
26380 BEGIN                           \ 3 cycles loop + 6~  
26381 \    MOV     #5,W                \ 3 MCLK = 1 MHz
26382 \    MOV     #23,W               \ 3 MCLK = 4 MHz
26383     MOV     #51,W               \ 3 MCLK = 8 MHz
26384 \    MOV     #104,W              \ 3 MCLK = 16 MHz
26385 \    MOV     #158,W              \ 3 MCLK = 24 MHz
26386     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
26387         SUB #1,W                \ 1
26388     0= UNTIL                    \ 2
26389     SUB     #1,TOS              \ 1
26390 0= UNTIL                        \ 2
26391     MOV     @PSP+,TOS           \ 2
26392     MOV     @IP+,PC             \ 4
26393 ENDCODE
26394     \
26395
26396 CODE TOP_LCD                    \ LCD Sample
26397 \                               \ if write : %xxxxWWWW --
26398 \                               \ if read  : -- %0000RRRR
26399     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
26400     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
26401 0= IF                           \ write LCD bits pattern
26402     AND.B #LCD_DB,TOS           \ 
26403     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
26404     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
26405     MOV @PSP+,TOS               \
26406     MOV @IP+,PC
26407 THEN                            \ read LCD bits pattern
26408     SUB #2,PSP
26409     MOV TOS,0(PSP)
26410     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
26411     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
26412     AND.B #LCD_DB,TOS           \
26413     MOV @IP+,PC
26414 ENDCODE
26415     \
26416
26417 CODE LCD_W                      \ byte --       write byte to LCD 
26418     SUB #2,PSP                  \
26419     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
26420     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
26421     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
26422     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
26423 COLON                           \ high level word starts here 
26424     TOP_LCD 2 20_US             \ write high nibble first
26425     TOP_LCD 2 20_US 
26426 ;
26427     \
26428
26429 CODE LCD_WrC                    \ char --         Write Char
26430     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
26431     JMP LCD_W 
26432 ENDCODE
26433     \
26434
26435 CODE LCD_WrF                    \ func --         Write Fonction
26436     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
26437     JMP LCD_W 
26438 ENDCODE
26439     \
26440
26441 : LCD_Clear 
26442     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
26443 ;
26444     \
26445
26446 : LCD_Home 
26447     $02 LCD_WrF 100 20_us 
26448 ;
26449     \
26450
26451 \ : LCD_Entry_set       $04 OR LCD_WrF ;
26452
26453 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
26454
26455 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
26456
26457 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
26458
26459 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
26460
26461 \ : LCD_Goto            $80 OR LCD_WrF ;
26462
26463 \ CODE LCD_R                      \ -- byte       read byte from LCD
26464 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
26465 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
26466 \ COLON                           \ starts a FORTH word
26467 \     TOP_LCD 2 20_us             \ -- %0000HHHH
26468 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
26469 \ HI2LO                           \ switch from FORTH to assembler
26470 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
26471 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
26472 \     MOV @RSP+,IP                \ restore IP saved by COLON
26473 \     MOV @IP+,PC                 \
26474 \ ENDCODE
26475 \     \
26476
26477 \ CODE LCD_RdS                    \ -- status       Read Status
26478 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
26479 \     JMP LCD_R
26480 \ ENDCODE
26481 \     \
26482
26483 \ CODE LCD_RdC                    \ -- char         Read Char
26484 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
26485 \     JMP LCD_R
26486 \ ENDCODE
26487 \     \
26488
26489 \ -------------+------+------+------+------++---+---+---+---+---------+
26490 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
26491 \ -------------+------+------+------+------++---+---+---+---+---------+
26492 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
26493 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
26494 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
26495 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
26496 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
26497 \ -------------+------+------+------+------++---+---+---+---+---------+
26498
26499
26500 \ ******************************\
26501 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
26502 \ ******************************\
26503 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
26504 \ ------------------------------\
26505 \ define LPM mode for ACCEPT    \
26506 \ ------------------------------\
26507 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
26508 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
26509 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
26510 BIT.B #SW2,&SW2_IN              \ test switch S2
26511 0= IF                           \ case of switch S2 pressed
26512     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
26513     U< IF
26514         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
26515     THEN
26516 ELSE
26517     BIT.B #SW1,&SW1_IN          \ test switch S1 input
26518     0= IF                       \ case of Switch S1 pressed
26519         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
26520         U>= IF                  \
26521             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
26522         THEN                    \
26523     THEN                        \
26524 THEN                            \
26525 RETI                            \ CPU is ON, GIE is OFF
26526 ENDASM                          \
26527     \
26528
26529
26530 \ ------------------------------\
26531 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
26532 \ ******************************\
26533 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
26534 \ ******************************\
26535 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
26536 \                               \       SMclock = 8|16|24 MHz
26537 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
26538 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
26539 \                               \       SR(9)=new Toggle bit memory (ADD on)
26540 \ ------------------------------\
26541 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
26542 \ ------------------------------\
26543 \ define LPM mode for ACCEPT    \
26544 \ ------------------------------\
26545 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
26546 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
26547 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
26548 \ ------------------------------\
26549 \ RC5_FirstStartBitHalfCycle:   \
26550 \ ------------------------------\
26551 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
26552 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
26553 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
26554 MOV     #1778,X                 \ RC5_Period in us
26555 MOV     #14,W                   \ count of loop
26556 BEGIN                           \
26557 \ ------------------------------\
26558 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
26559 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
26560     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
26561 \ RC5_Compute_3/4_Period:       \                   |
26562     RRUM    #1,X                \ X=1/2 cycle       |
26563     MOV     X,Y                 \ Y=1/2             ^
26564     RRUM    #1,Y                \ Y=1/4
26565     ADD     X,Y                 \ Y=3/4
26566 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
26567     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
26568     0= UNTIL                    \
26569 \ ------------------------------\
26570 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
26571 \ ------------------------------\
26572     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
26573     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
26574     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
26575     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
26576     SUB     #1,W                \ decrement count loop
26577 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
26578 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
26579 0<> WHILE                       \ ----> out of loop ----+
26580 \ RC5_compute_7/4_Time_out:     \                       |
26581     ADD     X,Y                 \                       |   out of bound = 7/4 period 
26582 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
26583     BEGIN                       \                       |
26584         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
26585         0>= IF                  \                       |   if cycle time out of bound
26586             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
26587             RETI                \                       |   then quit to do nothing
26588         THEN                    \                       |
26589 \ ------------------------------\                       |
26590         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
26591     0<> UNTIL                   \                   |   |
26592     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
26593 REPEAT                          \ ----> loop back --+   |
26594 \ ------------------------------\                       |
26595 \ RC5_SampleEndOf:              \ <---------------------+
26596 \ ------------------------------\
26597 BIC     #$30,&TA0CTL           \ stop timer_A0
26598 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
26599 \ ******************************\
26600 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
26601 \ ******************************\
26602 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
26603 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
26604 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
26605 BIT     #BIT13,X                \ X(13) = New_RC5_command
26606 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
26607 THEN                            \
26608 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
26609 \ ******************************\
26610 \ RC5_ComputeNewRC5word         \
26611 \ ******************************\
26612 SUB     #4,PSP                  \
26613 MOV     &BASE,2(PSP)            \ save variable BASE before use
26614 MOV     TOS,0(PSP)              \ save TOS before use
26615 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
26616 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
26617 \ ******************************\
26618 \ RC5_ComputeC6bit              \
26619 \ ******************************\
26620 BIT     #$4000,IP              \ test /C6 bit in IP
26621 0= IF   BIS #$40,TOS           \ set C6 bit in S
26622 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
26623 \ ******************************\
26624 \ RC5_CommandByteIsDone         \ RC5_code --
26625 \ ******************************\
26626
26627 \ ------------------------------\
26628 \ Display IR_RC5 code           \
26629 \ ------------------------------\
26630 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
26631 \ ------------------------------\
26632 LO2HI                           \ switch from assembler to FORTH
26633     ['] LCD_CLEAR IS CR         \ redirects CR
26634     ['] LCD_WrC  IS EMIT        \ redirects EMIT
26635     $10 BASE !                 \ change BASE to hexadecimal
26636     CR ." $" 2 U.R             \ print IR_RC5 code
26637     ['] (CR) IS CR              \ restore CR
26638     ['] (EMIT) IS EMIT          \ restore EMIT
26639 HI2LO                           \ switch from FORTH to assembler
26640 \ ------------------------------\
26641 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
26642 \ ------------------------------\
26643 MOV @PSP+,&BASE                 \ restore variable BASE
26644 RETI                            \ CPU is ON, GIE is OFF
26645 ENDASM                          \
26646     \ 
26647
26648 CODE START                      \
26649 \ ------------------------------\
26650 \ TB0CTL = %0000 0010 1001 0100\$3C0
26651 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
26652 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
26653 \                      --       \ID input divider \ 10 = /4
26654 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
26655 \                            -  \TBCLR TimerB Clear
26656 \                             - \TBIE
26657 \                              -\TBIFG
26658 \ --------------------------------\\
26659 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
26660 \              --                 \CM Capture Mode
26661 \                --               \CCIS
26662 \                   -             \SCS
26663 \                    --           \CLLD
26664 \                      -          \CAP
26665 \                        ---      \OUTMOD \ 011 = set/reset
26666 \                           -     \CCIE
26667 \                             -   \CCI
26668 \                              -  \OUT
26669 \                               - \COV
26670 \                                -\CCIFG
26671 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
26672 \ TB0EX0                          \$3E0 
26673 \ ------------------------------\
26674 \ set TimerB to make 50kHz PWM  \
26675 \ ------------------------------\
26676 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
26677 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
26678 \ ------------------------------\
26679 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
26680 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
26681 \ ------------------------------\
26682     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
26683     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
26684 \ ------------------------------\
26685 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
26686 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
26687 \ ------------------------------\
26688 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
26689 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
26690 \ ------------------------------\
26691     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
26692 \ ------------------------------\
26693 \ set TimerB to generate PWM for LCD_Vo
26694 \ ------------------------------\
26695     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
26696 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
26697     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
26698 \ ------------------------------\
26699     BIS.B #LCDVo,&LCDVo_DIR     \
26700     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
26701 \ ------------------------------\
26702     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
26703     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
26704 \ ------------------------------\
26705     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
26706     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
26707 \ ------------------------------\
26708 \ WDT interval init part        \
26709 \ ------------------------------\
26710     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
26711 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
26712 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
26713     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
26714 \ ------------------------------\
26715 \ init RC5_Int                  \
26716 \ ------------------------------\
26717     BIS.B #RC5,&IR_IE           \ enable RC5_Int
26718     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
26719 \ ------------------------------\
26720 \ init interrupt vectors
26721 \ ------------------------------\
26722     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
26723     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
26724 \ ------------------------------\
26725 \ define LPM mode for ACCEPT    \
26726 \ ------------------------------\
26727 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
26728 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
26729 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
26730
26731 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
26732
26733 \ ------------------------------\
26734 \ Init LCD 2x20                 \
26735 \ ------------------------------\
26736     $03E8 20_US                \ 1-  wait 20 ms
26737     $03 TOP_LCD                \ 2- send DB5=DB4=1
26738     $CD 20_US                  \ 3- wait 4,1 ms
26739     $03 TOP_LCD                \ 4- send again DB5=DB4=1
26740     $5 20_US                   \ 5- wait 0,1 ms
26741     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
26742     $2 20_US                   \    wait 40 us = LCD cycle
26743     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
26744     $2 20_US                   \    wait 40 us = LCD cycle
26745     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
26746     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
26747     LCD_Clear                   \ 10- "LCD_Clear"
26748     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
26749     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
26750     LCD_Clear                   \ 10- "LCD_Clear"
26751     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
26752     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
26753     CR ." I love you"   
26754     ['] (CR) IS CR              \ ' (CR) is CR
26755     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
26756     CR
26757     ."    RC5toLCD is running. Type STOP to quit"
26758 \    NOECHO                      \ uncomment to run this app without terminal connexion
26759     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
26760     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
26761 ;
26762     \
26763
26764 : STOP                  \ stops multitasking, must to be used before downloading app
26765     ['] (WARM) IS WARM  \ remove START app from FORTH init process
26766     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
26767 ;
26768     \
26769
26770
26771 RST_STATE   ;
26772
26773
26774 CODE MAX    \    n1 n2 -- n3       signed maximum
26775             CMP     @PSP,TOS    \ n2-n1
26776             S<      ?GOTO FW1   \ n2<n1
26777 BW1         ADD     #2,PSP
26778             MOV     @IP+,PC
26779 ENDCODE
26780     \
26781
26782 CODE MIN    \    n1 n2 -- n3       signed minimum
26783             CMP     @PSP,TOS     \ n2-n1
26784             S<      ?GOTO BW1    \ n2<n1
26785 FW1         MOV     @PSP+,TOS
26786             MOV     @IP+,PC
26787 ENDCODE
26788     \
26789
26790 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
26791   >R  <# 0 # #S #>  
26792   R> OVER - 0 MAX SPACES TYPE
26793 ;
26794     \
26795
26796 CODE 20_US                      \ n --      n * 20 us
26797 BEGIN                           \ 3 cycles loop + 6~  
26798 \    MOV     #5,W                \ 3 MCLK = 1 MHz
26799 \    MOV     #23,W               \ 3 MCLK = 4 MHz
26800     MOV     #51,W               \ 3 MCLK = 8 MHz
26801 \    MOV     #104,W              \ 3 MCLK = 16 MHz
26802 \    MOV     #158,W              \ 3 MCLK = 24 MHz
26803     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
26804         SUB #1,W                \ 1
26805     0= UNTIL                    \ 2
26806     SUB     #1,TOS              \ 1
26807 0= UNTIL                        \ 2
26808     MOV     @PSP+,TOS           \ 2
26809     MOV     @IP+,PC             \ 4
26810 ENDCODE
26811     \
26812
26813 CODE TOP_LCD                    \ LCD Sample
26814 \                               \ if write : %xxxxWWWW --
26815 \                               \ if read  : -- %0000RRRR
26816     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
26817     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
26818 0= IF                           \ write LCD bits pattern
26819     AND.B #LCD_DB,TOS           \ 
26820     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
26821     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
26822     MOV @PSP+,TOS               \
26823     MOV @IP+,PC
26824 THEN                            \ read LCD bits pattern
26825     SUB #2,PSP
26826     MOV TOS,0(PSP)
26827     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
26828     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
26829     AND.B #LCD_DB,TOS           \
26830     MOV @IP+,PC
26831 ENDCODE
26832     \
26833
26834 CODE LCD_W                      \ byte --       write byte to LCD 
26835     SUB #2,PSP                  \
26836     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
26837     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
26838     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
26839     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
26840 COLON                           \ high level word starts here 
26841     TOP_LCD 2 20_US             \ write high nibble first
26842     TOP_LCD 2 20_US 
26843 ;
26844     \
26845
26846 CODE LCD_WrC                    \ char --         Write Char
26847     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
26848     JMP LCD_W 
26849 ENDCODE
26850     \
26851
26852 CODE LCD_WrF                    \ func --         Write Fonction
26853     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
26854     JMP LCD_W 
26855 ENDCODE
26856     \
26857
26858 : LCD_Clear 
26859     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
26860 ;
26861     \
26862
26863 : LCD_Home 
26864     $02 LCD_WrF 100 20_us 
26865 ;
26866     \
26867
26868 \ : LCD_Entry_set       $04 OR LCD_WrF ;
26869
26870 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
26871
26872 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
26873
26874 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
26875
26876 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
26877
26878 \ : LCD_Goto            $80 OR LCD_WrF ;
26879
26880 \ CODE LCD_R                      \ -- byte       read byte from LCD
26881 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
26882 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
26883 \ COLON                           \ starts a FORTH word
26884 \     TOP_LCD 2 20_us             \ -- %0000HHHH
26885 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
26886 \ HI2LO                           \ switch from FORTH to assembler
26887 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
26888 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
26889 \     MOV @RSP+,IP                \ restore IP saved by COLON
26890 \     MOV @IP+,PC                 \
26891 \ ENDCODE
26892 \     \
26893
26894 \ CODE LCD_RdS                    \ -- status       Read Status
26895 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
26896 \     JMP LCD_R
26897 \ ENDCODE
26898 \     \
26899
26900 \ CODE LCD_RdC                    \ -- char         Read Char
26901 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
26902 \     JMP LCD_R
26903 \ ENDCODE
26904 \     \
26905
26906 \ -------------+------+------+------+------++---+---+---+---+---------+
26907 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
26908 \ -------------+------+------+------+------++---+---+---+---+---------+
26909 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
26910 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
26911 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
26912 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
26913 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
26914 \ -------------+------+------+------+------++---+---+---+---+---------+
26915
26916
26917 \ ******************************\
26918 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
26919 \ ******************************\
26920 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
26921 \ ------------------------------\
26922 \ define LPM mode for ACCEPT    \
26923 \ ------------------------------\
26924 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
26925 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
26926 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
26927 BIT.B #SW2,&SW2_IN              \ test switch S2
26928 0= IF                           \ case of switch S2 pressed
26929     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
26930     U< IF
26931         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
26932     THEN
26933 ELSE
26934     BIT.B #SW1,&SW1_IN          \ test switch S1 input
26935     0= IF                       \ case of Switch S1 pressed
26936         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
26937         U>= IF                  \
26938             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
26939         THEN                    \
26940     THEN                        \
26941 THEN                            \
26942 RETI                            \ CPU is ON, GIE is OFF
26943 ENDASM                          \
26944     \
26945
26946
26947 \ ------------------------------\
26948 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
26949 \ ******************************\
26950 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
26951 \ ******************************\
26952 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
26953 \                               \       SMclock = 8|16|24 MHz
26954 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
26955 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
26956 \                               \       SR(9)=new Toggle bit memory (ADD on)
26957 \ ------------------------------\
26958 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
26959 \ ------------------------------\
26960 \ define LPM mode for ACCEPT    \
26961 \ ------------------------------\
26962 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
26963 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
26964 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
26965 \ ------------------------------\
26966 \ RC5_FirstStartBitHalfCycle:   \
26967 \ ------------------------------\
26968 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
26969 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
26970 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
26971 MOV     #1778,X                 \ RC5_Period in us
26972 MOV     #14,W                   \ count of loop
26973 BEGIN                           \
26974 \ ------------------------------\
26975 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
26976 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
26977     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
26978 \ RC5_Compute_3/4_Period:       \                   |
26979     RRUM    #1,X                \ X=1/2 cycle       |
26980     MOV     X,Y                 \ Y=1/2             ^
26981     RRUM    #1,Y                \ Y=1/4
26982     ADD     X,Y                 \ Y=3/4
26983 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
26984     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
26985     0= UNTIL                    \
26986 \ ------------------------------\
26987 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
26988 \ ------------------------------\
26989     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
26990     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
26991     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
26992     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
26993     SUB     #1,W                \ decrement count loop
26994 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
26995 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
26996 0<> WHILE                       \ ----> out of loop ----+
26997 \ RC5_compute_7/4_Time_out:     \                       |
26998     ADD     X,Y                 \                       |   out of bound = 7/4 period 
26999 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
27000     BEGIN                       \                       |
27001         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
27002         0>= IF                  \                       |   if cycle time out of bound
27003             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
27004             RETI                \                       |   then quit to do nothing
27005         THEN                    \                       |
27006 \ ------------------------------\                       |
27007         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
27008     0<> UNTIL                   \                   |   |
27009     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
27010 REPEAT                          \ ----> loop back --+   |
27011 \ ------------------------------\                       |
27012 \ RC5_SampleEndOf:              \ <---------------------+
27013 \ ------------------------------\
27014 BIC     #$30,&TA0CTL           \ stop timer_A0
27015 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
27016 \ ******************************\
27017 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
27018 \ ******************************\
27019 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
27020 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
27021 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
27022 BIT     #BIT13,X                \ X(13) = New_RC5_command
27023 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
27024 THEN                            \
27025 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
27026 \ ******************************\
27027 \ RC5_ComputeNewRC5word         \
27028 \ ******************************\
27029 SUB     #4,PSP                  \
27030 MOV     &BASE,2(PSP)            \ save variable BASE before use
27031 MOV     TOS,0(PSP)              \ save TOS before use
27032 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
27033 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
27034 \ ******************************\
27035 \ RC5_ComputeC6bit              \
27036 \ ******************************\
27037 BIT     #$4000,IP              \ test /C6 bit in IP
27038 0= IF   BIS #$40,TOS           \ set C6 bit in S
27039 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
27040 \ ******************************\
27041 \ RC5_CommandByteIsDone         \ RC5_code --
27042 \ ******************************\
27043
27044 \ ------------------------------\
27045 \ Display IR_RC5 code           \
27046 \ ------------------------------\
27047 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
27048 \ ------------------------------\
27049 LO2HI                           \ switch from assembler to FORTH
27050     ['] LCD_CLEAR IS CR         \ redirects CR
27051     ['] LCD_WrC  IS EMIT        \ redirects EMIT
27052     $10 BASE !                 \ change BASE to hexadecimal
27053     CR ." $" 2 U.R             \ print IR_RC5 code
27054     ['] (CR) IS CR              \ restore CR
27055     ['] (EMIT) IS EMIT          \ restore EMIT
27056 HI2LO                           \ switch from FORTH to assembler
27057 \ ------------------------------\
27058 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
27059 \ ------------------------------\
27060 MOV @PSP+,&BASE                 \ restore variable BASE
27061 RETI                            \ CPU is ON, GIE is OFF
27062 ENDASM                          \
27063     \ 
27064
27065 CODE START                      \
27066 \ ------------------------------\
27067 \ TB0CTL = %0000 0010 1001 0100\$3C0
27068 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
27069 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
27070 \                      --       \ID input divider \ 10 = /4
27071 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
27072 \                            -  \TBCLR TimerB Clear
27073 \                             - \TBIE
27074 \                              -\TBIFG
27075 \ --------------------------------\\
27076 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
27077 \              --                 \CM Capture Mode
27078 \                --               \CCIS
27079 \                   -             \SCS
27080 \                    --           \CLLD
27081 \                      -          \CAP
27082 \                        ---      \OUTMOD \ 011 = set/reset
27083 \                           -     \CCIE
27084 \                             -   \CCI
27085 \                              -  \OUT
27086 \                               - \COV
27087 \                                -\CCIFG
27088 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
27089 \ TB0EX0                          \$3E0 
27090 \ ------------------------------\
27091 \ set TimerB to make 50kHz PWM  \
27092 \ ------------------------------\
27093 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
27094 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
27095 \ ------------------------------\
27096 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
27097 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
27098 \ ------------------------------\
27099     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
27100     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
27101 \ ------------------------------\
27102 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
27103 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
27104 \ ------------------------------\
27105 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
27106 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
27107 \ ------------------------------\
27108     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
27109 \ ------------------------------\
27110 \ set TimerB to generate PWM for LCD_Vo
27111 \ ------------------------------\
27112     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
27113 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
27114     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
27115 \ ------------------------------\
27116     BIS.B #LCDVo,&LCDVo_DIR     \
27117     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
27118 \ ------------------------------\
27119     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
27120     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
27121 \ ------------------------------\
27122     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
27123     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
27124 \ ------------------------------\
27125 \ WDT interval init part        \
27126 \ ------------------------------\
27127     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
27128 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
27129 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
27130     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
27131 \ ------------------------------\
27132 \ init RC5_Int                  \
27133 \ ------------------------------\
27134     BIS.B #RC5,&IR_IE           \ enable RC5_Int
27135     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
27136 \ ------------------------------\
27137 \ init interrupt vectors
27138 \ ------------------------------\
27139     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
27140     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
27141 \ ------------------------------\
27142 \ define LPM mode for ACCEPT    \
27143 \ ------------------------------\
27144 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
27145 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
27146 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
27147
27148 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
27149
27150 \ ------------------------------\
27151 \ Init LCD 2x20                 \
27152 \ ------------------------------\
27153     $03E8 20_US                \ 1-  wait 20 ms
27154     $03 TOP_LCD                \ 2- send DB5=DB4=1
27155     $CD 20_US                  \ 3- wait 4,1 ms
27156     $03 TOP_LCD                \ 4- send again DB5=DB4=1
27157     $5 20_US                   \ 5- wait 0,1 ms
27158     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
27159     $2 20_US                   \    wait 40 us = LCD cycle
27160     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
27161     $2 20_US                   \    wait 40 us = LCD cycle
27162     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
27163     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
27164     LCD_Clear                   \ 10- "LCD_Clear"
27165     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
27166     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
27167     LCD_Clear                   \ 10- "LCD_Clear"
27168     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
27169     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
27170     CR ." I love you"   
27171     ['] (CR) IS CR              \ ' (CR) is CR
27172     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
27173     CR
27174     ."    RC5toLCD is running. Type STOP to quit"
27175 \    NOECHO                      \ uncomment to run this app without terminal connexion
27176     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
27177     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
27178 ;
27179     \
27180
27181 : STOP                  \ stops multitasking, must to be used before downloading app
27182     ['] (WARM) IS WARM  \ remove START app from FORTH init process
27183     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
27184 ;
27185     \
27186
27187
27188 RST_STATE   ;
27189
27190
27191 CODE MAX    \    n1 n2 -- n3       signed maximum
27192             CMP     @PSP,TOS    \ n2-n1
27193             S<      ?GOTO FW1   \ n2<n1
27194 BW1         ADD     #2,PSP
27195             MOV     @IP+,PC
27196 ENDCODE
27197     \
27198
27199 CODE MIN    \    n1 n2 -- n3       signed minimum
27200             CMP     @PSP,TOS     \ n2-n1
27201             S<      ?GOTO BW1    \ n2<n1
27202 FW1         MOV     @PSP+,TOS
27203             MOV     @IP+,PC
27204 ENDCODE
27205     \
27206
27207 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
27208   >R  <# 0 # #S #>  
27209   R> OVER - 0 MAX SPACES TYPE
27210 ;
27211     \
27212
27213 CODE 20_US                      \ n --      n * 20 us
27214 BEGIN                           \ 3 cycles loop + 6~  
27215 \    MOV     #5,W                \ 3 MCLK = 1 MHz
27216 \    MOV     #23,W               \ 3 MCLK = 4 MHz
27217     MOV     #51,W               \ 3 MCLK = 8 MHz
27218 \    MOV     #104,W              \ 3 MCLK = 16 MHz
27219 \    MOV     #158,W              \ 3 MCLK = 24 MHz
27220     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
27221         SUB #1,W                \ 1
27222     0= UNTIL                    \ 2
27223     SUB     #1,TOS              \ 1
27224 0= UNTIL                        \ 2
27225     MOV     @PSP+,TOS           \ 2
27226     MOV     @IP+,PC             \ 4
27227 ENDCODE
27228     \
27229
27230 CODE TOP_LCD                    \ LCD Sample
27231 \                               \ if write : %xxxxWWWW --
27232 \                               \ if read  : -- %0000RRRR
27233     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
27234     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
27235 0= IF                           \ write LCD bits pattern
27236     AND.B #LCD_DB,TOS           \ 
27237     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
27238     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
27239     MOV @PSP+,TOS               \
27240     MOV @IP+,PC
27241 THEN                            \ read LCD bits pattern
27242     SUB #2,PSP
27243     MOV TOS,0(PSP)
27244     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
27245     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
27246     AND.B #LCD_DB,TOS           \
27247     MOV @IP+,PC
27248 ENDCODE
27249     \
27250
27251 CODE LCD_W                      \ byte --       write byte to LCD 
27252     SUB #2,PSP                  \
27253     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
27254     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
27255     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
27256     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
27257 COLON                           \ high level word starts here 
27258     TOP_LCD 2 20_US             \ write high nibble first
27259     TOP_LCD 2 20_US 
27260 ;
27261     \
27262
27263 CODE LCD_WrC                    \ char --         Write Char
27264     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
27265     JMP LCD_W 
27266 ENDCODE
27267     \
27268
27269 CODE LCD_WrF                    \ func --         Write Fonction
27270     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
27271     JMP LCD_W 
27272 ENDCODE
27273     \
27274
27275 : LCD_Clear 
27276     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
27277 ;
27278     \
27279
27280 : LCD_Home 
27281     $02 LCD_WrF 100 20_us 
27282 ;
27283     \
27284
27285 \ : LCD_Entry_set       $04 OR LCD_WrF ;
27286
27287 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
27288
27289 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
27290
27291 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
27292
27293 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
27294
27295 \ : LCD_Goto            $80 OR LCD_WrF ;
27296
27297 \ CODE LCD_R                      \ -- byte       read byte from LCD
27298 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
27299 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
27300 \ COLON                           \ starts a FORTH word
27301 \     TOP_LCD 2 20_us             \ -- %0000HHHH
27302 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
27303 \ HI2LO                           \ switch from FORTH to assembler
27304 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
27305 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
27306 \     MOV @RSP+,IP                \ restore IP saved by COLON
27307 \     MOV @IP+,PC                 \
27308 \ ENDCODE
27309 \     \
27310
27311 \ CODE LCD_RdS                    \ -- status       Read Status
27312 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
27313 \     JMP LCD_R
27314 \ ENDCODE
27315 \     \
27316
27317 \ CODE LCD_RdC                    \ -- char         Read Char
27318 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
27319 \     JMP LCD_R
27320 \ ENDCODE
27321 \     \
27322
27323 \ -------------+------+------+------+------++---+---+---+---+---------+
27324 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
27325 \ -------------+------+------+------+------++---+---+---+---+---------+
27326 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
27327 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
27328 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
27329 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
27330 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
27331 \ -------------+------+------+------+------++---+---+---+---+---------+
27332
27333
27334 \ ******************************\
27335 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
27336 \ ******************************\
27337 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
27338 \ ------------------------------\
27339 \ define LPM mode for ACCEPT    \
27340 \ ------------------------------\
27341 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
27342 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
27343 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
27344 BIT.B #SW2,&SW2_IN              \ test switch S2
27345 0= IF                           \ case of switch S2 pressed
27346     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
27347     U< IF
27348         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
27349     THEN
27350 ELSE
27351     BIT.B #SW1,&SW1_IN          \ test switch S1 input
27352     0= IF                       \ case of Switch S1 pressed
27353         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
27354         U>= IF                  \
27355             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
27356         THEN                    \
27357     THEN                        \
27358 THEN                            \
27359 RETI                            \ CPU is ON, GIE is OFF
27360 ENDASM                          \
27361     \
27362
27363
27364 \ ------------------------------\
27365 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
27366 \ ******************************\
27367 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
27368 \ ******************************\
27369 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
27370 \                               \       SMclock = 8|16|24 MHz
27371 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
27372 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
27373 \                               \       SR(9)=new Toggle bit memory (ADD on)
27374 \ ------------------------------\
27375 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
27376 \ ------------------------------\
27377 \ define LPM mode for ACCEPT    \
27378 \ ------------------------------\
27379 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
27380 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
27381 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
27382 \ ------------------------------\
27383 \ RC5_FirstStartBitHalfCycle:   \
27384 \ ------------------------------\
27385 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
27386 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
27387 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
27388 MOV     #1778,X                 \ RC5_Period in us
27389 MOV     #14,W                   \ count of loop
27390 BEGIN                           \
27391 \ ------------------------------\
27392 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
27393 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
27394     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
27395 \ RC5_Compute_3/4_Period:       \                   |
27396     RRUM    #1,X                \ X=1/2 cycle       |
27397     MOV     X,Y                 \ Y=1/2             ^
27398     RRUM    #1,Y                \ Y=1/4
27399     ADD     X,Y                 \ Y=3/4
27400 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
27401     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
27402     0= UNTIL                    \
27403 \ ------------------------------\
27404 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
27405 \ ------------------------------\
27406     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
27407     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
27408     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
27409     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
27410     SUB     #1,W                \ decrement count loop
27411 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
27412 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
27413 0<> WHILE                       \ ----> out of loop ----+
27414 \ RC5_compute_7/4_Time_out:     \                       |
27415     ADD     X,Y                 \                       |   out of bound = 7/4 period 
27416 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
27417     BEGIN                       \                       |
27418         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
27419         0>= IF                  \                       |   if cycle time out of bound
27420             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
27421             RETI                \                       |   then quit to do nothing
27422         THEN                    \                       |
27423 \ ------------------------------\                       |
27424         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
27425     0<> UNTIL                   \                   |   |
27426     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
27427 REPEAT                          \ ----> loop back --+   |
27428 \ ------------------------------\                       |
27429 \ RC5_SampleEndOf:              \ <---------------------+
27430 \ ------------------------------\
27431 BIC     #$30,&TA0CTL           \ stop timer_A0
27432 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
27433 \ ******************************\
27434 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
27435 \ ******************************\
27436 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
27437 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
27438 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
27439 BIT     #BIT13,X                \ X(13) = New_RC5_command
27440 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
27441 THEN                            \
27442 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
27443 \ ******************************\
27444 \ RC5_ComputeNewRC5word         \
27445 \ ******************************\
27446 SUB     #4,PSP                  \
27447 MOV     &BASE,2(PSP)            \ save variable BASE before use
27448 MOV     TOS,0(PSP)              \ save TOS before use
27449 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
27450 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
27451 \ ******************************\
27452 \ RC5_ComputeC6bit              \
27453 \ ******************************\
27454 BIT     #$4000,IP              \ test /C6 bit in IP
27455 0= IF   BIS #$40,TOS           \ set C6 bit in S
27456 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
27457 \ ******************************\
27458 \ RC5_CommandByteIsDone         \ RC5_code --
27459 \ ******************************\
27460
27461 \ ------------------------------\
27462 \ Display IR_RC5 code           \
27463 \ ------------------------------\
27464 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
27465 \ ------------------------------\
27466 LO2HI                           \ switch from assembler to FORTH
27467     ['] LCD_CLEAR IS CR         \ redirects CR
27468     ['] LCD_WrC  IS EMIT        \ redirects EMIT
27469     $10 BASE !                 \ change BASE to hexadecimal
27470     CR ." $" 2 U.R             \ print IR_RC5 code
27471     ['] (CR) IS CR              \ restore CR
27472     ['] (EMIT) IS EMIT          \ restore EMIT
27473 HI2LO                           \ switch from FORTH to assembler
27474 \ ------------------------------\
27475 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
27476 \ ------------------------------\
27477 MOV @PSP+,&BASE                 \ restore variable BASE
27478 RETI                            \ CPU is ON, GIE is OFF
27479 ENDASM                          \
27480     \ 
27481
27482 CODE START                      \
27483 \ ------------------------------\
27484 \ TB0CTL = %0000 0010 1001 0100\$3C0
27485 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
27486 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
27487 \                      --       \ID input divider \ 10 = /4
27488 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
27489 \                            -  \TBCLR TimerB Clear
27490 \                             - \TBIE
27491 \                              -\TBIFG
27492 \ --------------------------------\\
27493 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
27494 \              --                 \CM Capture Mode
27495 \                --               \CCIS
27496 \                   -             \SCS
27497 \                    --           \CLLD
27498 \                      -          \CAP
27499 \                        ---      \OUTMOD \ 011 = set/reset
27500 \                           -     \CCIE
27501 \                             -   \CCI
27502 \                              -  \OUT
27503 \                               - \COV
27504 \                                -\CCIFG
27505 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
27506 \ TB0EX0                          \$3E0 
27507 \ ------------------------------\
27508 \ set TimerB to make 50kHz PWM  \
27509 \ ------------------------------\
27510 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
27511 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
27512 \ ------------------------------\
27513 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
27514 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
27515 \ ------------------------------\
27516     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
27517     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
27518 \ ------------------------------\
27519 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
27520 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
27521 \ ------------------------------\
27522 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
27523 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
27524 \ ------------------------------\
27525     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
27526 \ ------------------------------\
27527 \ set TimerB to generate PWM for LCD_Vo
27528 \ ------------------------------\
27529     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
27530 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
27531     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
27532 \ ------------------------------\
27533     BIS.B #LCDVo,&LCDVo_DIR     \
27534     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
27535 \ ------------------------------\
27536     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
27537     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
27538 \ ------------------------------\
27539     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
27540     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
27541 \ ------------------------------\
27542 \ WDT interval init part        \
27543 \ ------------------------------\
27544     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
27545 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
27546 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
27547     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
27548 \ ------------------------------\
27549 \ init RC5_Int                  \
27550 \ ------------------------------\
27551     BIS.B #RC5,&IR_IE           \ enable RC5_Int
27552     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
27553 \ ------------------------------\
27554 \ init interrupt vectors
27555 \ ------------------------------\
27556     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
27557     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
27558 \ ------------------------------\
27559 \ define LPM mode for ACCEPT    \
27560 \ ------------------------------\
27561 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
27562 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
27563 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
27564
27565 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
27566
27567 \ ------------------------------\
27568 \ Init LCD 2x20                 \
27569 \ ------------------------------\
27570     $03E8 20_US                \ 1-  wait 20 ms
27571     $03 TOP_LCD                \ 2- send DB5=DB4=1
27572     $CD 20_US                  \ 3- wait 4,1 ms
27573     $03 TOP_LCD                \ 4- send again DB5=DB4=1
27574     $5 20_US                   \ 5- wait 0,1 ms
27575     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
27576     $2 20_US                   \    wait 40 us = LCD cycle
27577     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
27578     $2 20_US                   \    wait 40 us = LCD cycle
27579     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
27580     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
27581     LCD_Clear                   \ 10- "LCD_Clear"
27582     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
27583     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
27584     LCD_Clear                   \ 10- "LCD_Clear"
27585     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
27586     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
27587     CR ." I love you"   
27588     ['] (CR) IS CR              \ ' (CR) is CR
27589     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
27590     CR
27591     ."    RC5toLCD is running. Type STOP to quit"
27592 \    NOECHO                      \ uncomment to run this app without terminal connexion
27593     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
27594     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
27595 ;
27596     \
27597
27598 : STOP                  \ stops multitasking, must to be used before downloading app
27599     ['] (WARM) IS WARM  \ remove START app from FORTH init process
27600     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
27601 ;
27602     \
27603
27604
27605 RST_STATE   ;
27606
27607
27608 CODE MAX    \    n1 n2 -- n3       signed maximum
27609             CMP     @PSP,TOS    \ n2-n1
27610             S<      ?GOTO FW1   \ n2<n1
27611 BW1         ADD     #2,PSP
27612             MOV     @IP+,PC
27613 ENDCODE
27614     \
27615
27616 CODE MIN    \    n1 n2 -- n3       signed minimum
27617             CMP     @PSP,TOS     \ n2-n1
27618             S<      ?GOTO BW1    \ n2<n1
27619 FW1         MOV     @PSP+,TOS
27620             MOV     @IP+,PC
27621 ENDCODE
27622     \
27623
27624 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
27625   >R  <# 0 # #S #>  
27626   R> OVER - 0 MAX SPACES TYPE
27627 ;
27628     \
27629
27630 CODE 20_US                      \ n --      n * 20 us
27631 BEGIN                           \ 3 cycles loop + 6~  
27632 \    MOV     #5,W                \ 3 MCLK = 1 MHz
27633 \    MOV     #23,W               \ 3 MCLK = 4 MHz
27634     MOV     #51,W               \ 3 MCLK = 8 MHz
27635 \    MOV     #104,W              \ 3 MCLK = 16 MHz
27636 \    MOV     #158,W              \ 3 MCLK = 24 MHz
27637     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
27638         SUB #1,W                \ 1
27639     0= UNTIL                    \ 2
27640     SUB     #1,TOS              \ 1
27641 0= UNTIL                        \ 2
27642     MOV     @PSP+,TOS           \ 2
27643     MOV     @IP+,PC             \ 4
27644 ENDCODE
27645     \
27646
27647 CODE TOP_LCD                    \ LCD Sample
27648 \                               \ if write : %xxxxWWWW --
27649 \                               \ if read  : -- %0000RRRR
27650     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
27651     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
27652 0= IF                           \ write LCD bits pattern
27653     AND.B #LCD_DB,TOS           \ 
27654     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
27655     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
27656     MOV @PSP+,TOS               \
27657     MOV @IP+,PC
27658 THEN                            \ read LCD bits pattern
27659     SUB #2,PSP
27660     MOV TOS,0(PSP)
27661     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
27662     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
27663     AND.B #LCD_DB,TOS           \
27664     MOV @IP+,PC
27665 ENDCODE
27666     \
27667
27668 CODE LCD_W                      \ byte --       write byte to LCD 
27669     SUB #2,PSP                  \
27670     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
27671     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
27672     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
27673     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
27674 COLON                           \ high level word starts here 
27675     TOP_LCD 2 20_US             \ write high nibble first
27676     TOP_LCD 2 20_US 
27677 ;
27678     \
27679
27680 CODE LCD_WrC                    \ char --         Write Char
27681     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
27682     JMP LCD_W 
27683 ENDCODE
27684     \
27685
27686 CODE LCD_WrF                    \ func --         Write Fonction
27687     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
27688     JMP LCD_W 
27689 ENDCODE
27690     \
27691
27692 : LCD_Clear 
27693     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
27694 ;
27695     \
27696
27697 : LCD_Home 
27698     $02 LCD_WrF 100 20_us 
27699 ;
27700     \
27701
27702 \ : LCD_Entry_set       $04 OR LCD_WrF ;
27703
27704 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
27705
27706 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
27707
27708 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
27709
27710 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
27711
27712 \ : LCD_Goto            $80 OR LCD_WrF ;
27713
27714 \ CODE LCD_R                      \ -- byte       read byte from LCD
27715 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
27716 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
27717 \ COLON                           \ starts a FORTH word
27718 \     TOP_LCD 2 20_us             \ -- %0000HHHH
27719 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
27720 \ HI2LO                           \ switch from FORTH to assembler
27721 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
27722 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
27723 \     MOV @RSP+,IP                \ restore IP saved by COLON
27724 \     MOV @IP+,PC                 \
27725 \ ENDCODE
27726 \     \
27727
27728 \ CODE LCD_RdS                    \ -- status       Read Status
27729 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
27730 \     JMP LCD_R
27731 \ ENDCODE
27732 \     \
27733
27734 \ CODE LCD_RdC                    \ -- char         Read Char
27735 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
27736 \     JMP LCD_R
27737 \ ENDCODE
27738 \     \
27739
27740 \ -------------+------+------+------+------++---+---+---+---+---------+
27741 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
27742 \ -------------+------+------+------+------++---+---+---+---+---------+
27743 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
27744 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
27745 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
27746 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
27747 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
27748 \ -------------+------+------+------+------++---+---+---+---+---------+
27749
27750
27751 \ ******************************\
27752 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
27753 \ ******************************\
27754 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
27755 \ ------------------------------\
27756 \ define LPM mode for ACCEPT    \
27757 \ ------------------------------\
27758 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
27759 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
27760 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
27761 BIT.B #SW2,&SW2_IN              \ test switch S2
27762 0= IF                           \ case of switch S2 pressed
27763     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
27764     U< IF
27765         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
27766     THEN
27767 ELSE
27768     BIT.B #SW1,&SW1_IN          \ test switch S1 input
27769     0= IF                       \ case of Switch S1 pressed
27770         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
27771         U>= IF                  \
27772             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
27773         THEN                    \
27774     THEN                        \
27775 THEN                            \
27776 RETI                            \ CPU is ON, GIE is OFF
27777 ENDASM                          \
27778     \
27779
27780
27781 \ ------------------------------\
27782 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
27783 \ ******************************\
27784 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
27785 \ ******************************\
27786 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
27787 \                               \       SMclock = 8|16|24 MHz
27788 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
27789 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
27790 \                               \       SR(9)=new Toggle bit memory (ADD on)
27791 \ ------------------------------\
27792 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
27793 \ ------------------------------\
27794 \ define LPM mode for ACCEPT    \
27795 \ ------------------------------\
27796 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
27797 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
27798 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
27799 \ ------------------------------\
27800 \ RC5_FirstStartBitHalfCycle:   \
27801 \ ------------------------------\
27802 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
27803 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
27804 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
27805 MOV     #1778,X                 \ RC5_Period in us
27806 MOV     #14,W                   \ count of loop
27807 BEGIN                           \
27808 \ ------------------------------\
27809 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
27810 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
27811     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
27812 \ RC5_Compute_3/4_Period:       \                   |
27813     RRUM    #1,X                \ X=1/2 cycle       |
27814     MOV     X,Y                 \ Y=1/2             ^
27815     RRUM    #1,Y                \ Y=1/4
27816     ADD     X,Y                 \ Y=3/4
27817 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
27818     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
27819     0= UNTIL                    \
27820 \ ------------------------------\
27821 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
27822 \ ------------------------------\
27823     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
27824     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
27825     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
27826     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
27827     SUB     #1,W                \ decrement count loop
27828 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
27829 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
27830 0<> WHILE                       \ ----> out of loop ----+
27831 \ RC5_compute_7/4_Time_out:     \                       |
27832     ADD     X,Y                 \                       |   out of bound = 7/4 period 
27833 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
27834     BEGIN                       \                       |
27835         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
27836         0>= IF                  \                       |   if cycle time out of bound
27837             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
27838             RETI                \                       |   then quit to do nothing
27839         THEN                    \                       |
27840 \ ------------------------------\                       |
27841         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
27842     0<> UNTIL                   \                   |   |
27843     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
27844 REPEAT                          \ ----> loop back --+   |
27845 \ ------------------------------\                       |
27846 \ RC5_SampleEndOf:              \ <---------------------+
27847 \ ------------------------------\
27848 BIC     #$30,&TA0CTL           \ stop timer_A0
27849 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
27850 \ ******************************\
27851 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
27852 \ ******************************\
27853 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
27854 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
27855 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
27856 BIT     #BIT13,X                \ X(13) = New_RC5_command
27857 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
27858 THEN                            \
27859 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
27860 \ ******************************\
27861 \ RC5_ComputeNewRC5word         \
27862 \ ******************************\
27863 SUB     #4,PSP                  \
27864 MOV     &BASE,2(PSP)            \ save variable BASE before use
27865 MOV     TOS,0(PSP)              \ save TOS before use
27866 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
27867 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
27868 \ ******************************\
27869 \ RC5_ComputeC6bit              \
27870 \ ******************************\
27871 BIT     #$4000,IP              \ test /C6 bit in IP
27872 0= IF   BIS #$40,TOS           \ set C6 bit in S
27873 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
27874 \ ******************************\
27875 \ RC5_CommandByteIsDone         \ RC5_code --
27876 \ ******************************\
27877
27878 \ ------------------------------\
27879 \ Display IR_RC5 code           \
27880 \ ------------------------------\
27881 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
27882 \ ------------------------------\
27883 LO2HI                           \ switch from assembler to FORTH
27884     ['] LCD_CLEAR IS CR         \ redirects CR
27885     ['] LCD_WrC  IS EMIT        \ redirects EMIT
27886     $10 BASE !                 \ change BASE to hexadecimal
27887     CR ." $" 2 U.R             \ print IR_RC5 code
27888     ['] (CR) IS CR              \ restore CR
27889     ['] (EMIT) IS EMIT          \ restore EMIT
27890 HI2LO                           \ switch from FORTH to assembler
27891 \ ------------------------------\
27892 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
27893 \ ------------------------------\
27894 MOV @PSP+,&BASE                 \ restore variable BASE
27895 RETI                            \ CPU is ON, GIE is OFF
27896 ENDASM                          \
27897     \ 
27898
27899 CODE START                      \
27900 \ ------------------------------\
27901 \ TB0CTL = %0000 0010 1001 0100\$3C0
27902 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
27903 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
27904 \                      --       \ID input divider \ 10 = /4
27905 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
27906 \                            -  \TBCLR TimerB Clear
27907 \                             - \TBIE
27908 \                              -\TBIFG
27909 \ --------------------------------\\
27910 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
27911 \              --                 \CM Capture Mode
27912 \                --               \CCIS
27913 \                   -             \SCS
27914 \                    --           \CLLD
27915 \                      -          \CAP
27916 \                        ---      \OUTMOD \ 011 = set/reset
27917 \                           -     \CCIE
27918 \                             -   \CCI
27919 \                              -  \OUT
27920 \                               - \COV
27921 \                                -\CCIFG
27922 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
27923 \ TB0EX0                          \$3E0 
27924 \ ------------------------------\
27925 \ set TimerB to make 50kHz PWM  \
27926 \ ------------------------------\
27927 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
27928 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
27929 \ ------------------------------\
27930 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
27931 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
27932 \ ------------------------------\
27933     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
27934     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
27935 \ ------------------------------\
27936 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
27937 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
27938 \ ------------------------------\
27939 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
27940 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
27941 \ ------------------------------\
27942     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
27943 \ ------------------------------\
27944 \ set TimerB to generate PWM for LCD_Vo
27945 \ ------------------------------\
27946     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
27947 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
27948     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
27949 \ ------------------------------\
27950     BIS.B #LCDVo,&LCDVo_DIR     \
27951     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
27952 \ ------------------------------\
27953     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
27954     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
27955 \ ------------------------------\
27956     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
27957     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
27958 \ ------------------------------\
27959 \ WDT interval init part        \
27960 \ ------------------------------\
27961     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
27962 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
27963 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
27964     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
27965 \ ------------------------------\
27966 \ init RC5_Int                  \
27967 \ ------------------------------\
27968     BIS.B #RC5,&IR_IE           \ enable RC5_Int
27969     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
27970 \ ------------------------------\
27971 \ init interrupt vectors
27972 \ ------------------------------\
27973     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
27974     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
27975 \ ------------------------------\
27976 \ define LPM mode for ACCEPT    \
27977 \ ------------------------------\
27978 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
27979 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
27980 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
27981
27982 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
27983
27984 \ ------------------------------\
27985 \ Init LCD 2x20                 \
27986 \ ------------------------------\
27987     $03E8 20_US                \ 1-  wait 20 ms
27988     $03 TOP_LCD                \ 2- send DB5=DB4=1
27989     $CD 20_US                  \ 3- wait 4,1 ms
27990     $03 TOP_LCD                \ 4- send again DB5=DB4=1
27991     $5 20_US                   \ 5- wait 0,1 ms
27992     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
27993     $2 20_US                   \    wait 40 us = LCD cycle
27994     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
27995     $2 20_US                   \    wait 40 us = LCD cycle
27996     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
27997     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
27998     LCD_Clear                   \ 10- "LCD_Clear"
27999     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
28000     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
28001     LCD_Clear                   \ 10- "LCD_Clear"
28002     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
28003     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
28004     CR ." I love you"   
28005     ['] (CR) IS CR              \ ' (CR) is CR
28006     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
28007     CR
28008     ."    RC5toLCD is running. Type STOP to quit"
28009 \    NOECHO                      \ uncomment to run this app without terminal connexion
28010     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
28011     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
28012 ;
28013     \
28014
28015 : STOP                  \ stops multitasking, must to be used before downloading app
28016     ['] (WARM) IS WARM  \ remove START app from FORTH init process
28017     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
28018 ;
28019     \
28020
28021
28022 RST_STATE   ;
28023
28024
28025 CODE MAX    \    n1 n2 -- n3       signed maximum
28026             CMP     @PSP,TOS    \ n2-n1
28027             S<      ?GOTO FW1   \ n2<n1
28028 BW1         ADD     #2,PSP
28029             MOV     @IP+,PC
28030 ENDCODE
28031     \
28032
28033 CODE MIN    \    n1 n2 -- n3       signed minimum
28034             CMP     @PSP,TOS     \ n2-n1
28035             S<      ?GOTO BW1    \ n2<n1
28036 FW1         MOV     @PSP+,TOS
28037             MOV     @IP+,PC
28038 ENDCODE
28039     \
28040
28041 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
28042   >R  <# 0 # #S #>  
28043   R> OVER - 0 MAX SPACES TYPE
28044 ;
28045     \
28046
28047 CODE 20_US                      \ n --      n * 20 us
28048 BEGIN                           \ 3 cycles loop + 6~  
28049 \    MOV     #5,W                \ 3 MCLK = 1 MHz
28050 \    MOV     #23,W               \ 3 MCLK = 4 MHz
28051     MOV     #51,W               \ 3 MCLK = 8 MHz
28052 \    MOV     #104,W              \ 3 MCLK = 16 MHz
28053 \    MOV     #158,W              \ 3 MCLK = 24 MHz
28054     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
28055         SUB #1,W                \ 1
28056     0= UNTIL                    \ 2
28057     SUB     #1,TOS              \ 1
28058 0= UNTIL                        \ 2
28059     MOV     @PSP+,TOS           \ 2
28060     MOV     @IP+,PC             \ 4
28061 ENDCODE
28062     \
28063
28064 CODE TOP_LCD                    \ LCD Sample
28065 \                               \ if write : %xxxxWWWW --
28066 \                               \ if read  : -- %0000RRRR
28067     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
28068     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
28069 0= IF                           \ write LCD bits pattern
28070     AND.B #LCD_DB,TOS           \ 
28071     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
28072     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
28073     MOV @PSP+,TOS               \
28074     MOV @IP+,PC
28075 THEN                            \ read LCD bits pattern
28076     SUB #2,PSP
28077     MOV TOS,0(PSP)
28078     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
28079     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
28080     AND.B #LCD_DB,TOS           \
28081     MOV @IP+,PC
28082 ENDCODE
28083     \
28084
28085 CODE LCD_W                      \ byte --       write byte to LCD 
28086     SUB #2,PSP                  \
28087     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
28088     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
28089     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
28090     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
28091 COLON                           \ high level word starts here 
28092     TOP_LCD 2 20_US             \ write high nibble first
28093     TOP_LCD 2 20_US 
28094 ;
28095     \
28096
28097 CODE LCD_WrC                    \ char --         Write Char
28098     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
28099     JMP LCD_W 
28100 ENDCODE
28101     \
28102
28103 CODE LCD_WrF                    \ func --         Write Fonction
28104     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
28105     JMP LCD_W 
28106 ENDCODE
28107     \
28108
28109 : LCD_Clear 
28110     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
28111 ;
28112     \
28113
28114 : LCD_Home 
28115     $02 LCD_WrF 100 20_us 
28116 ;
28117     \
28118
28119 \ : LCD_Entry_set       $04 OR LCD_WrF ;
28120
28121 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
28122
28123 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
28124
28125 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
28126
28127 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
28128
28129 \ : LCD_Goto            $80 OR LCD_WrF ;
28130
28131 \ CODE LCD_R                      \ -- byte       read byte from LCD
28132 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
28133 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
28134 \ COLON                           \ starts a FORTH word
28135 \     TOP_LCD 2 20_us             \ -- %0000HHHH
28136 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
28137 \ HI2LO                           \ switch from FORTH to assembler
28138 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
28139 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
28140 \     MOV @RSP+,IP                \ restore IP saved by COLON
28141 \     MOV @IP+,PC                 \
28142 \ ENDCODE
28143 \     \
28144
28145 \ CODE LCD_RdS                    \ -- status       Read Status
28146 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
28147 \     JMP LCD_R
28148 \ ENDCODE
28149 \     \
28150
28151 \ CODE LCD_RdC                    \ -- char         Read Char
28152 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
28153 \     JMP LCD_R
28154 \ ENDCODE
28155 \     \
28156
28157 \ -------------+------+------+------+------++---+---+---+---+---------+
28158 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
28159 \ -------------+------+------+------+------++---+---+---+---+---------+
28160 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
28161 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
28162 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
28163 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
28164 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
28165 \ -------------+------+------+------+------++---+---+---+---+---------+
28166
28167
28168 \ ******************************\
28169 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
28170 \ ******************************\
28171 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
28172 \ ------------------------------\
28173 \ define LPM mode for ACCEPT    \
28174 \ ------------------------------\
28175 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
28176 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
28177 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
28178 BIT.B #SW2,&SW2_IN              \ test switch S2
28179 0= IF                           \ case of switch S2 pressed
28180     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
28181     U< IF
28182         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
28183     THEN
28184 ELSE
28185     BIT.B #SW1,&SW1_IN          \ test switch S1 input
28186     0= IF                       \ case of Switch S1 pressed
28187         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
28188         U>= IF                  \
28189             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
28190         THEN                    \
28191     THEN                        \
28192 THEN                            \
28193 RETI                            \ CPU is ON, GIE is OFF
28194 ENDASM                          \
28195     \
28196
28197
28198 \ ------------------------------\
28199 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
28200 \ ******************************\
28201 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
28202 \ ******************************\
28203 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
28204 \                               \       SMclock = 8|16|24 MHz
28205 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
28206 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
28207 \                               \       SR(9)=new Toggle bit memory (ADD on)
28208 \ ------------------------------\
28209 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
28210 \ ------------------------------\
28211 \ define LPM mode for ACCEPT    \
28212 \ ------------------------------\
28213 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
28214 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
28215 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
28216 \ ------------------------------\
28217 \ RC5_FirstStartBitHalfCycle:   \
28218 \ ------------------------------\
28219 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
28220 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
28221 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
28222 MOV     #1778,X                 \ RC5_Period in us
28223 MOV     #14,W                   \ count of loop
28224 BEGIN                           \
28225 \ ------------------------------\
28226 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
28227 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
28228     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
28229 \ RC5_Compute_3/4_Period:       \                   |
28230     RRUM    #1,X                \ X=1/2 cycle       |
28231     MOV     X,Y                 \ Y=1/2             ^
28232     RRUM    #1,Y                \ Y=1/4
28233     ADD     X,Y                 \ Y=3/4
28234 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
28235     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
28236     0= UNTIL                    \
28237 \ ------------------------------\
28238 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
28239 \ ------------------------------\
28240     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
28241     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
28242     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
28243     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
28244     SUB     #1,W                \ decrement count loop
28245 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
28246 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
28247 0<> WHILE                       \ ----> out of loop ----+
28248 \ RC5_compute_7/4_Time_out:     \                       |
28249     ADD     X,Y                 \                       |   out of bound = 7/4 period 
28250 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
28251     BEGIN                       \                       |
28252         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
28253         0>= IF                  \                       |   if cycle time out of bound
28254             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
28255             RETI                \                       |   then quit to do nothing
28256         THEN                    \                       |
28257 \ ------------------------------\                       |
28258         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
28259     0<> UNTIL                   \                   |   |
28260     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
28261 REPEAT                          \ ----> loop back --+   |
28262 \ ------------------------------\                       |
28263 \ RC5_SampleEndOf:              \ <---------------------+
28264 \ ------------------------------\
28265 BIC     #$30,&TA0CTL           \ stop timer_A0
28266 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
28267 \ ******************************\
28268 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
28269 \ ******************************\
28270 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
28271 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
28272 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
28273 BIT     #BIT13,X                \ X(13) = New_RC5_command
28274 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
28275 THEN                            \
28276 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
28277 \ ******************************\
28278 \ RC5_ComputeNewRC5word         \
28279 \ ******************************\
28280 SUB     #4,PSP                  \
28281 MOV     &BASE,2(PSP)            \ save variable BASE before use
28282 MOV     TOS,0(PSP)              \ save TOS before use
28283 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
28284 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
28285 \ ******************************\
28286 \ RC5_ComputeC6bit              \
28287 \ ******************************\
28288 BIT     #$4000,IP              \ test /C6 bit in IP
28289 0= IF   BIS #$40,TOS           \ set C6 bit in S
28290 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
28291 \ ******************************\
28292 \ RC5_CommandByteIsDone         \ RC5_code --
28293 \ ******************************\
28294
28295 \ ------------------------------\
28296 \ Display IR_RC5 code           \
28297 \ ------------------------------\
28298 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
28299 \ ------------------------------\
28300 LO2HI                           \ switch from assembler to FORTH
28301     ['] LCD_CLEAR IS CR         \ redirects CR
28302     ['] LCD_WrC  IS EMIT        \ redirects EMIT
28303     $10 BASE !                 \ change BASE to hexadecimal
28304     CR ." $" 2 U.R             \ print IR_RC5 code
28305     ['] (CR) IS CR              \ restore CR
28306     ['] (EMIT) IS EMIT          \ restore EMIT
28307 HI2LO                           \ switch from FORTH to assembler
28308 \ ------------------------------\
28309 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
28310 \ ------------------------------\
28311 MOV @PSP+,&BASE                 \ restore variable BASE
28312 RETI                            \ CPU is ON, GIE is OFF
28313 ENDASM                          \
28314     \ 
28315
28316 CODE START                      \
28317 \ ------------------------------\
28318 \ TB0CTL = %0000 0010 1001 0100\$3C0
28319 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
28320 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
28321 \                      --       \ID input divider \ 10 = /4
28322 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
28323 \                            -  \TBCLR TimerB Clear
28324 \                             - \TBIE
28325 \                              -\TBIFG
28326 \ --------------------------------\\
28327 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
28328 \              --                 \CM Capture Mode
28329 \                --               \CCIS
28330 \                   -             \SCS
28331 \                    --           \CLLD
28332 \                      -          \CAP
28333 \                        ---      \OUTMOD \ 011 = set/reset
28334 \                           -     \CCIE
28335 \                             -   \CCI
28336 \                              -  \OUT
28337 \                               - \COV
28338 \                                -\CCIFG
28339 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
28340 \ TB0EX0                          \$3E0 
28341 \ ------------------------------\
28342 \ set TimerB to make 50kHz PWM  \
28343 \ ------------------------------\
28344 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
28345 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
28346 \ ------------------------------\
28347 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
28348 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
28349 \ ------------------------------\
28350     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
28351     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
28352 \ ------------------------------\
28353 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
28354 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
28355 \ ------------------------------\
28356 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
28357 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
28358 \ ------------------------------\
28359     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
28360 \ ------------------------------\
28361 \ set TimerB to generate PWM for LCD_Vo
28362 \ ------------------------------\
28363     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
28364 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
28365     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
28366 \ ------------------------------\
28367     BIS.B #LCDVo,&LCDVo_DIR     \
28368     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
28369 \ ------------------------------\
28370     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
28371     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
28372 \ ------------------------------\
28373     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
28374     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
28375 \ ------------------------------\
28376 \ WDT interval init part        \
28377 \ ------------------------------\
28378     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
28379 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
28380 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
28381     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
28382 \ ------------------------------\
28383 \ init RC5_Int                  \
28384 \ ------------------------------\
28385     BIS.B #RC5,&IR_IE           \ enable RC5_Int
28386     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
28387 \ ------------------------------\
28388 \ init interrupt vectors
28389 \ ------------------------------\
28390     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
28391     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
28392 \ ------------------------------\
28393 \ define LPM mode for ACCEPT    \
28394 \ ------------------------------\
28395 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
28396 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
28397 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
28398
28399 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
28400
28401 \ ------------------------------\
28402 \ Init LCD 2x20                 \
28403 \ ------------------------------\
28404     $03E8 20_US                \ 1-  wait 20 ms
28405     $03 TOP_LCD                \ 2- send DB5=DB4=1
28406     $CD 20_US                  \ 3- wait 4,1 ms
28407     $03 TOP_LCD                \ 4- send again DB5=DB4=1
28408     $5 20_US                   \ 5- wait 0,1 ms
28409     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
28410     $2 20_US                   \    wait 40 us = LCD cycle
28411     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
28412     $2 20_US                   \    wait 40 us = LCD cycle
28413     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
28414     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
28415     LCD_Clear                   \ 10- "LCD_Clear"
28416     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
28417     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
28418     LCD_Clear                   \ 10- "LCD_Clear"
28419     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
28420     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
28421     CR ." I love you"   
28422     ['] (CR) IS CR              \ ' (CR) is CR
28423     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
28424     CR
28425     ."    RC5toLCD is running. Type STOP to quit"
28426 \    NOECHO                      \ uncomment to run this app without terminal connexion
28427     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
28428     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
28429 ;
28430     \
28431
28432 : STOP                  \ stops multitasking, must to be used before downloading app
28433     ['] (WARM) IS WARM  \ remove START app from FORTH init process
28434     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
28435 ;
28436     \
28437
28438
28439 RST_STATE   ;
28440
28441
28442 CODE MAX    \    n1 n2 -- n3       signed maximum
28443             CMP     @PSP,TOS    \ n2-n1
28444             S<      ?GOTO FW1   \ n2<n1
28445 BW1         ADD     #2,PSP
28446             MOV     @IP+,PC
28447 ENDCODE
28448     \
28449
28450 CODE MIN    \    n1 n2 -- n3       signed minimum
28451             CMP     @PSP,TOS     \ n2-n1
28452             S<      ?GOTO BW1    \ n2<n1
28453 FW1         MOV     @PSP+,TOS
28454             MOV     @IP+,PC
28455 ENDCODE
28456     \
28457
28458 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
28459   >R  <# 0 # #S #>  
28460   R> OVER - 0 MAX SPACES TYPE
28461 ;
28462     \
28463
28464 CODE 20_US                      \ n --      n * 20 us
28465 BEGIN                           \ 3 cycles loop + 6~  
28466 \    MOV     #5,W                \ 3 MCLK = 1 MHz
28467 \    MOV     #23,W               \ 3 MCLK = 4 MHz
28468     MOV     #51,W               \ 3 MCLK = 8 MHz
28469 \    MOV     #104,W              \ 3 MCLK = 16 MHz
28470 \    MOV     #158,W              \ 3 MCLK = 24 MHz
28471     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
28472         SUB #1,W                \ 1
28473     0= UNTIL                    \ 2
28474     SUB     #1,TOS              \ 1
28475 0= UNTIL                        \ 2
28476     MOV     @PSP+,TOS           \ 2
28477     MOV     @IP+,PC             \ 4
28478 ENDCODE
28479     \
28480
28481 CODE TOP_LCD                    \ LCD Sample
28482 \                               \ if write : %xxxxWWWW --
28483 \                               \ if read  : -- %0000RRRR
28484     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
28485     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
28486 0= IF                           \ write LCD bits pattern
28487     AND.B #LCD_DB,TOS           \ 
28488     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
28489     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
28490     MOV @PSP+,TOS               \
28491     MOV @IP+,PC
28492 THEN                            \ read LCD bits pattern
28493     SUB #2,PSP
28494     MOV TOS,0(PSP)
28495     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
28496     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
28497     AND.B #LCD_DB,TOS           \
28498     MOV @IP+,PC
28499 ENDCODE
28500     \
28501
28502 CODE LCD_W                      \ byte --       write byte to LCD 
28503     SUB #2,PSP                  \
28504     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
28505     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
28506     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
28507     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
28508 COLON                           \ high level word starts here 
28509     TOP_LCD 2 20_US             \ write high nibble first
28510     TOP_LCD 2 20_US 
28511 ;
28512     \
28513
28514 CODE LCD_WrC                    \ char --         Write Char
28515     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
28516     JMP LCD_W 
28517 ENDCODE
28518     \
28519
28520 CODE LCD_WrF                    \ func --         Write Fonction
28521     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
28522     JMP LCD_W 
28523 ENDCODE
28524     \
28525
28526 : LCD_Clear 
28527     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
28528 ;
28529     \
28530
28531 : LCD_Home 
28532     $02 LCD_WrF 100 20_us 
28533 ;
28534     \
28535
28536 \ : LCD_Entry_set       $04 OR LCD_WrF ;
28537
28538 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
28539
28540 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
28541
28542 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
28543
28544 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
28545
28546 \ : LCD_Goto            $80 OR LCD_WrF ;
28547
28548 \ CODE LCD_R                      \ -- byte       read byte from LCD
28549 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
28550 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
28551 \ COLON                           \ starts a FORTH word
28552 \     TOP_LCD 2 20_us             \ -- %0000HHHH
28553 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
28554 \ HI2LO                           \ switch from FORTH to assembler
28555 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
28556 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
28557 \     MOV @RSP+,IP                \ restore IP saved by COLON
28558 \     MOV @IP+,PC                 \
28559 \ ENDCODE
28560 \     \
28561
28562 \ CODE LCD_RdS                    \ -- status       Read Status
28563 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
28564 \     JMP LCD_R
28565 \ ENDCODE
28566 \     \
28567
28568 \ CODE LCD_RdC                    \ -- char         Read Char
28569 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
28570 \     JMP LCD_R
28571 \ ENDCODE
28572 \     \
28573
28574 \ -------------+------+------+------+------++---+---+---+---+---------+
28575 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
28576 \ -------------+------+------+------+------++---+---+---+---+---------+
28577 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
28578 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
28579 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
28580 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
28581 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
28582 \ -------------+------+------+------+------++---+---+---+---+---------+
28583
28584
28585 \ ******************************\
28586 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
28587 \ ******************************\
28588 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
28589 \ ------------------------------\
28590 \ define LPM mode for ACCEPT    \
28591 \ ------------------------------\
28592 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
28593 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
28594 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
28595 BIT.B #SW2,&SW2_IN              \ test switch S2
28596 0= IF                           \ case of switch S2 pressed
28597     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
28598     U< IF
28599         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
28600     THEN
28601 ELSE
28602     BIT.B #SW1,&SW1_IN          \ test switch S1 input
28603     0= IF                       \ case of Switch S1 pressed
28604         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
28605         U>= IF                  \
28606             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
28607         THEN                    \
28608     THEN                        \
28609 THEN                            \
28610 RETI                            \ CPU is ON, GIE is OFF
28611 ENDASM                          \
28612     \
28613
28614
28615 \ ------------------------------\
28616 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
28617 \ ******************************\
28618 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
28619 \ ******************************\
28620 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
28621 \                               \       SMclock = 8|16|24 MHz
28622 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
28623 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
28624 \                               \       SR(9)=new Toggle bit memory (ADD on)
28625 \ ------------------------------\
28626 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
28627 \ ------------------------------\
28628 \ define LPM mode for ACCEPT    \
28629 \ ------------------------------\
28630 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
28631 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
28632 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
28633 \ ------------------------------\
28634 \ RC5_FirstStartBitHalfCycle:   \
28635 \ ------------------------------\
28636 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
28637 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
28638 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
28639 MOV     #1778,X                 \ RC5_Period in us
28640 MOV     #14,W                   \ count of loop
28641 BEGIN                           \
28642 \ ------------------------------\
28643 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
28644 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
28645     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
28646 \ RC5_Compute_3/4_Period:       \                   |
28647     RRUM    #1,X                \ X=1/2 cycle       |
28648     MOV     X,Y                 \ Y=1/2             ^
28649     RRUM    #1,Y                \ Y=1/4
28650     ADD     X,Y                 \ Y=3/4
28651 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
28652     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
28653     0= UNTIL                    \
28654 \ ------------------------------\
28655 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
28656 \ ------------------------------\
28657     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
28658     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
28659     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
28660     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
28661     SUB     #1,W                \ decrement count loop
28662 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
28663 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
28664 0<> WHILE                       \ ----> out of loop ----+
28665 \ RC5_compute_7/4_Time_out:     \                       |
28666     ADD     X,Y                 \                       |   out of bound = 7/4 period 
28667 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
28668     BEGIN                       \                       |
28669         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
28670         0>= IF                  \                       |   if cycle time out of bound
28671             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
28672             RETI                \                       |   then quit to do nothing
28673         THEN                    \                       |
28674 \ ------------------------------\                       |
28675         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
28676     0<> UNTIL                   \                   |   |
28677     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
28678 REPEAT                          \ ----> loop back --+   |
28679 \ ------------------------------\                       |
28680 \ RC5_SampleEndOf:              \ <---------------------+
28681 \ ------------------------------\
28682 BIC     #$30,&TA0CTL           \ stop timer_A0
28683 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
28684 \ ******************************\
28685 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
28686 \ ******************************\
28687 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
28688 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
28689 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
28690 BIT     #BIT13,X                \ X(13) = New_RC5_command
28691 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
28692 THEN                            \
28693 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
28694 \ ******************************\
28695 \ RC5_ComputeNewRC5word         \
28696 \ ******************************\
28697 SUB     #4,PSP                  \
28698 MOV     &BASE,2(PSP)            \ save variable BASE before use
28699 MOV     TOS,0(PSP)              \ save TOS before use
28700 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
28701 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
28702 \ ******************************\
28703 \ RC5_ComputeC6bit              \
28704 \ ******************************\
28705 BIT     #$4000,IP              \ test /C6 bit in IP
28706 0= IF   BIS #$40,TOS           \ set C6 bit in S
28707 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
28708 \ ******************************\
28709 \ RC5_CommandByteIsDone         \ RC5_code --
28710 \ ******************************\
28711
28712 \ ------------------------------\
28713 \ Display IR_RC5 code           \
28714 \ ------------------------------\
28715 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
28716 \ ------------------------------\
28717 LO2HI                           \ switch from assembler to FORTH
28718     ['] LCD_CLEAR IS CR         \ redirects CR
28719     ['] LCD_WrC  IS EMIT        \ redirects EMIT
28720     $10 BASE !                 \ change BASE to hexadecimal
28721     CR ." $" 2 U.R             \ print IR_RC5 code
28722     ['] (CR) IS CR              \ restore CR
28723     ['] (EMIT) IS EMIT          \ restore EMIT
28724 HI2LO                           \ switch from FORTH to assembler
28725 \ ------------------------------\
28726 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
28727 \ ------------------------------\
28728 MOV @PSP+,&BASE                 \ restore variable BASE
28729 RETI                            \ CPU is ON, GIE is OFF
28730 ENDASM                          \
28731     \ 
28732
28733 CODE START                      \
28734 \ ------------------------------\
28735 \ TB0CTL = %0000 0010 1001 0100\$3C0
28736 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
28737 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
28738 \                      --       \ID input divider \ 10 = /4
28739 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
28740 \                            -  \TBCLR TimerB Clear
28741 \                             - \TBIE
28742 \                              -\TBIFG
28743 \ --------------------------------\\
28744 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
28745 \              --                 \CM Capture Mode
28746 \                --               \CCIS
28747 \                   -             \SCS
28748 \                    --           \CLLD
28749 \                      -          \CAP
28750 \                        ---      \OUTMOD \ 011 = set/reset
28751 \                           -     \CCIE
28752 \                             -   \CCI
28753 \                              -  \OUT
28754 \                               - \COV
28755 \                                -\CCIFG
28756 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
28757 \ TB0EX0                          \$3E0 
28758 \ ------------------------------\
28759 \ set TimerB to make 50kHz PWM  \
28760 \ ------------------------------\
28761 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
28762 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
28763 \ ------------------------------\
28764 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
28765 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
28766 \ ------------------------------\
28767     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
28768     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
28769 \ ------------------------------\
28770 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
28771 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
28772 \ ------------------------------\
28773 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
28774 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
28775 \ ------------------------------\
28776     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
28777 \ ------------------------------\
28778 \ set TimerB to generate PWM for LCD_Vo
28779 \ ------------------------------\
28780     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
28781 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
28782     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
28783 \ ------------------------------\
28784     BIS.B #LCDVo,&LCDVo_DIR     \
28785     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
28786 \ ------------------------------\
28787     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
28788     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
28789 \ ------------------------------\
28790     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
28791     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
28792 \ ------------------------------\
28793 \ WDT interval init part        \
28794 \ ------------------------------\
28795     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
28796 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
28797 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
28798     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
28799 \ ------------------------------\
28800 \ init RC5_Int                  \
28801 \ ------------------------------\
28802     BIS.B #RC5,&IR_IE           \ enable RC5_Int
28803     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
28804 \ ------------------------------\
28805 \ init interrupt vectors
28806 \ ------------------------------\
28807     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
28808     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
28809 \ ------------------------------\
28810 \ define LPM mode for ACCEPT    \
28811 \ ------------------------------\
28812 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
28813 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
28814 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
28815
28816 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
28817
28818 \ ------------------------------\
28819 \ Init LCD 2x20                 \
28820 \ ------------------------------\
28821     $03E8 20_US                \ 1-  wait 20 ms
28822     $03 TOP_LCD                \ 2- send DB5=DB4=1
28823     $CD 20_US                  \ 3- wait 4,1 ms
28824     $03 TOP_LCD                \ 4- send again DB5=DB4=1
28825     $5 20_US                   \ 5- wait 0,1 ms
28826     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
28827     $2 20_US                   \    wait 40 us = LCD cycle
28828     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
28829     $2 20_US                   \    wait 40 us = LCD cycle
28830     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
28831     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
28832     LCD_Clear                   \ 10- "LCD_Clear"
28833     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
28834     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
28835     LCD_Clear                   \ 10- "LCD_Clear"
28836     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
28837     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
28838     CR ." I love you"   
28839     ['] (CR) IS CR              \ ' (CR) is CR
28840     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
28841     CR
28842     ."    RC5toLCD is running. Type STOP to quit"
28843 \    NOECHO                      \ uncomment to run this app without terminal connexion
28844     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
28845     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
28846 ;
28847     \
28848
28849 : STOP                  \ stops multitasking, must to be used before downloading app
28850     ['] (WARM) IS WARM  \ remove START app from FORTH init process
28851     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
28852 ;
28853     \
28854
28855
28856 RST_STATE   ;
28857
28858
28859 CODE MAX    \    n1 n2 -- n3       signed maximum
28860             CMP     @PSP,TOS    \ n2-n1
28861             S<      ?GOTO FW1   \ n2<n1
28862 BW1         ADD     #2,PSP
28863             MOV     @IP+,PC
28864 ENDCODE
28865     \
28866
28867 CODE MIN    \    n1 n2 -- n3       signed minimum
28868             CMP     @PSP,TOS     \ n2-n1
28869             S<      ?GOTO BW1    \ n2<n1
28870 FW1         MOV     @PSP+,TOS
28871             MOV     @IP+,PC
28872 ENDCODE
28873     \
28874
28875 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
28876   >R  <# 0 # #S #>  
28877   R> OVER - 0 MAX SPACES TYPE
28878 ;
28879     \
28880
28881 CODE 20_US                      \ n --      n * 20 us
28882 BEGIN                           \ 3 cycles loop + 6~  
28883 \    MOV     #5,W                \ 3 MCLK = 1 MHz
28884 \    MOV     #23,W               \ 3 MCLK = 4 MHz
28885     MOV     #51,W               \ 3 MCLK = 8 MHz
28886 \    MOV     #104,W              \ 3 MCLK = 16 MHz
28887 \    MOV     #158,W              \ 3 MCLK = 24 MHz
28888     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
28889         SUB #1,W                \ 1
28890     0= UNTIL                    \ 2
28891     SUB     #1,TOS              \ 1
28892 0= UNTIL                        \ 2
28893     MOV     @PSP+,TOS           \ 2
28894     MOV     @IP+,PC             \ 4
28895 ENDCODE
28896     \
28897
28898 CODE TOP_LCD                    \ LCD Sample
28899 \                               \ if write : %xxxxWWWW --
28900 \                               \ if read  : -- %0000RRRR
28901     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
28902     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
28903 0= IF                           \ write LCD bits pattern
28904     AND.B #LCD_DB,TOS           \ 
28905     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
28906     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
28907     MOV @PSP+,TOS               \
28908     MOV @IP+,PC
28909 THEN                            \ read LCD bits pattern
28910     SUB #2,PSP
28911     MOV TOS,0(PSP)
28912     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
28913     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
28914     AND.B #LCD_DB,TOS           \
28915     MOV @IP+,PC
28916 ENDCODE
28917     \
28918
28919 CODE LCD_W                      \ byte --       write byte to LCD 
28920     SUB #2,PSP                  \
28921     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
28922     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
28923     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
28924     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
28925 COLON                           \ high level word starts here 
28926     TOP_LCD 2 20_US             \ write high nibble first
28927     TOP_LCD 2 20_US 
28928 ;
28929     \
28930
28931 CODE LCD_WrC                    \ char --         Write Char
28932     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
28933     JMP LCD_W 
28934 ENDCODE
28935     \
28936
28937 CODE LCD_WrF                    \ func --         Write Fonction
28938     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
28939     JMP LCD_W 
28940 ENDCODE
28941     \
28942
28943 : LCD_Clear 
28944     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
28945 ;
28946     \
28947
28948 : LCD_Home 
28949     $02 LCD_WrF 100 20_us 
28950 ;
28951     \
28952
28953 \ : LCD_Entry_set       $04 OR LCD_WrF ;
28954
28955 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
28956
28957 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
28958
28959 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
28960
28961 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
28962
28963 \ : LCD_Goto            $80 OR LCD_WrF ;
28964
28965 \ CODE LCD_R                      \ -- byte       read byte from LCD
28966 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
28967 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
28968 \ COLON                           \ starts a FORTH word
28969 \     TOP_LCD 2 20_us             \ -- %0000HHHH
28970 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
28971 \ HI2LO                           \ switch from FORTH to assembler
28972 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
28973 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
28974 \     MOV @RSP+,IP                \ restore IP saved by COLON
28975 \     MOV @IP+,PC                 \
28976 \ ENDCODE
28977 \     \
28978
28979 \ CODE LCD_RdS                    \ -- status       Read Status
28980 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
28981 \     JMP LCD_R
28982 \ ENDCODE
28983 \     \
28984
28985 \ CODE LCD_RdC                    \ -- char         Read Char
28986 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
28987 \     JMP LCD_R
28988 \ ENDCODE
28989 \     \
28990
28991 \ -------------+------+------+------+------++---+---+---+---+---------+
28992 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
28993 \ -------------+------+------+------+------++---+---+---+---+---------+
28994 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
28995 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
28996 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
28997 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
28998 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
28999 \ -------------+------+------+------+------++---+---+---+---+---------+
29000
29001
29002 \ ******************************\
29003 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
29004 \ ******************************\
29005 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
29006 \ ------------------------------\
29007 \ define LPM mode for ACCEPT    \
29008 \ ------------------------------\
29009 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
29010 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
29011 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
29012 BIT.B #SW2,&SW2_IN              \ test switch S2
29013 0= IF                           \ case of switch S2 pressed
29014     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
29015     U< IF
29016         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
29017     THEN
29018 ELSE
29019     BIT.B #SW1,&SW1_IN          \ test switch S1 input
29020     0= IF                       \ case of Switch S1 pressed
29021         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
29022         U>= IF                  \
29023             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
29024         THEN                    \
29025     THEN                        \
29026 THEN                            \
29027 RETI                            \ CPU is ON, GIE is OFF
29028 ENDASM                          \
29029     \
29030
29031
29032 \ ------------------------------\
29033 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
29034 \ ******************************\
29035 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
29036 \ ******************************\
29037 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
29038 \                               \       SMclock = 8|16|24 MHz
29039 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
29040 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
29041 \                               \       SR(9)=new Toggle bit memory (ADD on)
29042 \ ------------------------------\
29043 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
29044 \ ------------------------------\
29045 \ define LPM mode for ACCEPT    \
29046 \ ------------------------------\
29047 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
29048 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
29049 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
29050 \ ------------------------------\
29051 \ RC5_FirstStartBitHalfCycle:   \
29052 \ ------------------------------\
29053 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
29054 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
29055 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
29056 MOV     #1778,X                 \ RC5_Period in us
29057 MOV     #14,W                   \ count of loop
29058 BEGIN                           \
29059 \ ------------------------------\
29060 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
29061 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
29062     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
29063 \ RC5_Compute_3/4_Period:       \                   |
29064     RRUM    #1,X                \ X=1/2 cycle       |
29065     MOV     X,Y                 \ Y=1/2             ^
29066     RRUM    #1,Y                \ Y=1/4
29067     ADD     X,Y                 \ Y=3/4
29068 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
29069     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
29070     0= UNTIL                    \
29071 \ ------------------------------\
29072 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
29073 \ ------------------------------\
29074     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
29075     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
29076     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
29077     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
29078     SUB     #1,W                \ decrement count loop
29079 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
29080 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
29081 0<> WHILE                       \ ----> out of loop ----+
29082 \ RC5_compute_7/4_Time_out:     \                       |
29083     ADD     X,Y                 \                       |   out of bound = 7/4 period 
29084 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
29085     BEGIN                       \                       |
29086         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
29087         0>= IF                  \                       |   if cycle time out of bound
29088             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
29089             RETI                \                       |   then quit to do nothing
29090         THEN                    \                       |
29091 \ ------------------------------\                       |
29092         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
29093     0<> UNTIL                   \                   |   |
29094     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
29095 REPEAT                          \ ----> loop back --+   |
29096 \ ------------------------------\                       |
29097 \ RC5_SampleEndOf:              \ <---------------------+
29098 \ ------------------------------\
29099 BIC     #$30,&TA0CTL           \ stop timer_A0
29100 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
29101 \ ******************************\
29102 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
29103 \ ******************************\
29104 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
29105 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
29106 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
29107 BIT     #BIT13,X                \ X(13) = New_RC5_command
29108 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
29109 THEN                            \
29110 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
29111 \ ******************************\
29112 \ RC5_ComputeNewRC5word         \
29113 \ ******************************\
29114 SUB     #4,PSP                  \
29115 MOV     &BASE,2(PSP)            \ save variable BASE before use
29116 MOV     TOS,0(PSP)              \ save TOS before use
29117 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
29118 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
29119 \ ******************************\
29120 \ RC5_ComputeC6bit              \
29121 \ ******************************\
29122 BIT     #$4000,IP              \ test /C6 bit in IP
29123 0= IF   BIS #$40,TOS           \ set C6 bit in S
29124 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
29125 \ ******************************\
29126 \ RC5_CommandByteIsDone         \ RC5_code --
29127 \ ******************************\
29128
29129 \ ------------------------------\
29130 \ Display IR_RC5 code           \
29131 \ ------------------------------\
29132 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
29133 \ ------------------------------\
29134 LO2HI                           \ switch from assembler to FORTH
29135     ['] LCD_CLEAR IS CR         \ redirects CR
29136     ['] LCD_WrC  IS EMIT        \ redirects EMIT
29137     $10 BASE !                 \ change BASE to hexadecimal
29138     CR ." $" 2 U.R             \ print IR_RC5 code
29139     ['] (CR) IS CR              \ restore CR
29140     ['] (EMIT) IS EMIT          \ restore EMIT
29141 HI2LO                           \ switch from FORTH to assembler
29142 \ ------------------------------\
29143 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
29144 \ ------------------------------\
29145 MOV @PSP+,&BASE                 \ restore variable BASE
29146 RETI                            \ CPU is ON, GIE is OFF
29147 ENDASM                          \
29148     \ 
29149
29150 CODE START                      \
29151 \ ------------------------------\
29152 \ TB0CTL = %0000 0010 1001 0100\$3C0
29153 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
29154 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
29155 \                      --       \ID input divider \ 10 = /4
29156 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
29157 \                            -  \TBCLR TimerB Clear
29158 \                             - \TBIE
29159 \                              -\TBIFG
29160 \ --------------------------------\\
29161 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
29162 \              --                 \CM Capture Mode
29163 \                --               \CCIS
29164 \                   -             \SCS
29165 \                    --           \CLLD
29166 \                      -          \CAP
29167 \                        ---      \OUTMOD \ 011 = set/reset
29168 \                           -     \CCIE
29169 \                             -   \CCI
29170 \                              -  \OUT
29171 \                               - \COV
29172 \                                -\CCIFG
29173 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
29174 \ TB0EX0                          \$3E0 
29175 \ ------------------------------\
29176 \ set TimerB to make 50kHz PWM  \
29177 \ ------------------------------\
29178 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
29179 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
29180 \ ------------------------------\
29181 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
29182 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
29183 \ ------------------------------\
29184     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
29185     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
29186 \ ------------------------------\
29187 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
29188 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
29189 \ ------------------------------\
29190 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
29191 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
29192 \ ------------------------------\
29193     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
29194 \ ------------------------------\
29195 \ set TimerB to generate PWM for LCD_Vo
29196 \ ------------------------------\
29197     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
29198 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
29199     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
29200 \ ------------------------------\
29201     BIS.B #LCDVo,&LCDVo_DIR     \
29202     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
29203 \ ------------------------------\
29204     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
29205     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
29206 \ ------------------------------\
29207     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
29208     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
29209 \ ------------------------------\
29210 \ WDT interval init part        \
29211 \ ------------------------------\
29212     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
29213 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
29214 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
29215     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
29216 \ ------------------------------\
29217 \ init RC5_Int                  \
29218 \ ------------------------------\
29219     BIS.B #RC5,&IR_IE           \ enable RC5_Int
29220     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
29221 \ ------------------------------\
29222 \ init interrupt vectors
29223 \ ------------------------------\
29224     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
29225     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
29226 \ ------------------------------\
29227 \ define LPM mode for ACCEPT    \
29228 \ ------------------------------\
29229 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
29230 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
29231 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
29232
29233 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
29234
29235 \ ------------------------------\
29236 \ Init LCD 2x20                 \
29237 \ ------------------------------\
29238     $03E8 20_US                \ 1-  wait 20 ms
29239     $03 TOP_LCD                \ 2- send DB5=DB4=1
29240     $CD 20_US                  \ 3- wait 4,1 ms
29241     $03 TOP_LCD                \ 4- send again DB5=DB4=1
29242     $5 20_US                   \ 5- wait 0,1 ms
29243     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
29244     $2 20_US                   \    wait 40 us = LCD cycle
29245     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
29246     $2 20_US                   \    wait 40 us = LCD cycle
29247     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
29248     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
29249     LCD_Clear                   \ 10- "LCD_Clear"
29250     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
29251     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
29252     LCD_Clear                   \ 10- "LCD_Clear"
29253     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
29254     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
29255     CR ." I love you"   
29256     ['] (CR) IS CR              \ ' (CR) is CR
29257     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
29258     CR
29259     ."    RC5toLCD is running. Type STOP to quit"
29260 \    NOECHO                      \ uncomment to run this app without terminal connexion
29261     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
29262     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
29263 ;
29264     \
29265
29266 : STOP                  \ stops multitasking, must to be used before downloading app
29267     ['] (WARM) IS WARM  \ remove START app from FORTH init process
29268     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
29269 ;
29270     \
29271
29272
29273 RST_STATE   ;
29274
29275
29276 CODE MAX    \    n1 n2 -- n3       signed maximum
29277             CMP     @PSP,TOS    \ n2-n1
29278             S<      ?GOTO FW1   \ n2<n1
29279 BW1         ADD     #2,PSP
29280             MOV     @IP+,PC
29281 ENDCODE
29282     \
29283
29284 CODE MIN    \    n1 n2 -- n3       signed minimum
29285             CMP     @PSP,TOS     \ n2-n1
29286             S<      ?GOTO BW1    \ n2<n1
29287 FW1         MOV     @PSP+,TOS
29288             MOV     @IP+,PC
29289 ENDCODE
29290     \
29291
29292 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
29293   >R  <# 0 # #S #>  
29294   R> OVER - 0 MAX SPACES TYPE
29295 ;
29296     \
29297
29298 CODE 20_US                      \ n --      n * 20 us
29299 BEGIN                           \ 3 cycles loop + 6~  
29300 \    MOV     #5,W                \ 3 MCLK = 1 MHz
29301 \    MOV     #23,W               \ 3 MCLK = 4 MHz
29302     MOV     #51,W               \ 3 MCLK = 8 MHz
29303 \    MOV     #104,W              \ 3 MCLK = 16 MHz
29304 \    MOV     #158,W              \ 3 MCLK = 24 MHz
29305     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
29306         SUB #1,W                \ 1
29307     0= UNTIL                    \ 2
29308     SUB     #1,TOS              \ 1
29309 0= UNTIL                        \ 2
29310     MOV     @PSP+,TOS           \ 2
29311     MOV     @IP+,PC             \ 4
29312 ENDCODE
29313     \
29314
29315 CODE TOP_LCD                    \ LCD Sample
29316 \                               \ if write : %xxxxWWWW --
29317 \                               \ if read  : -- %0000RRRR
29318     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
29319     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
29320 0= IF                           \ write LCD bits pattern
29321     AND.B #LCD_DB,TOS           \ 
29322     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
29323     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
29324     MOV @PSP+,TOS               \
29325     MOV @IP+,PC
29326 THEN                            \ read LCD bits pattern
29327     SUB #2,PSP
29328     MOV TOS,0(PSP)
29329     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
29330     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
29331     AND.B #LCD_DB,TOS           \
29332     MOV @IP+,PC
29333 ENDCODE
29334     \
29335
29336 CODE LCD_W                      \ byte --       write byte to LCD 
29337     SUB #2,PSP                  \
29338     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
29339     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
29340     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
29341     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
29342 COLON                           \ high level word starts here 
29343     TOP_LCD 2 20_US             \ write high nibble first
29344     TOP_LCD 2 20_US 
29345 ;
29346     \
29347
29348 CODE LCD_WrC                    \ char --         Write Char
29349     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
29350     JMP LCD_W 
29351 ENDCODE
29352     \
29353
29354 CODE LCD_WrF                    \ func --         Write Fonction
29355     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
29356     JMP LCD_W 
29357 ENDCODE
29358     \
29359
29360 : LCD_Clear 
29361     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
29362 ;
29363     \
29364
29365 : LCD_Home 
29366     $02 LCD_WrF 100 20_us 
29367 ;
29368     \
29369
29370 \ : LCD_Entry_set       $04 OR LCD_WrF ;
29371
29372 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
29373
29374 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
29375
29376 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
29377
29378 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
29379
29380 \ : LCD_Goto            $80 OR LCD_WrF ;
29381
29382 \ CODE LCD_R                      \ -- byte       read byte from LCD
29383 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
29384 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
29385 \ COLON                           \ starts a FORTH word
29386 \     TOP_LCD 2 20_us             \ -- %0000HHHH
29387 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
29388 \ HI2LO                           \ switch from FORTH to assembler
29389 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
29390 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
29391 \     MOV @RSP+,IP                \ restore IP saved by COLON
29392 \     MOV @IP+,PC                 \
29393 \ ENDCODE
29394 \     \
29395
29396 \ CODE LCD_RdS                    \ -- status       Read Status
29397 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
29398 \     JMP LCD_R
29399 \ ENDCODE
29400 \     \
29401
29402 \ CODE LCD_RdC                    \ -- char         Read Char
29403 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
29404 \     JMP LCD_R
29405 \ ENDCODE
29406 \     \
29407
29408 \ -------------+------+------+------+------++---+---+---+---+---------+
29409 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
29410 \ -------------+------+------+------+------++---+---+---+---+---------+
29411 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
29412 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
29413 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
29414 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
29415 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
29416 \ -------------+------+------+------+------++---+---+---+---+---------+
29417
29418
29419 \ ******************************\
29420 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
29421 \ ******************************\
29422 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
29423 \ ------------------------------\
29424 \ define LPM mode for ACCEPT    \
29425 \ ------------------------------\
29426 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
29427 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
29428 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
29429 BIT.B #SW2,&SW2_IN              \ test switch S2
29430 0= IF                           \ case of switch S2 pressed
29431     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
29432     U< IF
29433         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
29434     THEN
29435 ELSE
29436     BIT.B #SW1,&SW1_IN          \ test switch S1 input
29437     0= IF                       \ case of Switch S1 pressed
29438         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
29439         U>= IF                  \
29440             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
29441         THEN                    \
29442     THEN                        \
29443 THEN                            \
29444 RETI                            \ CPU is ON, GIE is OFF
29445 ENDASM                          \
29446     \
29447
29448
29449 \ ------------------------------\
29450 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
29451 \ ******************************\
29452 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
29453 \ ******************************\
29454 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
29455 \                               \       SMclock = 8|16|24 MHz
29456 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
29457 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
29458 \                               \       SR(9)=new Toggle bit memory (ADD on)
29459 \ ------------------------------\
29460 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
29461 \ ------------------------------\
29462 \ define LPM mode for ACCEPT    \
29463 \ ------------------------------\
29464 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
29465 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
29466 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
29467 \ ------------------------------\
29468 \ RC5_FirstStartBitHalfCycle:   \
29469 \ ------------------------------\
29470 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
29471 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
29472 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
29473 MOV     #1778,X                 \ RC5_Period in us
29474 MOV     #14,W                   \ count of loop
29475 BEGIN                           \
29476 \ ------------------------------\
29477 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
29478 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
29479     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
29480 \ RC5_Compute_3/4_Period:       \                   |
29481     RRUM    #1,X                \ X=1/2 cycle       |
29482     MOV     X,Y                 \ Y=1/2             ^
29483     RRUM    #1,Y                \ Y=1/4
29484     ADD     X,Y                 \ Y=3/4
29485 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
29486     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
29487     0= UNTIL                    \
29488 \ ------------------------------\
29489 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
29490 \ ------------------------------\
29491     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
29492     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
29493     MOV     &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 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
29497 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
29498 0<> WHILE                       \ ----> out of loop ----+
29499 \ RC5_compute_7/4_Time_out:     \                       |
29500     ADD     X,Y                 \                       |   out of bound = 7/4 period 
29501 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
29502     BEGIN                       \                       |
29503         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
29504         0>= IF                  \                       |   if cycle time out of bound
29505             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
29506             RETI                \                       |   then quit to do nothing
29507         THEN                    \                       |
29508 \ ------------------------------\                       |
29509         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
29510     0<> UNTIL                   \                   |   |
29511     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
29512 REPEAT                          \ ----> loop back --+   |
29513 \ ------------------------------\                       |
29514 \ RC5_SampleEndOf:              \ <---------------------+
29515 \ ------------------------------\
29516 BIC     #$30,&TA0CTL           \ stop timer_A0
29517 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
29518 \ ******************************\
29519 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
29520 \ ******************************\
29521 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
29522 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
29523 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
29524 BIT     #BIT13,X                \ X(13) = New_RC5_command
29525 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
29526 THEN                            \
29527 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
29528 \ ******************************\
29529 \ RC5_ComputeNewRC5word         \
29530 \ ******************************\
29531 SUB     #4,PSP                  \
29532 MOV     &BASE,2(PSP)            \ save variable BASE before use
29533 MOV     TOS,0(PSP)              \ save TOS before use
29534 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
29535 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
29536 \ ******************************\
29537 \ RC5_ComputeC6bit              \
29538 \ ******************************\
29539 BIT     #$4000,IP              \ test /C6 bit in IP
29540 0= IF   BIS #$40,TOS           \ set C6 bit in S
29541 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
29542 \ ******************************\
29543 \ RC5_CommandByteIsDone         \ RC5_code --
29544 \ ******************************\
29545
29546 \ ------------------------------\
29547 \ Display IR_RC5 code           \
29548 \ ------------------------------\
29549 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
29550 \ ------------------------------\
29551 LO2HI                           \ switch from assembler to FORTH
29552     ['] LCD_CLEAR IS CR         \ redirects CR
29553     ['] LCD_WrC  IS EMIT        \ redirects EMIT
29554     $10 BASE !                 \ change BASE to hexadecimal
29555     CR ." $" 2 U.R             \ print IR_RC5 code
29556     ['] (CR) IS CR              \ restore CR
29557     ['] (EMIT) IS EMIT          \ restore EMIT
29558 HI2LO                           \ switch from FORTH to assembler
29559 \ ------------------------------\
29560 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
29561 \ ------------------------------\
29562 MOV @PSP+,&BASE                 \ restore variable BASE
29563 RETI                            \ CPU is ON, GIE is OFF
29564 ENDASM                          \
29565     \ 
29566
29567 CODE START                      \
29568 \ ------------------------------\
29569 \ TB0CTL = %0000 0010 1001 0100\$3C0
29570 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
29571 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
29572 \                      --       \ID input divider \ 10 = /4
29573 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
29574 \                            -  \TBCLR TimerB Clear
29575 \                             - \TBIE
29576 \                              -\TBIFG
29577 \ --------------------------------\\
29578 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
29579 \              --                 \CM Capture Mode
29580 \                --               \CCIS
29581 \                   -             \SCS
29582 \                    --           \CLLD
29583 \                      -          \CAP
29584 \                        ---      \OUTMOD \ 011 = set/reset
29585 \                           -     \CCIE
29586 \                             -   \CCI
29587 \                              -  \OUT
29588 \                               - \COV
29589 \                                -\CCIFG
29590 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
29591 \ TB0EX0                          \$3E0 
29592 \ ------------------------------\
29593 \ set TimerB to make 50kHz PWM  \
29594 \ ------------------------------\
29595 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
29596 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
29597 \ ------------------------------\
29598 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
29599 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
29600 \ ------------------------------\
29601     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
29602     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
29603 \ ------------------------------\
29604 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
29605 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
29606 \ ------------------------------\
29607 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
29608 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
29609 \ ------------------------------\
29610     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
29611 \ ------------------------------\
29612 \ set TimerB to generate PWM for LCD_Vo
29613 \ ------------------------------\
29614     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
29615 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
29616     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
29617 \ ------------------------------\
29618     BIS.B #LCDVo,&LCDVo_DIR     \
29619     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
29620 \ ------------------------------\
29621     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
29622     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
29623 \ ------------------------------\
29624     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
29625     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
29626 \ ------------------------------\
29627 \ WDT interval init part        \
29628 \ ------------------------------\
29629     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
29630 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
29631 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
29632     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
29633 \ ------------------------------\
29634 \ init RC5_Int                  \
29635 \ ------------------------------\
29636     BIS.B #RC5,&IR_IE           \ enable RC5_Int
29637     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
29638 \ ------------------------------\
29639 \ init interrupt vectors
29640 \ ------------------------------\
29641     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
29642     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
29643 \ ------------------------------\
29644 \ define LPM mode for ACCEPT    \
29645 \ ------------------------------\
29646 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
29647 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
29648 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
29649
29650 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
29651
29652 \ ------------------------------\
29653 \ Init LCD 2x20                 \
29654 \ ------------------------------\
29655     $03E8 20_US                \ 1-  wait 20 ms
29656     $03 TOP_LCD                \ 2- send DB5=DB4=1
29657     $CD 20_US                  \ 3- wait 4,1 ms
29658     $03 TOP_LCD                \ 4- send again DB5=DB4=1
29659     $5 20_US                   \ 5- wait 0,1 ms
29660     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
29661     $2 20_US                   \    wait 40 us = LCD cycle
29662     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
29663     $2 20_US                   \    wait 40 us = LCD cycle
29664     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
29665     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
29666     LCD_Clear                   \ 10- "LCD_Clear"
29667     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
29668     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
29669     LCD_Clear                   \ 10- "LCD_Clear"
29670     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
29671     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
29672     CR ." I love you"   
29673     ['] (CR) IS CR              \ ' (CR) is CR
29674     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
29675     CR
29676     ."    RC5toLCD is running. Type STOP to quit"
29677 \    NOECHO                      \ uncomment to run this app without terminal connexion
29678     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
29679     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
29680 ;
29681     \
29682
29683 : STOP                  \ stops multitasking, must to be used before downloading app
29684     ['] (WARM) IS WARM  \ remove START app from FORTH init process
29685     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
29686 ;
29687     \
29688
29689
29690 RST_STATE   ;
29691
29692
29693 CODE MAX    \    n1 n2 -- n3       signed maximum
29694             CMP     @PSP,TOS    \ n2-n1
29695             S<      ?GOTO FW1   \ n2<n1
29696 BW1         ADD     #2,PSP
29697             MOV     @IP+,PC
29698 ENDCODE
29699     \
29700
29701 CODE MIN    \    n1 n2 -- n3       signed minimum
29702             CMP     @PSP,TOS     \ n2-n1
29703             S<      ?GOTO BW1    \ n2<n1
29704 FW1         MOV     @PSP+,TOS
29705             MOV     @IP+,PC
29706 ENDCODE
29707     \
29708
29709 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
29710   >R  <# 0 # #S #>  
29711   R> OVER - 0 MAX SPACES TYPE
29712 ;
29713     \
29714
29715 CODE 20_US                      \ n --      n * 20 us
29716 BEGIN                           \ 3 cycles loop + 6~  
29717 \    MOV     #5,W                \ 3 MCLK = 1 MHz
29718 \    MOV     #23,W               \ 3 MCLK = 4 MHz
29719     MOV     #51,W               \ 3 MCLK = 8 MHz
29720 \    MOV     #104,W              \ 3 MCLK = 16 MHz
29721 \    MOV     #158,W              \ 3 MCLK = 24 MHz
29722     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
29723         SUB #1,W                \ 1
29724     0= UNTIL                    \ 2
29725     SUB     #1,TOS              \ 1
29726 0= UNTIL                        \ 2
29727     MOV     @PSP+,TOS           \ 2
29728     MOV     @IP+,PC             \ 4
29729 ENDCODE
29730     \
29731
29732 CODE TOP_LCD                    \ LCD Sample
29733 \                               \ if write : %xxxxWWWW --
29734 \                               \ if read  : -- %0000RRRR
29735     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
29736     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
29737 0= IF                           \ write LCD bits pattern
29738     AND.B #LCD_DB,TOS           \ 
29739     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
29740     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
29741     MOV @PSP+,TOS               \
29742     MOV @IP+,PC
29743 THEN                            \ read LCD bits pattern
29744     SUB #2,PSP
29745     MOV TOS,0(PSP)
29746     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
29747     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
29748     AND.B #LCD_DB,TOS           \
29749     MOV @IP+,PC
29750 ENDCODE
29751     \
29752
29753 CODE LCD_W                      \ byte --       write byte to LCD 
29754     SUB #2,PSP                  \
29755     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
29756     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
29757     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
29758     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
29759 COLON                           \ high level word starts here 
29760     TOP_LCD 2 20_US             \ write high nibble first
29761     TOP_LCD 2 20_US 
29762 ;
29763     \
29764
29765 CODE LCD_WrC                    \ char --         Write Char
29766     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
29767     JMP LCD_W 
29768 ENDCODE
29769     \
29770
29771 CODE LCD_WrF                    \ func --         Write Fonction
29772     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
29773     JMP LCD_W 
29774 ENDCODE
29775     \
29776
29777 : LCD_Clear 
29778     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
29779 ;
29780     \
29781
29782 : LCD_Home 
29783     $02 LCD_WrF 100 20_us 
29784 ;
29785     \
29786
29787 \ : LCD_Entry_set       $04 OR LCD_WrF ;
29788
29789 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
29790
29791 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
29792
29793 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
29794
29795 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
29796
29797 \ : LCD_Goto            $80 OR LCD_WrF ;
29798
29799 \ CODE LCD_R                      \ -- byte       read byte from LCD
29800 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
29801 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
29802 \ COLON                           \ starts a FORTH word
29803 \     TOP_LCD 2 20_us             \ -- %0000HHHH
29804 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
29805 \ HI2LO                           \ switch from FORTH to assembler
29806 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
29807 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
29808 \     MOV @RSP+,IP                \ restore IP saved by COLON
29809 \     MOV @IP+,PC                 \
29810 \ ENDCODE
29811 \     \
29812
29813 \ CODE LCD_RdS                    \ -- status       Read Status
29814 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
29815 \     JMP LCD_R
29816 \ ENDCODE
29817 \     \
29818
29819 \ CODE LCD_RdC                    \ -- char         Read Char
29820 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
29821 \     JMP LCD_R
29822 \ ENDCODE
29823 \     \
29824
29825 \ -------------+------+------+------+------++---+---+---+---+---------+
29826 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
29827 \ -------------+------+------+------+------++---+---+---+---+---------+
29828 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
29829 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
29830 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
29831 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
29832 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
29833 \ -------------+------+------+------+------++---+---+---+---+---------+
29834
29835
29836 \ ******************************\
29837 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
29838 \ ******************************\
29839 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
29840 \ ------------------------------\
29841 \ define LPM mode for ACCEPT    \
29842 \ ------------------------------\
29843 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
29844 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
29845 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
29846 BIT.B #SW2,&SW2_IN              \ test switch S2
29847 0= IF                           \ case of switch S2 pressed
29848     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
29849     U< IF
29850         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
29851     THEN
29852 ELSE
29853     BIT.B #SW1,&SW1_IN          \ test switch S1 input
29854     0= IF                       \ case of Switch S1 pressed
29855         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
29856         U>= IF                  \
29857             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
29858         THEN                    \
29859     THEN                        \
29860 THEN                            \
29861 RETI                            \ CPU is ON, GIE is OFF
29862 ENDASM                          \
29863     \
29864
29865
29866 \ ------------------------------\
29867 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
29868 \ ******************************\
29869 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
29870 \ ******************************\
29871 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
29872 \                               \       SMclock = 8|16|24 MHz
29873 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
29874 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
29875 \                               \       SR(9)=new Toggle bit memory (ADD on)
29876 \ ------------------------------\
29877 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
29878 \ ------------------------------\
29879 \ define LPM mode for ACCEPT    \
29880 \ ------------------------------\
29881 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
29882 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
29883 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
29884 \ ------------------------------\
29885 \ RC5_FirstStartBitHalfCycle:   \
29886 \ ------------------------------\
29887 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
29888 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
29889 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
29890 MOV     #1778,X                 \ RC5_Period in us
29891 MOV     #14,W                   \ count of loop
29892 BEGIN                           \
29893 \ ------------------------------\
29894 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
29895 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
29896     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
29897 \ RC5_Compute_3/4_Period:       \                   |
29898     RRUM    #1,X                \ X=1/2 cycle       |
29899     MOV     X,Y                 \ Y=1/2             ^
29900     RRUM    #1,Y                \ Y=1/4
29901     ADD     X,Y                 \ Y=3/4
29902 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
29903     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
29904     0= UNTIL                    \
29905 \ ------------------------------\
29906 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
29907 \ ------------------------------\
29908     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
29909     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
29910     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
29911     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
29912     SUB     #1,W                \ decrement count loop
29913 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
29914 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
29915 0<> WHILE                       \ ----> out of loop ----+
29916 \ RC5_compute_7/4_Time_out:     \                       |
29917     ADD     X,Y                 \                       |   out of bound = 7/4 period 
29918 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
29919     BEGIN                       \                       |
29920         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
29921         0>= IF                  \                       |   if cycle time out of bound
29922             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
29923             RETI                \                       |   then quit to do nothing
29924         THEN                    \                       |
29925 \ ------------------------------\                       |
29926         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
29927     0<> UNTIL                   \                   |   |
29928     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
29929 REPEAT                          \ ----> loop back --+   |
29930 \ ------------------------------\                       |
29931 \ RC5_SampleEndOf:              \ <---------------------+
29932 \ ------------------------------\
29933 BIC     #$30,&TA0CTL           \ stop timer_A0
29934 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
29935 \ ******************************\
29936 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
29937 \ ******************************\
29938 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
29939 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
29940 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
29941 BIT     #BIT13,X                \ X(13) = New_RC5_command
29942 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
29943 THEN                            \
29944 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
29945 \ ******************************\
29946 \ RC5_ComputeNewRC5word         \
29947 \ ******************************\
29948 SUB     #4,PSP                  \
29949 MOV     &BASE,2(PSP)            \ save variable BASE before use
29950 MOV     TOS,0(PSP)              \ save TOS before use
29951 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
29952 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
29953 \ ******************************\
29954 \ RC5_ComputeC6bit              \
29955 \ ******************************\
29956 BIT     #$4000,IP              \ test /C6 bit in IP
29957 0= IF   BIS #$40,TOS           \ set C6 bit in S
29958 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
29959 \ ******************************\
29960 \ RC5_CommandByteIsDone         \ RC5_code --
29961 \ ******************************\
29962
29963 \ ------------------------------\
29964 \ Display IR_RC5 code           \
29965 \ ------------------------------\
29966 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
29967 \ ------------------------------\
29968 LO2HI                           \ switch from assembler to FORTH
29969     ['] LCD_CLEAR IS CR         \ redirects CR
29970     ['] LCD_WrC  IS EMIT        \ redirects EMIT
29971     $10 BASE !                 \ change BASE to hexadecimal
29972     CR ." $" 2 U.R             \ print IR_RC5 code
29973     ['] (CR) IS CR              \ restore CR
29974     ['] (EMIT) IS EMIT          \ restore EMIT
29975 HI2LO                           \ switch from FORTH to assembler
29976 \ ------------------------------\
29977 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
29978 \ ------------------------------\
29979 MOV @PSP+,&BASE                 \ restore variable BASE
29980 RETI                            \ CPU is ON, GIE is OFF
29981 ENDASM                          \
29982     \ 
29983
29984 CODE START                      \
29985 \ ------------------------------\
29986 \ TB0CTL = %0000 0010 1001 0100\$3C0
29987 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
29988 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
29989 \                      --       \ID input divider \ 10 = /4
29990 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
29991 \                            -  \TBCLR TimerB Clear
29992 \                             - \TBIE
29993 \                              -\TBIFG
29994 \ --------------------------------\\
29995 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
29996 \              --                 \CM Capture Mode
29997 \                --               \CCIS
29998 \                   -             \SCS
29999 \                    --           \CLLD
30000 \                      -          \CAP
30001 \                        ---      \OUTMOD \ 011 = set/reset
30002 \                           -     \CCIE
30003 \                             -   \CCI
30004 \                              -  \OUT
30005 \                               - \COV
30006 \                                -\CCIFG
30007 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
30008 \ TB0EX0                          \$3E0 
30009 \ ------------------------------\
30010 \ set TimerB to make 50kHz PWM  \
30011 \ ------------------------------\
30012 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
30013 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
30014 \ ------------------------------\
30015 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
30016 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
30017 \ ------------------------------\
30018     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
30019     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
30020 \ ------------------------------\
30021 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
30022 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
30023 \ ------------------------------\
30024 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
30025 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
30026 \ ------------------------------\
30027     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
30028 \ ------------------------------\
30029 \ set TimerB to generate PWM for LCD_Vo
30030 \ ------------------------------\
30031     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
30032 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
30033     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
30034 \ ------------------------------\
30035     BIS.B #LCDVo,&LCDVo_DIR     \
30036     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
30037 \ ------------------------------\
30038     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
30039     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
30040 \ ------------------------------\
30041     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
30042     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
30043 \ ------------------------------\
30044 \ WDT interval init part        \
30045 \ ------------------------------\
30046     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
30047 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
30048 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
30049     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
30050 \ ------------------------------\
30051 \ init RC5_Int                  \
30052 \ ------------------------------\
30053     BIS.B #RC5,&IR_IE           \ enable RC5_Int
30054     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
30055 \ ------------------------------\
30056 \ init interrupt vectors
30057 \ ------------------------------\
30058     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
30059     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
30060 \ ------------------------------\
30061 \ define LPM mode for ACCEPT    \
30062 \ ------------------------------\
30063 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
30064 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
30065 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
30066
30067 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
30068
30069 \ ------------------------------\
30070 \ Init LCD 2x20                 \
30071 \ ------------------------------\
30072     $03E8 20_US                \ 1-  wait 20 ms
30073     $03 TOP_LCD                \ 2- send DB5=DB4=1
30074     $CD 20_US                  \ 3- wait 4,1 ms
30075     $03 TOP_LCD                \ 4- send again DB5=DB4=1
30076     $5 20_US                   \ 5- wait 0,1 ms
30077     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
30078     $2 20_US                   \    wait 40 us = LCD cycle
30079     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
30080     $2 20_US                   \    wait 40 us = LCD cycle
30081     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
30082     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
30083     LCD_Clear                   \ 10- "LCD_Clear"
30084     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
30085     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
30086     LCD_Clear                   \ 10- "LCD_Clear"
30087     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
30088     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
30089     CR ." I love you"   
30090     ['] (CR) IS CR              \ ' (CR) is CR
30091     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
30092     CR
30093     ."    RC5toLCD is running. Type STOP to quit"
30094 \    NOECHO                      \ uncomment to run this app without terminal connexion
30095     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
30096     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
30097 ;
30098     \
30099
30100 : STOP                  \ stops multitasking, must to be used before downloading app
30101     ['] (WARM) IS WARM  \ remove START app from FORTH init process
30102     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
30103 ;
30104     \
30105
30106
30107 RST_STATE   ;
30108
30109
30110 CODE MAX    \    n1 n2 -- n3       signed maximum
30111             CMP     @PSP,TOS    \ n2-n1
30112             S<      ?GOTO FW1   \ n2<n1
30113 BW1         ADD     #2,PSP
30114             MOV     @IP+,PC
30115 ENDCODE
30116     \
30117
30118 CODE MIN    \    n1 n2 -- n3       signed minimum
30119             CMP     @PSP,TOS     \ n2-n1
30120             S<      ?GOTO BW1    \ n2<n1
30121 FW1         MOV     @PSP+,TOS
30122             MOV     @IP+,PC
30123 ENDCODE
30124     \
30125
30126 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
30127   >R  <# 0 # #S #>  
30128   R> OVER - 0 MAX SPACES TYPE
30129 ;
30130     \
30131
30132 CODE 20_US                      \ n --      n * 20 us
30133 BEGIN                           \ 3 cycles loop + 6~  
30134 \    MOV     #5,W                \ 3 MCLK = 1 MHz
30135 \    MOV     #23,W               \ 3 MCLK = 4 MHz
30136     MOV     #51,W               \ 3 MCLK = 8 MHz
30137 \    MOV     #104,W              \ 3 MCLK = 16 MHz
30138 \    MOV     #158,W              \ 3 MCLK = 24 MHz
30139     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
30140         SUB #1,W                \ 1
30141     0= UNTIL                    \ 2
30142     SUB     #1,TOS              \ 1
30143 0= UNTIL                        \ 2
30144     MOV     @PSP+,TOS           \ 2
30145     MOV     @IP+,PC             \ 4
30146 ENDCODE
30147     \
30148
30149 CODE TOP_LCD                    \ LCD Sample
30150 \                               \ if write : %xxxxWWWW --
30151 \                               \ if read  : -- %0000RRRR
30152     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
30153     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
30154 0= IF                           \ write LCD bits pattern
30155     AND.B #LCD_DB,TOS           \ 
30156     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
30157     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
30158     MOV @PSP+,TOS               \
30159     MOV @IP+,PC
30160 THEN                            \ read LCD bits pattern
30161     SUB #2,PSP
30162     MOV TOS,0(PSP)
30163     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
30164     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
30165     AND.B #LCD_DB,TOS           \
30166     MOV @IP+,PC
30167 ENDCODE
30168     \
30169
30170 CODE LCD_W                      \ byte --       write byte to LCD 
30171     SUB #2,PSP                  \
30172     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
30173     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
30174     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
30175     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
30176 COLON                           \ high level word starts here 
30177     TOP_LCD 2 20_US             \ write high nibble first
30178     TOP_LCD 2 20_US 
30179 ;
30180     \
30181
30182 CODE LCD_WrC                    \ char --         Write Char
30183     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
30184     JMP LCD_W 
30185 ENDCODE
30186     \
30187
30188 CODE LCD_WrF                    \ func --         Write Fonction
30189     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
30190     JMP LCD_W 
30191 ENDCODE
30192     \
30193
30194 : LCD_Clear 
30195     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
30196 ;
30197     \
30198
30199 : LCD_Home 
30200     $02 LCD_WrF 100 20_us 
30201 ;
30202     \
30203
30204 \ : LCD_Entry_set       $04 OR LCD_WrF ;
30205
30206 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
30207
30208 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
30209
30210 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
30211
30212 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
30213
30214 \ : LCD_Goto            $80 OR LCD_WrF ;
30215
30216 \ CODE LCD_R                      \ -- byte       read byte from LCD
30217 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
30218 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
30219 \ COLON                           \ starts a FORTH word
30220 \     TOP_LCD 2 20_us             \ -- %0000HHHH
30221 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
30222 \ HI2LO                           \ switch from FORTH to assembler
30223 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
30224 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
30225 \     MOV @RSP+,IP                \ restore IP saved by COLON
30226 \     MOV @IP+,PC                 \
30227 \ ENDCODE
30228 \     \
30229
30230 \ CODE LCD_RdS                    \ -- status       Read Status
30231 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
30232 \     JMP LCD_R
30233 \ ENDCODE
30234 \     \
30235
30236 \ CODE LCD_RdC                    \ -- char         Read Char
30237 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
30238 \     JMP LCD_R
30239 \ ENDCODE
30240 \     \
30241
30242 \ -------------+------+------+------+------++---+---+---+---+---------+
30243 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
30244 \ -------------+------+------+------+------++---+---+---+---+---------+
30245 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
30246 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
30247 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
30248 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
30249 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
30250 \ -------------+------+------+------+------++---+---+---+---+---------+
30251
30252
30253 \ ******************************\
30254 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
30255 \ ******************************\
30256 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
30257 \ ------------------------------\
30258 \ define LPM mode for ACCEPT    \
30259 \ ------------------------------\
30260 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
30261 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
30262 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
30263 BIT.B #SW2,&SW2_IN              \ test switch S2
30264 0= IF                           \ case of switch S2 pressed
30265     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
30266     U< IF
30267         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
30268     THEN
30269 ELSE
30270     BIT.B #SW1,&SW1_IN          \ test switch S1 input
30271     0= IF                       \ case of Switch S1 pressed
30272         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
30273         U>= IF                  \
30274             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
30275         THEN                    \
30276     THEN                        \
30277 THEN                            \
30278 RETI                            \ CPU is ON, GIE is OFF
30279 ENDASM                          \
30280     \
30281
30282
30283 \ ------------------------------\
30284 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
30285 \ ******************************\
30286 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
30287 \ ******************************\
30288 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
30289 \                               \       SMclock = 8|16|24 MHz
30290 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
30291 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
30292 \                               \       SR(9)=new Toggle bit memory (ADD on)
30293 \ ------------------------------\
30294 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
30295 \ ------------------------------\
30296 \ define LPM mode for ACCEPT    \
30297 \ ------------------------------\
30298 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
30299 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
30300 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
30301 \ ------------------------------\
30302 \ RC5_FirstStartBitHalfCycle:   \
30303 \ ------------------------------\
30304 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
30305 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
30306 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
30307 MOV     #1778,X                 \ RC5_Period in us
30308 MOV     #14,W                   \ count of loop
30309 BEGIN                           \
30310 \ ------------------------------\
30311 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
30312 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
30313     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
30314 \ RC5_Compute_3/4_Period:       \                   |
30315     RRUM    #1,X                \ X=1/2 cycle       |
30316     MOV     X,Y                 \ Y=1/2             ^
30317     RRUM    #1,Y                \ Y=1/4
30318     ADD     X,Y                 \ Y=3/4
30319 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
30320     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
30321     0= UNTIL                    \
30322 \ ------------------------------\
30323 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
30324 \ ------------------------------\
30325     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
30326     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
30327     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
30328     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
30329     SUB     #1,W                \ decrement count loop
30330 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
30331 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
30332 0<> WHILE                       \ ----> out of loop ----+
30333 \ RC5_compute_7/4_Time_out:     \                       |
30334     ADD     X,Y                 \                       |   out of bound = 7/4 period 
30335 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
30336     BEGIN                       \                       |
30337         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
30338         0>= IF                  \                       |   if cycle time out of bound
30339             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
30340             RETI                \                       |   then quit to do nothing
30341         THEN                    \                       |
30342 \ ------------------------------\                       |
30343         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
30344     0<> UNTIL                   \                   |   |
30345     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
30346 REPEAT                          \ ----> loop back --+   |
30347 \ ------------------------------\                       |
30348 \ RC5_SampleEndOf:              \ <---------------------+
30349 \ ------------------------------\
30350 BIC     #$30,&TA0CTL           \ stop timer_A0
30351 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
30352 \ ******************************\
30353 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
30354 \ ******************************\
30355 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
30356 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
30357 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
30358 BIT     #BIT13,X                \ X(13) = New_RC5_command
30359 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
30360 THEN                            \
30361 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
30362 \ ******************************\
30363 \ RC5_ComputeNewRC5word         \
30364 \ ******************************\
30365 SUB     #4,PSP                  \
30366 MOV     &BASE,2(PSP)            \ save variable BASE before use
30367 MOV     TOS,0(PSP)              \ save TOS before use
30368 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
30369 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
30370 \ ******************************\
30371 \ RC5_ComputeC6bit              \
30372 \ ******************************\
30373 BIT     #$4000,IP              \ test /C6 bit in IP
30374 0= IF   BIS #$40,TOS           \ set C6 bit in S
30375 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
30376 \ ******************************\
30377 \ RC5_CommandByteIsDone         \ RC5_code --
30378 \ ******************************\
30379
30380 \ ------------------------------\
30381 \ Display IR_RC5 code           \
30382 \ ------------------------------\
30383 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
30384 \ ------------------------------\
30385 LO2HI                           \ switch from assembler to FORTH
30386     ['] LCD_CLEAR IS CR         \ redirects CR
30387     ['] LCD_WrC  IS EMIT        \ redirects EMIT
30388     $10 BASE !                 \ change BASE to hexadecimal
30389     CR ." $" 2 U.R             \ print IR_RC5 code
30390     ['] (CR) IS CR              \ restore CR
30391     ['] (EMIT) IS EMIT          \ restore EMIT
30392 HI2LO                           \ switch from FORTH to assembler
30393 \ ------------------------------\
30394 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
30395 \ ------------------------------\
30396 MOV @PSP+,&BASE                 \ restore variable BASE
30397 RETI                            \ CPU is ON, GIE is OFF
30398 ENDASM                          \
30399     \ 
30400
30401 CODE START                      \
30402 \ ------------------------------\
30403 \ TB0CTL = %0000 0010 1001 0100\$3C0
30404 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
30405 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
30406 \                      --       \ID input divider \ 10 = /4
30407 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
30408 \                            -  \TBCLR TimerB Clear
30409 \                             - \TBIE
30410 \                              -\TBIFG
30411 \ --------------------------------\\
30412 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
30413 \              --                 \CM Capture Mode
30414 \                --               \CCIS
30415 \                   -             \SCS
30416 \                    --           \CLLD
30417 \                      -          \CAP
30418 \                        ---      \OUTMOD \ 011 = set/reset
30419 \                           -     \CCIE
30420 \                             -   \CCI
30421 \                              -  \OUT
30422 \                               - \COV
30423 \                                -\CCIFG
30424 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
30425 \ TB0EX0                          \$3E0 
30426 \ ------------------------------\
30427 \ set TimerB to make 50kHz PWM  \
30428 \ ------------------------------\
30429 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
30430 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
30431 \ ------------------------------\
30432 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
30433 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
30434 \ ------------------------------\
30435     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
30436     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
30437 \ ------------------------------\
30438 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
30439 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
30440 \ ------------------------------\
30441 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
30442 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
30443 \ ------------------------------\
30444     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
30445 \ ------------------------------\
30446 \ set TimerB to generate PWM for LCD_Vo
30447 \ ------------------------------\
30448     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
30449 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
30450     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
30451 \ ------------------------------\
30452     BIS.B #LCDVo,&LCDVo_DIR     \
30453     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
30454 \ ------------------------------\
30455     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
30456     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
30457 \ ------------------------------\
30458     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
30459     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
30460 \ ------------------------------\
30461 \ WDT interval init part        \
30462 \ ------------------------------\
30463     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
30464 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
30465 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
30466     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
30467 \ ------------------------------\
30468 \ init RC5_Int                  \
30469 \ ------------------------------\
30470     BIS.B #RC5,&IR_IE           \ enable RC5_Int
30471     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
30472 \ ------------------------------\
30473 \ init interrupt vectors
30474 \ ------------------------------\
30475     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
30476     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
30477 \ ------------------------------\
30478 \ define LPM mode for ACCEPT    \
30479 \ ------------------------------\
30480 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
30481 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
30482 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
30483
30484 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
30485
30486 \ ------------------------------\
30487 \ Init LCD 2x20                 \
30488 \ ------------------------------\
30489     $03E8 20_US                \ 1-  wait 20 ms
30490     $03 TOP_LCD                \ 2- send DB5=DB4=1
30491     $CD 20_US                  \ 3- wait 4,1 ms
30492     $03 TOP_LCD                \ 4- send again DB5=DB4=1
30493     $5 20_US                   \ 5- wait 0,1 ms
30494     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
30495     $2 20_US                   \    wait 40 us = LCD cycle
30496     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
30497     $2 20_US                   \    wait 40 us = LCD cycle
30498     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
30499     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
30500     LCD_Clear                   \ 10- "LCD_Clear"
30501     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
30502     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
30503     LCD_Clear                   \ 10- "LCD_Clear"
30504     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
30505     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
30506     CR ." I love you"   
30507     ['] (CR) IS CR              \ ' (CR) is CR
30508     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
30509     CR
30510     ."    RC5toLCD is running. Type STOP to quit"
30511 \    NOECHO                      \ uncomment to run this app without terminal connexion
30512     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
30513     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
30514 ;
30515     \
30516
30517 : STOP                  \ stops multitasking, must to be used before downloading app
30518     ['] (WARM) IS WARM  \ remove START app from FORTH init process
30519     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
30520 ;
30521     \
30522
30523
30524 RST_STATE   ;
30525
30526
30527 CODE MAX    \    n1 n2 -- n3       signed maximum
30528             CMP     @PSP,TOS    \ n2-n1
30529             S<      ?GOTO FW1   \ n2<n1
30530 BW1         ADD     #2,PSP
30531             MOV     @IP+,PC
30532 ENDCODE
30533     \
30534
30535 CODE MIN    \    n1 n2 -- n3       signed minimum
30536             CMP     @PSP,TOS     \ n2-n1
30537             S<      ?GOTO BW1    \ n2<n1
30538 FW1         MOV     @PSP+,TOS
30539             MOV     @IP+,PC
30540 ENDCODE
30541     \
30542
30543 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
30544   >R  <# 0 # #S #>  
30545   R> OVER - 0 MAX SPACES TYPE
30546 ;
30547     \
30548
30549 CODE 20_US                      \ n --      n * 20 us
30550 BEGIN                           \ 3 cycles loop + 6~  
30551 \    MOV     #5,W                \ 3 MCLK = 1 MHz
30552 \    MOV     #23,W               \ 3 MCLK = 4 MHz
30553     MOV     #51,W               \ 3 MCLK = 8 MHz
30554 \    MOV     #104,W              \ 3 MCLK = 16 MHz
30555 \    MOV     #158,W              \ 3 MCLK = 24 MHz
30556     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
30557         SUB #1,W                \ 1
30558     0= UNTIL                    \ 2
30559     SUB     #1,TOS              \ 1
30560 0= UNTIL                        \ 2
30561     MOV     @PSP+,TOS           \ 2
30562     MOV     @IP+,PC             \ 4
30563 ENDCODE
30564     \
30565
30566 CODE TOP_LCD                    \ LCD Sample
30567 \                               \ if write : %xxxxWWWW --
30568 \                               \ if read  : -- %0000RRRR
30569     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
30570     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
30571 0= IF                           \ write LCD bits pattern
30572     AND.B #LCD_DB,TOS           \ 
30573     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
30574     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
30575     MOV @PSP+,TOS               \
30576     MOV @IP+,PC
30577 THEN                            \ read LCD bits pattern
30578     SUB #2,PSP
30579     MOV TOS,0(PSP)
30580     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
30581     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
30582     AND.B #LCD_DB,TOS           \
30583     MOV @IP+,PC
30584 ENDCODE
30585     \
30586
30587 CODE LCD_W                      \ byte --       write byte to LCD 
30588     SUB #2,PSP                  \
30589     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
30590     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
30591     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
30592     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
30593 COLON                           \ high level word starts here 
30594     TOP_LCD 2 20_US             \ write high nibble first
30595     TOP_LCD 2 20_US 
30596 ;
30597     \
30598
30599 CODE LCD_WrC                    \ char --         Write Char
30600     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
30601     JMP LCD_W 
30602 ENDCODE
30603     \
30604
30605 CODE LCD_WrF                    \ func --         Write Fonction
30606     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
30607     JMP LCD_W 
30608 ENDCODE
30609     \
30610
30611 : LCD_Clear 
30612     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
30613 ;
30614     \
30615
30616 : LCD_Home 
30617     $02 LCD_WrF 100 20_us 
30618 ;
30619     \
30620
30621 \ : LCD_Entry_set       $04 OR LCD_WrF ;
30622
30623 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
30624
30625 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
30626
30627 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
30628
30629 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
30630
30631 \ : LCD_Goto            $80 OR LCD_WrF ;
30632
30633 \ CODE LCD_R                      \ -- byte       read byte from LCD
30634 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
30635 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
30636 \ COLON                           \ starts a FORTH word
30637 \     TOP_LCD 2 20_us             \ -- %0000HHHH
30638 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
30639 \ HI2LO                           \ switch from FORTH to assembler
30640 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
30641 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
30642 \     MOV @RSP+,IP                \ restore IP saved by COLON
30643 \     MOV @IP+,PC                 \
30644 \ ENDCODE
30645 \     \
30646
30647 \ CODE LCD_RdS                    \ -- status       Read Status
30648 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
30649 \     JMP LCD_R
30650 \ ENDCODE
30651 \     \
30652
30653 \ CODE LCD_RdC                    \ -- char         Read Char
30654 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
30655 \     JMP LCD_R
30656 \ ENDCODE
30657 \     \
30658
30659 \ -------------+------+------+------+------++---+---+---+---+---------+
30660 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
30661 \ -------------+------+------+------+------++---+---+---+---+---------+
30662 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
30663 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
30664 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
30665 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
30666 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
30667 \ -------------+------+------+------+------++---+---+---+---+---------+
30668
30669
30670 \ ******************************\
30671 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
30672 \ ******************************\
30673 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
30674 \ ------------------------------\
30675 \ define LPM mode for ACCEPT    \
30676 \ ------------------------------\
30677 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
30678 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
30679 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
30680 BIT.B #SW2,&SW2_IN              \ test switch S2
30681 0= IF                           \ case of switch S2 pressed
30682     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
30683     U< IF
30684         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
30685     THEN
30686 ELSE
30687     BIT.B #SW1,&SW1_IN          \ test switch S1 input
30688     0= IF                       \ case of Switch S1 pressed
30689         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
30690         U>= IF                  \
30691             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
30692         THEN                    \
30693     THEN                        \
30694 THEN                            \
30695 RETI                            \ CPU is ON, GIE is OFF
30696 ENDASM                          \
30697     \
30698
30699
30700 \ ------------------------------\
30701 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
30702 \ ******************************\
30703 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
30704 \ ******************************\
30705 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
30706 \                               \       SMclock = 8|16|24 MHz
30707 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
30708 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
30709 \                               \       SR(9)=new Toggle bit memory (ADD on)
30710 \ ------------------------------\
30711 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
30712 \ ------------------------------\
30713 \ define LPM mode for ACCEPT    \
30714 \ ------------------------------\
30715 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
30716 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
30717 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
30718 \ ------------------------------\
30719 \ RC5_FirstStartBitHalfCycle:   \
30720 \ ------------------------------\
30721 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
30722 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
30723 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
30724 MOV     #1778,X                 \ RC5_Period in us
30725 MOV     #14,W                   \ count of loop
30726 BEGIN                           \
30727 \ ------------------------------\
30728 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
30729 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
30730     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
30731 \ RC5_Compute_3/4_Period:       \                   |
30732     RRUM    #1,X                \ X=1/2 cycle       |
30733     MOV     X,Y                 \ Y=1/2             ^
30734     RRUM    #1,Y                \ Y=1/4
30735     ADD     X,Y                 \ Y=3/4
30736 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
30737     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
30738     0= UNTIL                    \
30739 \ ------------------------------\
30740 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
30741 \ ------------------------------\
30742     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
30743     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
30744     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
30745     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
30746     SUB     #1,W                \ decrement count loop
30747 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
30748 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
30749 0<> WHILE                       \ ----> out of loop ----+
30750 \ RC5_compute_7/4_Time_out:     \                       |
30751     ADD     X,Y                 \                       |   out of bound = 7/4 period 
30752 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
30753     BEGIN                       \                       |
30754         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
30755         0>= IF                  \                       |   if cycle time out of bound
30756             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
30757             RETI                \                       |   then quit to do nothing
30758         THEN                    \                       |
30759 \ ------------------------------\                       |
30760         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
30761     0<> UNTIL                   \                   |   |
30762     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
30763 REPEAT                          \ ----> loop back --+   |
30764 \ ------------------------------\                       |
30765 \ RC5_SampleEndOf:              \ <---------------------+
30766 \ ------------------------------\
30767 BIC     #$30,&TA0CTL           \ stop timer_A0
30768 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
30769 \ ******************************\
30770 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
30771 \ ******************************\
30772 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
30773 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
30774 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
30775 BIT     #BIT13,X                \ X(13) = New_RC5_command
30776 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
30777 THEN                            \
30778 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
30779 \ ******************************\
30780 \ RC5_ComputeNewRC5word         \
30781 \ ******************************\
30782 SUB     #4,PSP                  \
30783 MOV     &BASE,2(PSP)            \ save variable BASE before use
30784 MOV     TOS,0(PSP)              \ save TOS before use
30785 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
30786 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
30787 \ ******************************\
30788 \ RC5_ComputeC6bit              \
30789 \ ******************************\
30790 BIT     #$4000,IP              \ test /C6 bit in IP
30791 0= IF   BIS #$40,TOS           \ set C6 bit in S
30792 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
30793 \ ******************************\
30794 \ RC5_CommandByteIsDone         \ RC5_code --
30795 \ ******************************\
30796
30797 \ ------------------------------\
30798 \ Display IR_RC5 code           \
30799 \ ------------------------------\
30800 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
30801 \ ------------------------------\
30802 LO2HI                           \ switch from assembler to FORTH
30803     ['] LCD_CLEAR IS CR         \ redirects CR
30804     ['] LCD_WrC  IS EMIT        \ redirects EMIT
30805     $10 BASE !                 \ change BASE to hexadecimal
30806     CR ." $" 2 U.R             \ print IR_RC5 code
30807     ['] (CR) IS CR              \ restore CR
30808     ['] (EMIT) IS EMIT          \ restore EMIT
30809 HI2LO                           \ switch from FORTH to assembler
30810 \ ------------------------------\
30811 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
30812 \ ------------------------------\
30813 MOV @PSP+,&BASE                 \ restore variable BASE
30814 RETI                            \ CPU is ON, GIE is OFF
30815 ENDASM                          \
30816     \ 
30817
30818 CODE START                      \
30819 \ ------------------------------\
30820 \ TB0CTL = %0000 0010 1001 0100\$3C0
30821 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
30822 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
30823 \                      --       \ID input divider \ 10 = /4
30824 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
30825 \                            -  \TBCLR TimerB Clear
30826 \                             - \TBIE
30827 \                              -\TBIFG
30828 \ --------------------------------\\
30829 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
30830 \              --                 \CM Capture Mode
30831 \                --               \CCIS
30832 \                   -             \SCS
30833 \                    --           \CLLD
30834 \                      -          \CAP
30835 \                        ---      \OUTMOD \ 011 = set/reset
30836 \                           -     \CCIE
30837 \                             -   \CCI
30838 \                              -  \OUT
30839 \                               - \COV
30840 \                                -\CCIFG
30841 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
30842 \ TB0EX0                          \$3E0 
30843 \ ------------------------------\
30844 \ set TimerB to make 50kHz PWM  \
30845 \ ------------------------------\
30846 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
30847 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
30848 \ ------------------------------\
30849 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
30850 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
30851 \ ------------------------------\
30852     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
30853     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
30854 \ ------------------------------\
30855 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
30856 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
30857 \ ------------------------------\
30858 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
30859 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
30860 \ ------------------------------\
30861     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
30862 \ ------------------------------\
30863 \ set TimerB to generate PWM for LCD_Vo
30864 \ ------------------------------\
30865     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
30866 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
30867     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
30868 \ ------------------------------\
30869     BIS.B #LCDVo,&LCDVo_DIR     \
30870     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
30871 \ ------------------------------\
30872     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
30873     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
30874 \ ------------------------------\
30875     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
30876     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
30877 \ ------------------------------\
30878 \ WDT interval init part        \
30879 \ ------------------------------\
30880     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
30881 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
30882 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
30883     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
30884 \ ------------------------------\
30885 \ init RC5_Int                  \
30886 \ ------------------------------\
30887     BIS.B #RC5,&IR_IE           \ enable RC5_Int
30888     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
30889 \ ------------------------------\
30890 \ init interrupt vectors
30891 \ ------------------------------\
30892     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
30893     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
30894 \ ------------------------------\
30895 \ define LPM mode for ACCEPT    \
30896 \ ------------------------------\
30897 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
30898 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
30899 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
30900
30901 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
30902
30903 \ ------------------------------\
30904 \ Init LCD 2x20                 \
30905 \ ------------------------------\
30906     $03E8 20_US                \ 1-  wait 20 ms
30907     $03 TOP_LCD                \ 2- send DB5=DB4=1
30908     $CD 20_US                  \ 3- wait 4,1 ms
30909     $03 TOP_LCD                \ 4- send again DB5=DB4=1
30910     $5 20_US                   \ 5- wait 0,1 ms
30911     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
30912     $2 20_US                   \    wait 40 us = LCD cycle
30913     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
30914     $2 20_US                   \    wait 40 us = LCD cycle
30915     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
30916     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
30917     LCD_Clear                   \ 10- "LCD_Clear"
30918     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
30919     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
30920     LCD_Clear                   \ 10- "LCD_Clear"
30921     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
30922     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
30923     CR ." I love you"   
30924     ['] (CR) IS CR              \ ' (CR) is CR
30925     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
30926     CR
30927     ."    RC5toLCD is running. Type STOP to quit"
30928 \    NOECHO                      \ uncomment to run this app without terminal connexion
30929     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
30930     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
30931 ;
30932     \
30933
30934 : STOP                  \ stops multitasking, must to be used before downloading app
30935     ['] (WARM) IS WARM  \ remove START app from FORTH init process
30936     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
30937 ;
30938     \
30939
30940
30941 RST_STATE   ;
30942
30943
30944 CODE MAX    \    n1 n2 -- n3       signed maximum
30945             CMP     @PSP,TOS    \ n2-n1
30946             S<      ?GOTO FW1   \ n2<n1
30947 BW1         ADD     #2,PSP
30948             MOV     @IP+,PC
30949 ENDCODE
30950     \
30951
30952 CODE MIN    \    n1 n2 -- n3       signed minimum
30953             CMP     @PSP,TOS     \ n2-n1
30954             S<      ?GOTO BW1    \ n2<n1
30955 FW1         MOV     @PSP+,TOS
30956             MOV     @IP+,PC
30957 ENDCODE
30958     \
30959
30960 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
30961   >R  <# 0 # #S #>  
30962   R> OVER - 0 MAX SPACES TYPE
30963 ;
30964     \
30965
30966 CODE 20_US                      \ n --      n * 20 us
30967 BEGIN                           \ 3 cycles loop + 6~  
30968 \    MOV     #5,W                \ 3 MCLK = 1 MHz
30969 \    MOV     #23,W               \ 3 MCLK = 4 MHz
30970     MOV     #51,W               \ 3 MCLK = 8 MHz
30971 \    MOV     #104,W              \ 3 MCLK = 16 MHz
30972 \    MOV     #158,W              \ 3 MCLK = 24 MHz
30973     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
30974         SUB #1,W                \ 1
30975     0= UNTIL                    \ 2
30976     SUB     #1,TOS              \ 1
30977 0= UNTIL                        \ 2
30978     MOV     @PSP+,TOS           \ 2
30979     MOV     @IP+,PC             \ 4
30980 ENDCODE
30981     \
30982
30983 CODE TOP_LCD                    \ LCD Sample
30984 \                               \ if write : %xxxxWWWW --
30985 \                               \ if read  : -- %0000RRRR
30986     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
30987     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
30988 0= IF                           \ write LCD bits pattern
30989     AND.B #LCD_DB,TOS           \ 
30990     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
30991     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
30992     MOV @PSP+,TOS               \
30993     MOV @IP+,PC
30994 THEN                            \ read LCD bits pattern
30995     SUB #2,PSP
30996     MOV TOS,0(PSP)
30997     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
30998     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
30999     AND.B #LCD_DB,TOS           \
31000     MOV @IP+,PC
31001 ENDCODE
31002     \
31003
31004 CODE LCD_W                      \ byte --       write byte to LCD 
31005     SUB #2,PSP                  \
31006     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
31007     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
31008     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
31009     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
31010 COLON                           \ high level word starts here 
31011     TOP_LCD 2 20_US             \ write high nibble first
31012     TOP_LCD 2 20_US 
31013 ;
31014     \
31015
31016 CODE LCD_WrC                    \ char --         Write Char
31017     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
31018     JMP LCD_W 
31019 ENDCODE
31020     \
31021
31022 CODE LCD_WrF                    \ func --         Write Fonction
31023     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
31024     JMP LCD_W 
31025 ENDCODE
31026     \
31027
31028 : LCD_Clear 
31029     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
31030 ;
31031     \
31032
31033 : LCD_Home 
31034     $02 LCD_WrF 100 20_us 
31035 ;
31036     \
31037
31038 \ : LCD_Entry_set       $04 OR LCD_WrF ;
31039
31040 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
31041
31042 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
31043
31044 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
31045
31046 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
31047
31048 \ : LCD_Goto            $80 OR LCD_WrF ;
31049
31050 \ CODE LCD_R                      \ -- byte       read byte from LCD
31051 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
31052 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
31053 \ COLON                           \ starts a FORTH word
31054 \     TOP_LCD 2 20_us             \ -- %0000HHHH
31055 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
31056 \ HI2LO                           \ switch from FORTH to assembler
31057 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
31058 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
31059 \     MOV @RSP+,IP                \ restore IP saved by COLON
31060 \     MOV @IP+,PC                 \
31061 \ ENDCODE
31062 \     \
31063
31064 \ CODE LCD_RdS                    \ -- status       Read Status
31065 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
31066 \     JMP LCD_R
31067 \ ENDCODE
31068 \     \
31069
31070 \ CODE LCD_RdC                    \ -- char         Read Char
31071 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
31072 \     JMP LCD_R
31073 \ ENDCODE
31074 \     \
31075
31076 \ -------------+------+------+------+------++---+---+---+---+---------+
31077 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
31078 \ -------------+------+------+------+------++---+---+---+---+---------+
31079 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
31080 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
31081 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
31082 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
31083 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
31084 \ -------------+------+------+------+------++---+---+---+---+---------+
31085
31086
31087 \ ******************************\
31088 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
31089 \ ******************************\
31090 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
31091 \ ------------------------------\
31092 \ define LPM mode for ACCEPT    \
31093 \ ------------------------------\
31094 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
31095 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
31096 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
31097 BIT.B #SW2,&SW2_IN              \ test switch S2
31098 0= IF                           \ case of switch S2 pressed
31099     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
31100     U< IF
31101         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
31102     THEN
31103 ELSE
31104     BIT.B #SW1,&SW1_IN          \ test switch S1 input
31105     0= IF                       \ case of Switch S1 pressed
31106         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
31107         U>= IF                  \
31108             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
31109         THEN                    \
31110     THEN                        \
31111 THEN                            \
31112 RETI                            \ CPU is ON, GIE is OFF
31113 ENDASM                          \
31114     \
31115
31116
31117 \ ------------------------------\
31118 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
31119 \ ******************************\
31120 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
31121 \ ******************************\
31122 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
31123 \                               \       SMclock = 8|16|24 MHz
31124 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
31125 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
31126 \                               \       SR(9)=new Toggle bit memory (ADD on)
31127 \ ------------------------------\
31128 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
31129 \ ------------------------------\
31130 \ define LPM mode for ACCEPT    \
31131 \ ------------------------------\
31132 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
31133 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
31134 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
31135 \ ------------------------------\
31136 \ RC5_FirstStartBitHalfCycle:   \
31137 \ ------------------------------\
31138 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
31139 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
31140 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
31141 MOV     #1778,X                 \ RC5_Period in us
31142 MOV     #14,W                   \ count of loop
31143 BEGIN                           \
31144 \ ------------------------------\
31145 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
31146 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
31147     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
31148 \ RC5_Compute_3/4_Period:       \                   |
31149     RRUM    #1,X                \ X=1/2 cycle       |
31150     MOV     X,Y                 \ Y=1/2             ^
31151     RRUM    #1,Y                \ Y=1/4
31152     ADD     X,Y                 \ Y=3/4
31153 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
31154     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
31155     0= UNTIL                    \
31156 \ ------------------------------\
31157 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
31158 \ ------------------------------\
31159     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
31160     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
31161     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
31162     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
31163     SUB     #1,W                \ decrement count loop
31164 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
31165 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
31166 0<> WHILE                       \ ----> out of loop ----+
31167 \ RC5_compute_7/4_Time_out:     \                       |
31168     ADD     X,Y                 \                       |   out of bound = 7/4 period 
31169 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
31170     BEGIN                       \                       |
31171         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
31172         0>= IF                  \                       |   if cycle time out of bound
31173             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
31174             RETI                \                       |   then quit to do nothing
31175         THEN                    \                       |
31176 \ ------------------------------\                       |
31177         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
31178     0<> UNTIL                   \                   |   |
31179     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
31180 REPEAT                          \ ----> loop back --+   |
31181 \ ------------------------------\                       |
31182 \ RC5_SampleEndOf:              \ <---------------------+
31183 \ ------------------------------\
31184 BIC     #$30,&TA0CTL           \ stop timer_A0
31185 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
31186 \ ******************************\
31187 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
31188 \ ******************************\
31189 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
31190 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
31191 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
31192 BIT     #BIT13,X                \ X(13) = New_RC5_command
31193 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
31194 THEN                            \
31195 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
31196 \ ******************************\
31197 \ RC5_ComputeNewRC5word         \
31198 \ ******************************\
31199 SUB     #4,PSP                  \
31200 MOV     &BASE,2(PSP)            \ save variable BASE before use
31201 MOV     TOS,0(PSP)              \ save TOS before use
31202 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
31203 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
31204 \ ******************************\
31205 \ RC5_ComputeC6bit              \
31206 \ ******************************\
31207 BIT     #$4000,IP              \ test /C6 bit in IP
31208 0= IF   BIS #$40,TOS           \ set C6 bit in S
31209 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
31210 \ ******************************\
31211 \ RC5_CommandByteIsDone         \ RC5_code --
31212 \ ******************************\
31213
31214 \ ------------------------------\
31215 \ Display IR_RC5 code           \
31216 \ ------------------------------\
31217 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
31218 \ ------------------------------\
31219 LO2HI                           \ switch from assembler to FORTH
31220     ['] LCD_CLEAR IS CR         \ redirects CR
31221     ['] LCD_WrC  IS EMIT        \ redirects EMIT
31222     $10 BASE !                 \ change BASE to hexadecimal
31223     CR ." $" 2 U.R             \ print IR_RC5 code
31224     ['] (CR) IS CR              \ restore CR
31225     ['] (EMIT) IS EMIT          \ restore EMIT
31226 HI2LO                           \ switch from FORTH to assembler
31227 \ ------------------------------\
31228 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
31229 \ ------------------------------\
31230 MOV @PSP+,&BASE                 \ restore variable BASE
31231 RETI                            \ CPU is ON, GIE is OFF
31232 ENDASM                          \
31233     \ 
31234
31235 CODE START                      \
31236 \ ------------------------------\
31237 \ TB0CTL = %0000 0010 1001 0100\$3C0
31238 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
31239 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
31240 \                      --       \ID input divider \ 10 = /4
31241 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
31242 \                            -  \TBCLR TimerB Clear
31243 \                             - \TBIE
31244 \                              -\TBIFG
31245 \ --------------------------------\\
31246 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
31247 \              --                 \CM Capture Mode
31248 \                --               \CCIS
31249 \                   -             \SCS
31250 \                    --           \CLLD
31251 \                      -          \CAP
31252 \                        ---      \OUTMOD \ 011 = set/reset
31253 \                           -     \CCIE
31254 \                             -   \CCI
31255 \                              -  \OUT
31256 \                               - \COV
31257 \                                -\CCIFG
31258 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
31259 \ TB0EX0                          \$3E0 
31260 \ ------------------------------\
31261 \ set TimerB to make 50kHz PWM  \
31262 \ ------------------------------\
31263 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
31264 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
31265 \ ------------------------------\
31266 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
31267 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
31268 \ ------------------------------\
31269     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
31270     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
31271 \ ------------------------------\
31272 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
31273 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
31274 \ ------------------------------\
31275 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
31276 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
31277 \ ------------------------------\
31278     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
31279 \ ------------------------------\
31280 \ set TimerB to generate PWM for LCD_Vo
31281 \ ------------------------------\
31282     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
31283 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
31284     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
31285 \ ------------------------------\
31286     BIS.B #LCDVo,&LCDVo_DIR     \
31287     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
31288 \ ------------------------------\
31289     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
31290     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
31291 \ ------------------------------\
31292     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
31293     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
31294 \ ------------------------------\
31295 \ WDT interval init part        \
31296 \ ------------------------------\
31297     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
31298 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
31299 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
31300     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
31301 \ ------------------------------\
31302 \ init RC5_Int                  \
31303 \ ------------------------------\
31304     BIS.B #RC5,&IR_IE           \ enable RC5_Int
31305     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
31306 \ ------------------------------\
31307 \ init interrupt vectors
31308 \ ------------------------------\
31309     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
31310     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
31311 \ ------------------------------\
31312 \ define LPM mode for ACCEPT    \
31313 \ ------------------------------\
31314 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
31315 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
31316 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
31317
31318 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
31319
31320 \ ------------------------------\
31321 \ Init LCD 2x20                 \
31322 \ ------------------------------\
31323     $03E8 20_US                \ 1-  wait 20 ms
31324     $03 TOP_LCD                \ 2- send DB5=DB4=1
31325     $CD 20_US                  \ 3- wait 4,1 ms
31326     $03 TOP_LCD                \ 4- send again DB5=DB4=1
31327     $5 20_US                   \ 5- wait 0,1 ms
31328     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
31329     $2 20_US                   \    wait 40 us = LCD cycle
31330     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
31331     $2 20_US                   \    wait 40 us = LCD cycle
31332     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
31333     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
31334     LCD_Clear                   \ 10- "LCD_Clear"
31335     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
31336     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
31337     LCD_Clear                   \ 10- "LCD_Clear"
31338     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
31339     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
31340     CR ." I love you"   
31341     ['] (CR) IS CR              \ ' (CR) is CR
31342     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
31343     CR
31344     ."    RC5toLCD is running. Type STOP to quit"
31345 \    NOECHO                      \ uncomment to run this app without terminal connexion
31346     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
31347     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
31348 ;
31349     \
31350
31351 : STOP                  \ stops multitasking, must to be used before downloading app
31352     ['] (WARM) IS WARM  \ remove START app from FORTH init process
31353     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
31354 ;
31355     \
31356
31357
31358 RST_STATE   ;
31359
31360
31361 CODE MAX    \    n1 n2 -- n3       signed maximum
31362             CMP     @PSP,TOS    \ n2-n1
31363             S<      ?GOTO FW1   \ n2<n1
31364 BW1         ADD     #2,PSP
31365             MOV     @IP+,PC
31366 ENDCODE
31367     \
31368
31369 CODE MIN    \    n1 n2 -- n3       signed minimum
31370             CMP     @PSP,TOS     \ n2-n1
31371             S<      ?GOTO BW1    \ n2<n1
31372 FW1         MOV     @PSP+,TOS
31373             MOV     @IP+,PC
31374 ENDCODE
31375     \
31376
31377 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
31378   >R  <# 0 # #S #>  
31379   R> OVER - 0 MAX SPACES TYPE
31380 ;
31381     \
31382
31383 CODE 20_US                      \ n --      n * 20 us
31384 BEGIN                           \ 3 cycles loop + 6~  
31385 \    MOV     #5,W                \ 3 MCLK = 1 MHz
31386 \    MOV     #23,W               \ 3 MCLK = 4 MHz
31387     MOV     #51,W               \ 3 MCLK = 8 MHz
31388 \    MOV     #104,W              \ 3 MCLK = 16 MHz
31389 \    MOV     #158,W              \ 3 MCLK = 24 MHz
31390     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
31391         SUB #1,W                \ 1
31392     0= UNTIL                    \ 2
31393     SUB     #1,TOS              \ 1
31394 0= UNTIL                        \ 2
31395     MOV     @PSP+,TOS           \ 2
31396     MOV     @IP+,PC             \ 4
31397 ENDCODE
31398     \
31399
31400 CODE TOP_LCD                    \ LCD Sample
31401 \                               \ if write : %xxxxWWWW --
31402 \                               \ if read  : -- %0000RRRR
31403     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
31404     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
31405 0= IF                           \ write LCD bits pattern
31406     AND.B #LCD_DB,TOS           \ 
31407     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
31408     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
31409     MOV @PSP+,TOS               \
31410     MOV @IP+,PC
31411 THEN                            \ read LCD bits pattern
31412     SUB #2,PSP
31413     MOV TOS,0(PSP)
31414     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
31415     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
31416     AND.B #LCD_DB,TOS           \
31417     MOV @IP+,PC
31418 ENDCODE
31419     \
31420
31421 CODE LCD_W                      \ byte --       write byte to LCD 
31422     SUB #2,PSP                  \
31423     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
31424     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
31425     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
31426     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
31427 COLON                           \ high level word starts here 
31428     TOP_LCD 2 20_US             \ write high nibble first
31429     TOP_LCD 2 20_US 
31430 ;
31431     \
31432
31433 CODE LCD_WrC                    \ char --         Write Char
31434     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
31435     JMP LCD_W 
31436 ENDCODE
31437     \
31438
31439 CODE LCD_WrF                    \ func --         Write Fonction
31440     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
31441     JMP LCD_W 
31442 ENDCODE
31443     \
31444
31445 : LCD_Clear 
31446     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
31447 ;
31448     \
31449
31450 : LCD_Home 
31451     $02 LCD_WrF 100 20_us 
31452 ;
31453     \
31454
31455 \ : LCD_Entry_set       $04 OR LCD_WrF ;
31456
31457 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
31458
31459 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
31460
31461 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
31462
31463 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
31464
31465 \ : LCD_Goto            $80 OR LCD_WrF ;
31466
31467 \ CODE LCD_R                      \ -- byte       read byte from LCD
31468 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
31469 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
31470 \ COLON                           \ starts a FORTH word
31471 \     TOP_LCD 2 20_us             \ -- %0000HHHH
31472 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
31473 \ HI2LO                           \ switch from FORTH to assembler
31474 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
31475 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
31476 \     MOV @RSP+,IP                \ restore IP saved by COLON
31477 \     MOV @IP+,PC                 \
31478 \ ENDCODE
31479 \     \
31480
31481 \ CODE LCD_RdS                    \ -- status       Read Status
31482 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
31483 \     JMP LCD_R
31484 \ ENDCODE
31485 \     \
31486
31487 \ CODE LCD_RdC                    \ -- char         Read Char
31488 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
31489 \     JMP LCD_R
31490 \ ENDCODE
31491 \     \
31492
31493 \ -------------+------+------+------+------++---+---+---+---+---------+
31494 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
31495 \ -------------+------+------+------+------++---+---+---+---+---------+
31496 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
31497 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
31498 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
31499 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
31500 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
31501 \ -------------+------+------+------+------++---+---+---+---+---------+
31502
31503
31504 \ ******************************\
31505 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
31506 \ ******************************\
31507 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
31508 \ ------------------------------\
31509 \ define LPM mode for ACCEPT    \
31510 \ ------------------------------\
31511 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
31512 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
31513 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
31514 BIT.B #SW2,&SW2_IN              \ test switch S2
31515 0= IF                           \ case of switch S2 pressed
31516     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
31517     U< IF
31518         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
31519     THEN
31520 ELSE
31521     BIT.B #SW1,&SW1_IN          \ test switch S1 input
31522     0= IF                       \ case of Switch S1 pressed
31523         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
31524         U>= IF                  \
31525             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
31526         THEN                    \
31527     THEN                        \
31528 THEN                            \
31529 RETI                            \ CPU is ON, GIE is OFF
31530 ENDASM                          \
31531     \
31532
31533
31534 \ ------------------------------\
31535 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
31536 \ ******************************\
31537 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
31538 \ ******************************\
31539 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
31540 \                               \       SMclock = 8|16|24 MHz
31541 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
31542 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
31543 \                               \       SR(9)=new Toggle bit memory (ADD on)
31544 \ ------------------------------\
31545 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
31546 \ ------------------------------\
31547 \ define LPM mode for ACCEPT    \
31548 \ ------------------------------\
31549 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
31550 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
31551 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
31552 \ ------------------------------\
31553 \ RC5_FirstStartBitHalfCycle:   \
31554 \ ------------------------------\
31555 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
31556 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
31557 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
31558 MOV     #1778,X                 \ RC5_Period in us
31559 MOV     #14,W                   \ count of loop
31560 BEGIN                           \
31561 \ ------------------------------\
31562 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
31563 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
31564     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
31565 \ RC5_Compute_3/4_Period:       \                   |
31566     RRUM    #1,X                \ X=1/2 cycle       |
31567     MOV     X,Y                 \ Y=1/2             ^
31568     RRUM    #1,Y                \ Y=1/4
31569     ADD     X,Y                 \ Y=3/4
31570 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
31571     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
31572     0= UNTIL                    \
31573 \ ------------------------------\
31574 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
31575 \ ------------------------------\
31576     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
31577     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
31578     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
31579     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
31580     SUB     #1,W                \ decrement count loop
31581 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
31582 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
31583 0<> WHILE                       \ ----> out of loop ----+
31584 \ RC5_compute_7/4_Time_out:     \                       |
31585     ADD     X,Y                 \                       |   out of bound = 7/4 period 
31586 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
31587     BEGIN                       \                       |
31588         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
31589         0>= IF                  \                       |   if cycle time out of bound
31590             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
31591             RETI                \                       |   then quit to do nothing
31592         THEN                    \                       |
31593 \ ------------------------------\                       |
31594         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
31595     0<> UNTIL                   \                   |   |
31596     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
31597 REPEAT                          \ ----> loop back --+   |
31598 \ ------------------------------\                       |
31599 \ RC5_SampleEndOf:              \ <---------------------+
31600 \ ------------------------------\
31601 BIC     #$30,&TA0CTL           \ stop timer_A0
31602 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
31603 \ ******************************\
31604 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
31605 \ ******************************\
31606 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
31607 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
31608 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
31609 BIT     #BIT13,X                \ X(13) = New_RC5_command
31610 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
31611 THEN                            \
31612 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
31613 \ ******************************\
31614 \ RC5_ComputeNewRC5word         \
31615 \ ******************************\
31616 SUB     #4,PSP                  \
31617 MOV     &BASE,2(PSP)            \ save variable BASE before use
31618 MOV     TOS,0(PSP)              \ save TOS before use
31619 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
31620 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
31621 \ ******************************\
31622 \ RC5_ComputeC6bit              \
31623 \ ******************************\
31624 BIT     #$4000,IP              \ test /C6 bit in IP
31625 0= IF   BIS #$40,TOS           \ set C6 bit in S
31626 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
31627 \ ******************************\
31628 \ RC5_CommandByteIsDone         \ RC5_code --
31629 \ ******************************\
31630
31631 \ ------------------------------\
31632 \ Display IR_RC5 code           \
31633 \ ------------------------------\
31634 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
31635 \ ------------------------------\
31636 LO2HI                           \ switch from assembler to FORTH
31637     ['] LCD_CLEAR IS CR         \ redirects CR
31638     ['] LCD_WrC  IS EMIT        \ redirects EMIT
31639     $10 BASE !                 \ change BASE to hexadecimal
31640     CR ." $" 2 U.R             \ print IR_RC5 code
31641     ['] (CR) IS CR              \ restore CR
31642     ['] (EMIT) IS EMIT          \ restore EMIT
31643 HI2LO                           \ switch from FORTH to assembler
31644 \ ------------------------------\
31645 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
31646 \ ------------------------------\
31647 MOV @PSP+,&BASE                 \ restore variable BASE
31648 RETI                            \ CPU is ON, GIE is OFF
31649 ENDASM                          \
31650     \ 
31651
31652 CODE START                      \
31653 \ ------------------------------\
31654 \ TB0CTL = %0000 0010 1001 0100\$3C0
31655 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
31656 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
31657 \                      --       \ID input divider \ 10 = /4
31658 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
31659 \                            -  \TBCLR TimerB Clear
31660 \                             - \TBIE
31661 \                              -\TBIFG
31662 \ --------------------------------\\
31663 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
31664 \              --                 \CM Capture Mode
31665 \                --               \CCIS
31666 \                   -             \SCS
31667 \                    --           \CLLD
31668 \                      -          \CAP
31669 \                        ---      \OUTMOD \ 011 = set/reset
31670 \                           -     \CCIE
31671 \                             -   \CCI
31672 \                              -  \OUT
31673 \                               - \COV
31674 \                                -\CCIFG
31675 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
31676 \ TB0EX0                          \$3E0 
31677 \ ------------------------------\
31678 \ set TimerB to make 50kHz PWM  \
31679 \ ------------------------------\
31680 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
31681 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
31682 \ ------------------------------\
31683 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
31684 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
31685 \ ------------------------------\
31686     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
31687     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
31688 \ ------------------------------\
31689 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
31690 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
31691 \ ------------------------------\
31692 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
31693 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
31694 \ ------------------------------\
31695     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
31696 \ ------------------------------\
31697 \ set TimerB to generate PWM for LCD_Vo
31698 \ ------------------------------\
31699     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
31700 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
31701     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
31702 \ ------------------------------\
31703     BIS.B #LCDVo,&LCDVo_DIR     \
31704     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
31705 \ ------------------------------\
31706     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
31707     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
31708 \ ------------------------------\
31709     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
31710     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
31711 \ ------------------------------\
31712 \ WDT interval init part        \
31713 \ ------------------------------\
31714     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
31715 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
31716 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
31717     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
31718 \ ------------------------------\
31719 \ init RC5_Int                  \
31720 \ ------------------------------\
31721     BIS.B #RC5,&IR_IE           \ enable RC5_Int
31722     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
31723 \ ------------------------------\
31724 \ init interrupt vectors
31725 \ ------------------------------\
31726     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
31727     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
31728 \ ------------------------------\
31729 \ define LPM mode for ACCEPT    \
31730 \ ------------------------------\
31731 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
31732 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
31733 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
31734
31735 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
31736
31737 \ ------------------------------\
31738 \ Init LCD 2x20                 \
31739 \ ------------------------------\
31740     $03E8 20_US                \ 1-  wait 20 ms
31741     $03 TOP_LCD                \ 2- send DB5=DB4=1
31742     $CD 20_US                  \ 3- wait 4,1 ms
31743     $03 TOP_LCD                \ 4- send again DB5=DB4=1
31744     $5 20_US                   \ 5- wait 0,1 ms
31745     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
31746     $2 20_US                   \    wait 40 us = LCD cycle
31747     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
31748     $2 20_US                   \    wait 40 us = LCD cycle
31749     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
31750     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
31751     LCD_Clear                   \ 10- "LCD_Clear"
31752     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
31753     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
31754     LCD_Clear                   \ 10- "LCD_Clear"
31755     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
31756     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
31757     CR ." I love you"   
31758     ['] (CR) IS CR              \ ' (CR) is CR
31759     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
31760     CR
31761     ."    RC5toLCD is running. Type STOP to quit"
31762 \    NOECHO                      \ uncomment to run this app without terminal connexion
31763     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
31764     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
31765 ;
31766     \
31767
31768 : STOP                  \ stops multitasking, must to be used before downloading app
31769     ['] (WARM) IS WARM  \ remove START app from FORTH init process
31770     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
31771 ;
31772     \
31773
31774
31775 RST_STATE   ;
31776
31777
31778 CODE MAX    \    n1 n2 -- n3       signed maximum
31779             CMP     @PSP,TOS    \ n2-n1
31780             S<      ?GOTO FW1   \ n2<n1
31781 BW1         ADD     #2,PSP
31782             MOV     @IP+,PC
31783 ENDCODE
31784     \
31785
31786 CODE MIN    \    n1 n2 -- n3       signed minimum
31787             CMP     @PSP,TOS     \ n2-n1
31788             S<      ?GOTO BW1    \ n2<n1
31789 FW1         MOV     @PSP+,TOS
31790             MOV     @IP+,PC
31791 ENDCODE
31792     \
31793
31794 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
31795   >R  <# 0 # #S #>  
31796   R> OVER - 0 MAX SPACES TYPE
31797 ;
31798     \
31799
31800 CODE 20_US                      \ n --      n * 20 us
31801 BEGIN                           \ 3 cycles loop + 6~  
31802 \    MOV     #5,W                \ 3 MCLK = 1 MHz
31803 \    MOV     #23,W               \ 3 MCLK = 4 MHz
31804     MOV     #51,W               \ 3 MCLK = 8 MHz
31805 \    MOV     #104,W              \ 3 MCLK = 16 MHz
31806 \    MOV     #158,W              \ 3 MCLK = 24 MHz
31807     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
31808         SUB #1,W                \ 1
31809     0= UNTIL                    \ 2
31810     SUB     #1,TOS              \ 1
31811 0= UNTIL                        \ 2
31812     MOV     @PSP+,TOS           \ 2
31813     MOV     @IP+,PC             \ 4
31814 ENDCODE
31815     \
31816
31817 CODE TOP_LCD                    \ LCD Sample
31818 \                               \ if write : %xxxxWWWW --
31819 \                               \ if read  : -- %0000RRRR
31820     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
31821     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
31822 0= IF                           \ write LCD bits pattern
31823     AND.B #LCD_DB,TOS           \ 
31824     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
31825     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
31826     MOV @PSP+,TOS               \
31827     MOV @IP+,PC
31828 THEN                            \ read LCD bits pattern
31829     SUB #2,PSP
31830     MOV TOS,0(PSP)
31831     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
31832     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
31833     AND.B #LCD_DB,TOS           \
31834     MOV @IP+,PC
31835 ENDCODE
31836     \
31837
31838 CODE LCD_W                      \ byte --       write byte to LCD 
31839     SUB #2,PSP                  \
31840     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
31841     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
31842     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
31843     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
31844 COLON                           \ high level word starts here 
31845     TOP_LCD 2 20_US             \ write high nibble first
31846     TOP_LCD 2 20_US 
31847 ;
31848     \
31849
31850 CODE LCD_WrC                    \ char --         Write Char
31851     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
31852     JMP LCD_W 
31853 ENDCODE
31854     \
31855
31856 CODE LCD_WrF                    \ func --         Write Fonction
31857     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
31858     JMP LCD_W 
31859 ENDCODE
31860     \
31861
31862 : LCD_Clear 
31863     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
31864 ;
31865     \
31866
31867 : LCD_Home 
31868     $02 LCD_WrF 100 20_us 
31869 ;
31870     \
31871
31872 \ : LCD_Entry_set       $04 OR LCD_WrF ;
31873
31874 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
31875
31876 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
31877
31878 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
31879
31880 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
31881
31882 \ : LCD_Goto            $80 OR LCD_WrF ;
31883
31884 \ CODE LCD_R                      \ -- byte       read byte from LCD
31885 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
31886 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
31887 \ COLON                           \ starts a FORTH word
31888 \     TOP_LCD 2 20_us             \ -- %0000HHHH
31889 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
31890 \ HI2LO                           \ switch from FORTH to assembler
31891 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
31892 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
31893 \     MOV @RSP+,IP                \ restore IP saved by COLON
31894 \     MOV @IP+,PC                 \
31895 \ ENDCODE
31896 \     \
31897
31898 \ CODE LCD_RdS                    \ -- status       Read Status
31899 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
31900 \     JMP LCD_R
31901 \ ENDCODE
31902 \     \
31903
31904 \ CODE LCD_RdC                    \ -- char         Read Char
31905 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
31906 \     JMP LCD_R
31907 \ ENDCODE
31908 \     \
31909
31910 \ -------------+------+------+------+------++---+---+---+---+---------+
31911 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
31912 \ -------------+------+------+------+------++---+---+---+---+---------+
31913 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
31914 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
31915 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
31916 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
31917 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
31918 \ -------------+------+------+------+------++---+---+---+---+---------+
31919
31920
31921 \ ******************************\
31922 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
31923 \ ******************************\
31924 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
31925 \ ------------------------------\
31926 \ define LPM mode for ACCEPT    \
31927 \ ------------------------------\
31928 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
31929 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
31930 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
31931 BIT.B #SW2,&SW2_IN              \ test switch S2
31932 0= IF                           \ case of switch S2 pressed
31933     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
31934     U< IF
31935         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
31936     THEN
31937 ELSE
31938     BIT.B #SW1,&SW1_IN          \ test switch S1 input
31939     0= IF                       \ case of Switch S1 pressed
31940         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
31941         U>= IF                  \
31942             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
31943         THEN                    \
31944     THEN                        \
31945 THEN                            \
31946 RETI                            \ CPU is ON, GIE is OFF
31947 ENDASM                          \
31948     \
31949
31950
31951 \ ------------------------------\
31952 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
31953 \ ******************************\
31954 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
31955 \ ******************************\
31956 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
31957 \                               \       SMclock = 8|16|24 MHz
31958 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
31959 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
31960 \                               \       SR(9)=new Toggle bit memory (ADD on)
31961 \ ------------------------------\
31962 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
31963 \ ------------------------------\
31964 \ define LPM mode for ACCEPT    \
31965 \ ------------------------------\
31966 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
31967 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
31968 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
31969 \ ------------------------------\
31970 \ RC5_FirstStartBitHalfCycle:   \
31971 \ ------------------------------\
31972 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
31973 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
31974 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
31975 MOV     #1778,X                 \ RC5_Period in us
31976 MOV     #14,W                   \ count of loop
31977 BEGIN                           \
31978 \ ------------------------------\
31979 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
31980 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
31981     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
31982 \ RC5_Compute_3/4_Period:       \                   |
31983     RRUM    #1,X                \ X=1/2 cycle       |
31984     MOV     X,Y                 \ Y=1/2             ^
31985     RRUM    #1,Y                \ Y=1/4
31986     ADD     X,Y                 \ Y=3/4
31987 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
31988     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
31989     0= UNTIL                    \
31990 \ ------------------------------\
31991 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
31992 \ ------------------------------\
31993     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
31994     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
31995     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
31996     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
31997     SUB     #1,W                \ decrement count loop
31998 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
31999 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
32000 0<> WHILE                       \ ----> out of loop ----+
32001 \ RC5_compute_7/4_Time_out:     \                       |
32002     ADD     X,Y                 \                       |   out of bound = 7/4 period 
32003 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
32004     BEGIN                       \                       |
32005         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
32006         0>= IF                  \                       |   if cycle time out of bound
32007             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
32008             RETI                \                       |   then quit to do nothing
32009         THEN                    \                       |
32010 \ ------------------------------\                       |
32011         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
32012     0<> UNTIL                   \                   |   |
32013     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
32014 REPEAT                          \ ----> loop back --+   |
32015 \ ------------------------------\                       |
32016 \ RC5_SampleEndOf:              \ <---------------------+
32017 \ ------------------------------\
32018 BIC     #$30,&TA0CTL           \ stop timer_A0
32019 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
32020 \ ******************************\
32021 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
32022 \ ******************************\
32023 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
32024 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
32025 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
32026 BIT     #BIT13,X                \ X(13) = New_RC5_command
32027 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
32028 THEN                            \
32029 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
32030 \ ******************************\
32031 \ RC5_ComputeNewRC5word         \
32032 \ ******************************\
32033 SUB     #4,PSP                  \
32034 MOV     &BASE,2(PSP)            \ save variable BASE before use
32035 MOV     TOS,0(PSP)              \ save TOS before use
32036 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
32037 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
32038 \ ******************************\
32039 \ RC5_ComputeC6bit              \
32040 \ ******************************\
32041 BIT     #$4000,IP              \ test /C6 bit in IP
32042 0= IF   BIS #$40,TOS           \ set C6 bit in S
32043 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
32044 \ ******************************\
32045 \ RC5_CommandByteIsDone         \ RC5_code --
32046 \ ******************************\
32047
32048 \ ------------------------------\
32049 \ Display IR_RC5 code           \
32050 \ ------------------------------\
32051 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
32052 \ ------------------------------\
32053 LO2HI                           \ switch from assembler to FORTH
32054     ['] LCD_CLEAR IS CR         \ redirects CR
32055     ['] LCD_WrC  IS EMIT        \ redirects EMIT
32056     $10 BASE !                 \ change BASE to hexadecimal
32057     CR ." $" 2 U.R             \ print IR_RC5 code
32058     ['] (CR) IS CR              \ restore CR
32059     ['] (EMIT) IS EMIT          \ restore EMIT
32060 HI2LO                           \ switch from FORTH to assembler
32061 \ ------------------------------\
32062 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
32063 \ ------------------------------\
32064 MOV @PSP+,&BASE                 \ restore variable BASE
32065 RETI                            \ CPU is ON, GIE is OFF
32066 ENDASM                          \
32067     \ 
32068
32069 CODE START                      \
32070 \ ------------------------------\
32071 \ TB0CTL = %0000 0010 1001 0100\$3C0
32072 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
32073 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
32074 \                      --       \ID input divider \ 10 = /4
32075 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
32076 \                            -  \TBCLR TimerB Clear
32077 \                             - \TBIE
32078 \                              -\TBIFG
32079 \ --------------------------------\\
32080 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
32081 \              --                 \CM Capture Mode
32082 \                --               \CCIS
32083 \                   -             \SCS
32084 \                    --           \CLLD
32085 \                      -          \CAP
32086 \                        ---      \OUTMOD \ 011 = set/reset
32087 \                           -     \CCIE
32088 \                             -   \CCI
32089 \                              -  \OUT
32090 \                               - \COV
32091 \                                -\CCIFG
32092 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
32093 \ TB0EX0                          \$3E0 
32094 \ ------------------------------\
32095 \ set TimerB to make 50kHz PWM  \
32096 \ ------------------------------\
32097 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
32098 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
32099 \ ------------------------------\
32100 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
32101 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
32102 \ ------------------------------\
32103     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
32104     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
32105 \ ------------------------------\
32106 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
32107 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
32108 \ ------------------------------\
32109 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
32110 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
32111 \ ------------------------------\
32112     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
32113 \ ------------------------------\
32114 \ set TimerB to generate PWM for LCD_Vo
32115 \ ------------------------------\
32116     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
32117 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
32118     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
32119 \ ------------------------------\
32120     BIS.B #LCDVo,&LCDVo_DIR     \
32121     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
32122 \ ------------------------------\
32123     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
32124     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
32125 \ ------------------------------\
32126     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
32127     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
32128 \ ------------------------------\
32129 \ WDT interval init part        \
32130 \ ------------------------------\
32131     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
32132 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
32133 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
32134     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
32135 \ ------------------------------\
32136 \ init RC5_Int                  \
32137 \ ------------------------------\
32138     BIS.B #RC5,&IR_IE           \ enable RC5_Int
32139     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
32140 \ ------------------------------\
32141 \ init interrupt vectors
32142 \ ------------------------------\
32143     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
32144     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
32145 \ ------------------------------\
32146 \ define LPM mode for ACCEPT    \
32147 \ ------------------------------\
32148 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
32149 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
32150 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
32151
32152 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
32153
32154 \ ------------------------------\
32155 \ Init LCD 2x20                 \
32156 \ ------------------------------\
32157     $03E8 20_US                \ 1-  wait 20 ms
32158     $03 TOP_LCD                \ 2- send DB5=DB4=1
32159     $CD 20_US                  \ 3- wait 4,1 ms
32160     $03 TOP_LCD                \ 4- send again DB5=DB4=1
32161     $5 20_US                   \ 5- wait 0,1 ms
32162     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
32163     $2 20_US                   \    wait 40 us = LCD cycle
32164     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
32165     $2 20_US                   \    wait 40 us = LCD cycle
32166     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
32167     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
32168     LCD_Clear                   \ 10- "LCD_Clear"
32169     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
32170     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
32171     LCD_Clear                   \ 10- "LCD_Clear"
32172     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
32173     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
32174     CR ." I love you"   
32175     ['] (CR) IS CR              \ ' (CR) is CR
32176     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
32177     CR
32178     ."    RC5toLCD is running. Type STOP to quit"
32179 \    NOECHO                      \ uncomment to run this app without terminal connexion
32180     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
32181     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
32182 ;
32183     \
32184
32185 : STOP                  \ stops multitasking, must to be used before downloading app
32186     ['] (WARM) IS WARM  \ remove START app from FORTH init process
32187     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
32188 ;
32189     \
32190
32191
32192 RST_STATE   ;
32193
32194
32195 CODE MAX    \    n1 n2 -- n3       signed maximum
32196             CMP     @PSP,TOS    \ n2-n1
32197             S<      ?GOTO FW1   \ n2<n1
32198 BW1         ADD     #2,PSP
32199             MOV     @IP+,PC
32200 ENDCODE
32201     \
32202
32203 CODE MIN    \    n1 n2 -- n3       signed minimum
32204             CMP     @PSP,TOS     \ n2-n1
32205             S<      ?GOTO BW1    \ n2<n1
32206 FW1         MOV     @PSP+,TOS
32207             MOV     @IP+,PC
32208 ENDCODE
32209     \
32210
32211 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
32212   >R  <# 0 # #S #>  
32213   R> OVER - 0 MAX SPACES TYPE
32214 ;
32215     \
32216
32217 CODE 20_US                      \ n --      n * 20 us
32218 BEGIN                           \ 3 cycles loop + 6~  
32219 \    MOV     #5,W                \ 3 MCLK = 1 MHz
32220 \    MOV     #23,W               \ 3 MCLK = 4 MHz
32221     MOV     #51,W               \ 3 MCLK = 8 MHz
32222 \    MOV     #104,W              \ 3 MCLK = 16 MHz
32223 \    MOV     #158,W              \ 3 MCLK = 24 MHz
32224     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
32225         SUB #1,W                \ 1
32226     0= UNTIL                    \ 2
32227     SUB     #1,TOS              \ 1
32228 0= UNTIL                        \ 2
32229     MOV     @PSP+,TOS           \ 2
32230     MOV     @IP+,PC             \ 4
32231 ENDCODE
32232     \
32233
32234 CODE TOP_LCD                    \ LCD Sample
32235 \                               \ if write : %xxxxWWWW --
32236 \                               \ if read  : -- %0000RRRR
32237     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
32238     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
32239 0= IF                           \ write LCD bits pattern
32240     AND.B #LCD_DB,TOS           \ 
32241     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
32242     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
32243     MOV @PSP+,TOS               \
32244     MOV @IP+,PC
32245 THEN                            \ read LCD bits pattern
32246     SUB #2,PSP
32247     MOV TOS,0(PSP)
32248     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
32249     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
32250     AND.B #LCD_DB,TOS           \
32251     MOV @IP+,PC
32252 ENDCODE
32253     \
32254
32255 CODE LCD_W                      \ byte --       write byte to LCD 
32256     SUB #2,PSP                  \
32257     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
32258     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
32259     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
32260     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
32261 COLON                           \ high level word starts here 
32262     TOP_LCD 2 20_US             \ write high nibble first
32263     TOP_LCD 2 20_US 
32264 ;
32265     \
32266
32267 CODE LCD_WrC                    \ char --         Write Char
32268     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
32269     JMP LCD_W 
32270 ENDCODE
32271     \
32272
32273 CODE LCD_WrF                    \ func --         Write Fonction
32274     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
32275     JMP LCD_W 
32276 ENDCODE
32277     \
32278
32279 : LCD_Clear 
32280     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
32281 ;
32282     \
32283
32284 : LCD_Home 
32285     $02 LCD_WrF 100 20_us 
32286 ;
32287     \
32288
32289 \ : LCD_Entry_set       $04 OR LCD_WrF ;
32290
32291 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
32292
32293 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
32294
32295 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
32296
32297 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
32298
32299 \ : LCD_Goto            $80 OR LCD_WrF ;
32300
32301 \ CODE LCD_R                      \ -- byte       read byte from LCD
32302 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
32303 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
32304 \ COLON                           \ starts a FORTH word
32305 \     TOP_LCD 2 20_us             \ -- %0000HHHH
32306 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
32307 \ HI2LO                           \ switch from FORTH to assembler
32308 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
32309 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
32310 \     MOV @RSP+,IP                \ restore IP saved by COLON
32311 \     MOV @IP+,PC                 \
32312 \ ENDCODE
32313 \     \
32314
32315 \ CODE LCD_RdS                    \ -- status       Read Status
32316 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
32317 \     JMP LCD_R
32318 \ ENDCODE
32319 \     \
32320
32321 \ CODE LCD_RdC                    \ -- char         Read Char
32322 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
32323 \     JMP LCD_R
32324 \ ENDCODE
32325 \     \
32326
32327 \ -------------+------+------+------+------++---+---+---+---+---------+
32328 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
32329 \ -------------+------+------+------+------++---+---+---+---+---------+
32330 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
32331 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
32332 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
32333 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
32334 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
32335 \ -------------+------+------+------+------++---+---+---+---+---------+
32336
32337
32338 \ ******************************\
32339 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
32340 \ ******************************\
32341 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
32342 \ ------------------------------\
32343 \ define LPM mode for ACCEPT    \
32344 \ ------------------------------\
32345 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
32346 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
32347 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
32348 BIT.B #SW2,&SW2_IN              \ test switch S2
32349 0= IF                           \ case of switch S2 pressed
32350     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
32351     U< IF
32352         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
32353     THEN
32354 ELSE
32355     BIT.B #SW1,&SW1_IN          \ test switch S1 input
32356     0= IF                       \ case of Switch S1 pressed
32357         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
32358         U>= IF                  \
32359             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
32360         THEN                    \
32361     THEN                        \
32362 THEN                            \
32363 RETI                            \ CPU is ON, GIE is OFF
32364 ENDASM                          \
32365     \
32366
32367
32368 \ ------------------------------\
32369 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
32370 \ ******************************\
32371 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
32372 \ ******************************\
32373 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
32374 \                               \       SMclock = 8|16|24 MHz
32375 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
32376 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
32377 \                               \       SR(9)=new Toggle bit memory (ADD on)
32378 \ ------------------------------\
32379 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
32380 \ ------------------------------\
32381 \ define LPM mode for ACCEPT    \
32382 \ ------------------------------\
32383 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
32384 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
32385 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
32386 \ ------------------------------\
32387 \ RC5_FirstStartBitHalfCycle:   \
32388 \ ------------------------------\
32389 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
32390 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
32391 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
32392 MOV     #1778,X                 \ RC5_Period in us
32393 MOV     #14,W                   \ count of loop
32394 BEGIN                           \
32395 \ ------------------------------\
32396 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
32397 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
32398     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
32399 \ RC5_Compute_3/4_Period:       \                   |
32400     RRUM    #1,X                \ X=1/2 cycle       |
32401     MOV     X,Y                 \ Y=1/2             ^
32402     RRUM    #1,Y                \ Y=1/4
32403     ADD     X,Y                 \ Y=3/4
32404 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
32405     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
32406     0= UNTIL                    \
32407 \ ------------------------------\
32408 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
32409 \ ------------------------------\
32410     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
32411     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
32412     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
32413     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
32414     SUB     #1,W                \ decrement count loop
32415 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
32416 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
32417 0<> WHILE                       \ ----> out of loop ----+
32418 \ RC5_compute_7/4_Time_out:     \                       |
32419     ADD     X,Y                 \                       |   out of bound = 7/4 period 
32420 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
32421     BEGIN                       \                       |
32422         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
32423         0>= IF                  \                       |   if cycle time out of bound
32424             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
32425             RETI                \                       |   then quit to do nothing
32426         THEN                    \                       |
32427 \ ------------------------------\                       |
32428         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
32429     0<> UNTIL                   \                   |   |
32430     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
32431 REPEAT                          \ ----> loop back --+   |
32432 \ ------------------------------\                       |
32433 \ RC5_SampleEndOf:              \ <---------------------+
32434 \ ------------------------------\
32435 BIC     #$30,&TA0CTL           \ stop timer_A0
32436 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
32437 \ ******************************\
32438 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
32439 \ ******************************\
32440 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
32441 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
32442 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
32443 BIT     #BIT13,X                \ X(13) = New_RC5_command
32444 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
32445 THEN                            \
32446 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
32447 \ ******************************\
32448 \ RC5_ComputeNewRC5word         \
32449 \ ******************************\
32450 SUB     #4,PSP                  \
32451 MOV     &BASE,2(PSP)            \ save variable BASE before use
32452 MOV     TOS,0(PSP)              \ save TOS before use
32453 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
32454 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
32455 \ ******************************\
32456 \ RC5_ComputeC6bit              \
32457 \ ******************************\
32458 BIT     #$4000,IP              \ test /C6 bit in IP
32459 0= IF   BIS #$40,TOS           \ set C6 bit in S
32460 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
32461 \ ******************************\
32462 \ RC5_CommandByteIsDone         \ RC5_code --
32463 \ ******************************\
32464
32465 \ ------------------------------\
32466 \ Display IR_RC5 code           \
32467 \ ------------------------------\
32468 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
32469 \ ------------------------------\
32470 LO2HI                           \ switch from assembler to FORTH
32471     ['] LCD_CLEAR IS CR         \ redirects CR
32472     ['] LCD_WrC  IS EMIT        \ redirects EMIT
32473     $10 BASE !                 \ change BASE to hexadecimal
32474     CR ." $" 2 U.R             \ print IR_RC5 code
32475     ['] (CR) IS CR              \ restore CR
32476     ['] (EMIT) IS EMIT          \ restore EMIT
32477 HI2LO                           \ switch from FORTH to assembler
32478 \ ------------------------------\
32479 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
32480 \ ------------------------------\
32481 MOV @PSP+,&BASE                 \ restore variable BASE
32482 RETI                            \ CPU is ON, GIE is OFF
32483 ENDASM                          \
32484     \ 
32485
32486 CODE START                      \
32487 \ ------------------------------\
32488 \ TB0CTL = %0000 0010 1001 0100\$3C0
32489 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
32490 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
32491 \                      --       \ID input divider \ 10 = /4
32492 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
32493 \                            -  \TBCLR TimerB Clear
32494 \                             - \TBIE
32495 \                              -\TBIFG
32496 \ --------------------------------\\
32497 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
32498 \              --                 \CM Capture Mode
32499 \                --               \CCIS
32500 \                   -             \SCS
32501 \                    --           \CLLD
32502 \                      -          \CAP
32503 \                        ---      \OUTMOD \ 011 = set/reset
32504 \                           -     \CCIE
32505 \                             -   \CCI
32506 \                              -  \OUT
32507 \                               - \COV
32508 \                                -\CCIFG
32509 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
32510 \ TB0EX0                          \$3E0 
32511 \ ------------------------------\
32512 \ set TimerB to make 50kHz PWM  \
32513 \ ------------------------------\
32514 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
32515 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
32516 \ ------------------------------\
32517 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
32518 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
32519 \ ------------------------------\
32520     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
32521     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
32522 \ ------------------------------\
32523 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
32524 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
32525 \ ------------------------------\
32526 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
32527 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
32528 \ ------------------------------\
32529     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
32530 \ ------------------------------\
32531 \ set TimerB to generate PWM for LCD_Vo
32532 \ ------------------------------\
32533     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
32534 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
32535     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
32536 \ ------------------------------\
32537     BIS.B #LCDVo,&LCDVo_DIR     \
32538     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
32539 \ ------------------------------\
32540     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
32541     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
32542 \ ------------------------------\
32543     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
32544     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
32545 \ ------------------------------\
32546 \ WDT interval init part        \
32547 \ ------------------------------\
32548     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
32549 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
32550 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
32551     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
32552 \ ------------------------------\
32553 \ init RC5_Int                  \
32554 \ ------------------------------\
32555     BIS.B #RC5,&IR_IE           \ enable RC5_Int
32556     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
32557 \ ------------------------------\
32558 \ init interrupt vectors
32559 \ ------------------------------\
32560     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
32561     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
32562 \ ------------------------------\
32563 \ define LPM mode for ACCEPT    \
32564 \ ------------------------------\
32565 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
32566 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
32567 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
32568
32569 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
32570
32571 \ ------------------------------\
32572 \ Init LCD 2x20                 \
32573 \ ------------------------------\
32574     $03E8 20_US                \ 1-  wait 20 ms
32575     $03 TOP_LCD                \ 2- send DB5=DB4=1
32576     $CD 20_US                  \ 3- wait 4,1 ms
32577     $03 TOP_LCD                \ 4- send again DB5=DB4=1
32578     $5 20_US                   \ 5- wait 0,1 ms
32579     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
32580     $2 20_US                   \    wait 40 us = LCD cycle
32581     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
32582     $2 20_US                   \    wait 40 us = LCD cycle
32583     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
32584     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
32585     LCD_Clear                   \ 10- "LCD_Clear"
32586     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
32587     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
32588     LCD_Clear                   \ 10- "LCD_Clear"
32589     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
32590     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
32591     CR ." I love you"   
32592     ['] (CR) IS CR              \ ' (CR) is CR
32593     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
32594     CR
32595     ."    RC5toLCD is running. Type STOP to quit"
32596 \    NOECHO                      \ uncomment to run this app without terminal connexion
32597     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
32598     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
32599 ;
32600     \
32601
32602 : STOP                  \ stops multitasking, must to be used before downloading app
32603     ['] (WARM) IS WARM  \ remove START app from FORTH init process
32604     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
32605 ;
32606     \
32607
32608
32609 RST_STATE   ;
32610
32611
32612 CODE MAX    \    n1 n2 -- n3       signed maximum
32613             CMP     @PSP,TOS    \ n2-n1
32614             S<      ?GOTO FW1   \ n2<n1
32615 BW1         ADD     #2,PSP
32616             MOV     @IP+,PC
32617 ENDCODE
32618     \
32619
32620 CODE MIN    \    n1 n2 -- n3       signed minimum
32621             CMP     @PSP,TOS     \ n2-n1
32622             S<      ?GOTO BW1    \ n2<n1
32623 FW1         MOV     @PSP+,TOS
32624             MOV     @IP+,PC
32625 ENDCODE
32626     \
32627
32628 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
32629   >R  <# 0 # #S #>  
32630   R> OVER - 0 MAX SPACES TYPE
32631 ;
32632     \
32633
32634 CODE 20_US                      \ n --      n * 20 us
32635 BEGIN                           \ 3 cycles loop + 6~  
32636 \    MOV     #5,W                \ 3 MCLK = 1 MHz
32637 \    MOV     #23,W               \ 3 MCLK = 4 MHz
32638     MOV     #51,W               \ 3 MCLK = 8 MHz
32639 \    MOV     #104,W              \ 3 MCLK = 16 MHz
32640 \    MOV     #158,W              \ 3 MCLK = 24 MHz
32641     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
32642         SUB #1,W                \ 1
32643     0= UNTIL                    \ 2
32644     SUB     #1,TOS              \ 1
32645 0= UNTIL                        \ 2
32646     MOV     @PSP+,TOS           \ 2
32647     MOV     @IP+,PC             \ 4
32648 ENDCODE
32649     \
32650
32651 CODE TOP_LCD                    \ LCD Sample
32652 \                               \ if write : %xxxxWWWW --
32653 \                               \ if read  : -- %0000RRRR
32654     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
32655     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
32656 0= IF                           \ write LCD bits pattern
32657     AND.B #LCD_DB,TOS           \ 
32658     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
32659     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
32660     MOV @PSP+,TOS               \
32661     MOV @IP+,PC
32662 THEN                            \ read LCD bits pattern
32663     SUB #2,PSP
32664     MOV TOS,0(PSP)
32665     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
32666     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
32667     AND.B #LCD_DB,TOS           \
32668     MOV @IP+,PC
32669 ENDCODE
32670     \
32671
32672 CODE LCD_W                      \ byte --       write byte to LCD 
32673     SUB #2,PSP                  \
32674     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
32675     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
32676     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
32677     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
32678 COLON                           \ high level word starts here 
32679     TOP_LCD 2 20_US             \ write high nibble first
32680     TOP_LCD 2 20_US 
32681 ;
32682     \
32683
32684 CODE LCD_WrC                    \ char --         Write Char
32685     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
32686     JMP LCD_W 
32687 ENDCODE
32688     \
32689
32690 CODE LCD_WrF                    \ func --         Write Fonction
32691     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
32692     JMP LCD_W 
32693 ENDCODE
32694     \
32695
32696 : LCD_Clear 
32697     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
32698 ;
32699     \
32700
32701 : LCD_Home 
32702     $02 LCD_WrF 100 20_us 
32703 ;
32704     \
32705
32706 \ : LCD_Entry_set       $04 OR LCD_WrF ;
32707
32708 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
32709
32710 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
32711
32712 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
32713
32714 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
32715
32716 \ : LCD_Goto            $80 OR LCD_WrF ;
32717
32718 \ CODE LCD_R                      \ -- byte       read byte from LCD
32719 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
32720 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
32721 \ COLON                           \ starts a FORTH word
32722 \     TOP_LCD 2 20_us             \ -- %0000HHHH
32723 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
32724 \ HI2LO                           \ switch from FORTH to assembler
32725 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
32726 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
32727 \     MOV @RSP+,IP                \ restore IP saved by COLON
32728 \     MOV @IP+,PC                 \
32729 \ ENDCODE
32730 \     \
32731
32732 \ CODE LCD_RdS                    \ -- status       Read Status
32733 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
32734 \     JMP LCD_R
32735 \ ENDCODE
32736 \     \
32737
32738 \ CODE LCD_RdC                    \ -- char         Read Char
32739 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
32740 \     JMP LCD_R
32741 \ ENDCODE
32742 \     \
32743
32744 \ -------------+------+------+------+------++---+---+---+---+---------+
32745 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
32746 \ -------------+------+------+------+------++---+---+---+---+---------+
32747 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
32748 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
32749 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
32750 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
32751 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
32752 \ -------------+------+------+------+------++---+---+---+---+---------+
32753
32754
32755 \ ******************************\
32756 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
32757 \ ******************************\
32758 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
32759 \ ------------------------------\
32760 \ define LPM mode for ACCEPT    \
32761 \ ------------------------------\
32762 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
32763 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
32764 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
32765 BIT.B #SW2,&SW2_IN              \ test switch S2
32766 0= IF                           \ case of switch S2 pressed
32767     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
32768     U< IF
32769         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
32770     THEN
32771 ELSE
32772     BIT.B #SW1,&SW1_IN          \ test switch S1 input
32773     0= IF                       \ case of Switch S1 pressed
32774         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
32775         U>= IF                  \
32776             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
32777         THEN                    \
32778     THEN                        \
32779 THEN                            \
32780 RETI                            \ CPU is ON, GIE is OFF
32781 ENDASM                          \
32782     \
32783
32784
32785 \ ------------------------------\
32786 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
32787 \ ******************************\
32788 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
32789 \ ******************************\
32790 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
32791 \                               \       SMclock = 8|16|24 MHz
32792 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
32793 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
32794 \                               \       SR(9)=new Toggle bit memory (ADD on)
32795 \ ------------------------------\
32796 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
32797 \ ------------------------------\
32798 \ define LPM mode for ACCEPT    \
32799 \ ------------------------------\
32800 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
32801 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
32802 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
32803 \ ------------------------------\
32804 \ RC5_FirstStartBitHalfCycle:   \
32805 \ ------------------------------\
32806 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
32807 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
32808 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
32809 MOV     #1778,X                 \ RC5_Period in us
32810 MOV     #14,W                   \ count of loop
32811 BEGIN                           \
32812 \ ------------------------------\
32813 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
32814 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
32815     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
32816 \ RC5_Compute_3/4_Period:       \                   |
32817     RRUM    #1,X                \ X=1/2 cycle       |
32818     MOV     X,Y                 \ Y=1/2             ^
32819     RRUM    #1,Y                \ Y=1/4
32820     ADD     X,Y                 \ Y=3/4
32821 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
32822     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
32823     0= UNTIL                    \
32824 \ ------------------------------\
32825 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
32826 \ ------------------------------\
32827     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
32828     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
32829     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
32830     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
32831     SUB     #1,W                \ decrement count loop
32832 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
32833 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
32834 0<> WHILE                       \ ----> out of loop ----+
32835 \ RC5_compute_7/4_Time_out:     \                       |
32836     ADD     X,Y                 \                       |   out of bound = 7/4 period 
32837 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
32838     BEGIN                       \                       |
32839         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
32840         0>= IF                  \                       |   if cycle time out of bound
32841             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
32842             RETI                \                       |   then quit to do nothing
32843         THEN                    \                       |
32844 \ ------------------------------\                       |
32845         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
32846     0<> UNTIL                   \                   |   |
32847     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
32848 REPEAT                          \ ----> loop back --+   |
32849 \ ------------------------------\                       |
32850 \ RC5_SampleEndOf:              \ <---------------------+
32851 \ ------------------------------\
32852 BIC     #$30,&TA0CTL           \ stop timer_A0
32853 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
32854 \ ******************************\
32855 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
32856 \ ******************************\
32857 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
32858 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
32859 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
32860 BIT     #BIT13,X                \ X(13) = New_RC5_command
32861 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
32862 THEN                            \
32863 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
32864 \ ******************************\
32865 \ RC5_ComputeNewRC5word         \
32866 \ ******************************\
32867 SUB     #4,PSP                  \
32868 MOV     &BASE,2(PSP)            \ save variable BASE before use
32869 MOV     TOS,0(PSP)              \ save TOS before use
32870 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
32871 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
32872 \ ******************************\
32873 \ RC5_ComputeC6bit              \
32874 \ ******************************\
32875 BIT     #$4000,IP              \ test /C6 bit in IP
32876 0= IF   BIS #$40,TOS           \ set C6 bit in S
32877 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
32878 \ ******************************\
32879 \ RC5_CommandByteIsDone         \ RC5_code --
32880 \ ******************************\
32881
32882 \ ------------------------------\
32883 \ Display IR_RC5 code           \
32884 \ ------------------------------\
32885 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
32886 \ ------------------------------\
32887 LO2HI                           \ switch from assembler to FORTH
32888     ['] LCD_CLEAR IS CR         \ redirects CR
32889     ['] LCD_WrC  IS EMIT        \ redirects EMIT
32890     $10 BASE !                 \ change BASE to hexadecimal
32891     CR ." $" 2 U.R             \ print IR_RC5 code
32892     ['] (CR) IS CR              \ restore CR
32893     ['] (EMIT) IS EMIT          \ restore EMIT
32894 HI2LO                           \ switch from FORTH to assembler
32895 \ ------------------------------\
32896 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
32897 \ ------------------------------\
32898 MOV @PSP+,&BASE                 \ restore variable BASE
32899 RETI                            \ CPU is ON, GIE is OFF
32900 ENDASM                          \
32901     \ 
32902
32903 CODE START                      \
32904 \ ------------------------------\
32905 \ TB0CTL = %0000 0010 1001 0100\$3C0
32906 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
32907 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
32908 \                      --       \ID input divider \ 10 = /4
32909 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
32910 \                            -  \TBCLR TimerB Clear
32911 \                             - \TBIE
32912 \                              -\TBIFG
32913 \ --------------------------------\\
32914 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
32915 \              --                 \CM Capture Mode
32916 \                --               \CCIS
32917 \                   -             \SCS
32918 \                    --           \CLLD
32919 \                      -          \CAP
32920 \                        ---      \OUTMOD \ 011 = set/reset
32921 \                           -     \CCIE
32922 \                             -   \CCI
32923 \                              -  \OUT
32924 \                               - \COV
32925 \                                -\CCIFG
32926 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
32927 \ TB0EX0                          \$3E0 
32928 \ ------------------------------\
32929 \ set TimerB to make 50kHz PWM  \
32930 \ ------------------------------\
32931 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
32932 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
32933 \ ------------------------------\
32934 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
32935 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
32936 \ ------------------------------\
32937     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
32938     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
32939 \ ------------------------------\
32940 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
32941 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
32942 \ ------------------------------\
32943 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
32944 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
32945 \ ------------------------------\
32946     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
32947 \ ------------------------------\
32948 \ set TimerB to generate PWM for LCD_Vo
32949 \ ------------------------------\
32950     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
32951 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
32952     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
32953 \ ------------------------------\
32954     BIS.B #LCDVo,&LCDVo_DIR     \
32955     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
32956 \ ------------------------------\
32957     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
32958     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
32959 \ ------------------------------\
32960     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
32961     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
32962 \ ------------------------------\
32963 \ WDT interval init part        \
32964 \ ------------------------------\
32965     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
32966 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
32967 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
32968     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
32969 \ ------------------------------\
32970 \ init RC5_Int                  \
32971 \ ------------------------------\
32972     BIS.B #RC5,&IR_IE           \ enable RC5_Int
32973     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
32974 \ ------------------------------\
32975 \ init interrupt vectors
32976 \ ------------------------------\
32977     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
32978     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
32979 \ ------------------------------\
32980 \ define LPM mode for ACCEPT    \
32981 \ ------------------------------\
32982 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
32983 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
32984 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
32985
32986 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
32987
32988 \ ------------------------------\
32989 \ Init LCD 2x20                 \
32990 \ ------------------------------\
32991     $03E8 20_US                \ 1-  wait 20 ms
32992     $03 TOP_LCD                \ 2- send DB5=DB4=1
32993     $CD 20_US                  \ 3- wait 4,1 ms
32994     $03 TOP_LCD                \ 4- send again DB5=DB4=1
32995     $5 20_US                   \ 5- wait 0,1 ms
32996     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
32997     $2 20_US                   \    wait 40 us = LCD cycle
32998     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
32999     $2 20_US                   \    wait 40 us = LCD cycle
33000     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
33001     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
33002     LCD_Clear                   \ 10- "LCD_Clear"
33003     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
33004     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
33005     LCD_Clear                   \ 10- "LCD_Clear"
33006     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
33007     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
33008     CR ." I love you"   
33009     ['] (CR) IS CR              \ ' (CR) is CR
33010     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
33011     CR
33012     ."    RC5toLCD is running. Type STOP to quit"
33013 \    NOECHO                      \ uncomment to run this app without terminal connexion
33014     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
33015     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
33016 ;
33017     \
33018
33019 : STOP                  \ stops multitasking, must to be used before downloading app
33020     ['] (WARM) IS WARM  \ remove START app from FORTH init process
33021     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
33022 ;
33023     \
33024
33025
33026 RST_STATE   ;
33027
33028
33029 CODE MAX    \    n1 n2 -- n3       signed maximum
33030             CMP     @PSP,TOS    \ n2-n1
33031             S<      ?GOTO FW1   \ n2<n1
33032 BW1         ADD     #2,PSP
33033             MOV     @IP+,PC
33034 ENDCODE
33035     \
33036
33037 CODE MIN    \    n1 n2 -- n3       signed minimum
33038             CMP     @PSP,TOS     \ n2-n1
33039             S<      ?GOTO BW1    \ n2<n1
33040 FW1         MOV     @PSP+,TOS
33041             MOV     @IP+,PC
33042 ENDCODE
33043     \
33044
33045 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
33046   >R  <# 0 # #S #>  
33047   R> OVER - 0 MAX SPACES TYPE
33048 ;
33049     \
33050
33051 CODE 20_US                      \ n --      n * 20 us
33052 BEGIN                           \ 3 cycles loop + 6~  
33053 \    MOV     #5,W                \ 3 MCLK = 1 MHz
33054 \    MOV     #23,W               \ 3 MCLK = 4 MHz
33055     MOV     #51,W               \ 3 MCLK = 8 MHz
33056 \    MOV     #104,W              \ 3 MCLK = 16 MHz
33057 \    MOV     #158,W              \ 3 MCLK = 24 MHz
33058     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
33059         SUB #1,W                \ 1
33060     0= UNTIL                    \ 2
33061     SUB     #1,TOS              \ 1
33062 0= UNTIL                        \ 2
33063     MOV     @PSP+,TOS           \ 2
33064     MOV     @IP+,PC             \ 4
33065 ENDCODE
33066     \
33067
33068 CODE TOP_LCD                    \ LCD Sample
33069 \                               \ if write : %xxxxWWWW --
33070 \                               \ if read  : -- %0000RRRR
33071     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
33072     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
33073 0= IF                           \ write LCD bits pattern
33074     AND.B #LCD_DB,TOS           \ 
33075     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
33076     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
33077     MOV @PSP+,TOS               \
33078     MOV @IP+,PC
33079 THEN                            \ read LCD bits pattern
33080     SUB #2,PSP
33081     MOV TOS,0(PSP)
33082     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
33083     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
33084     AND.B #LCD_DB,TOS           \
33085     MOV @IP+,PC
33086 ENDCODE
33087     \
33088
33089 CODE LCD_W                      \ byte --       write byte to LCD 
33090     SUB #2,PSP                  \
33091     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
33092     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
33093     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
33094     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
33095 COLON                           \ high level word starts here 
33096     TOP_LCD 2 20_US             \ write high nibble first
33097     TOP_LCD 2 20_US 
33098 ;
33099     \
33100
33101 CODE LCD_WrC                    \ char --         Write Char
33102     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
33103     JMP LCD_W 
33104 ENDCODE
33105     \
33106
33107 CODE LCD_WrF                    \ func --         Write Fonction
33108     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
33109     JMP LCD_W 
33110 ENDCODE
33111     \
33112
33113 : LCD_Clear 
33114     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
33115 ;
33116     \
33117
33118 : LCD_Home 
33119     $02 LCD_WrF 100 20_us 
33120 ;
33121     \
33122
33123 \ : LCD_Entry_set       $04 OR LCD_WrF ;
33124
33125 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
33126
33127 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
33128
33129 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
33130
33131 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
33132
33133 \ : LCD_Goto            $80 OR LCD_WrF ;
33134
33135 \ CODE LCD_R                      \ -- byte       read byte from LCD
33136 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
33137 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
33138 \ COLON                           \ starts a FORTH word
33139 \     TOP_LCD 2 20_us             \ -- %0000HHHH
33140 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
33141 \ HI2LO                           \ switch from FORTH to assembler
33142 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
33143 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
33144 \     MOV @RSP+,IP                \ restore IP saved by COLON
33145 \     MOV @IP+,PC                 \
33146 \ ENDCODE
33147 \     \
33148
33149 \ CODE LCD_RdS                    \ -- status       Read Status
33150 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
33151 \     JMP LCD_R
33152 \ ENDCODE
33153 \     \
33154
33155 \ CODE LCD_RdC                    \ -- char         Read Char
33156 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
33157 \     JMP LCD_R
33158 \ ENDCODE
33159 \     \
33160
33161 \ -------------+------+------+------+------++---+---+---+---+---------+
33162 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
33163 \ -------------+------+------+------+------++---+---+---+---+---------+
33164 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
33165 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
33166 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
33167 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
33168 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
33169 \ -------------+------+------+------+------++---+---+---+---+---------+
33170
33171
33172 \ ******************************\
33173 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
33174 \ ******************************\
33175 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
33176 \ ------------------------------\
33177 \ define LPM mode for ACCEPT    \
33178 \ ------------------------------\
33179 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
33180 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
33181 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
33182 BIT.B #SW2,&SW2_IN              \ test switch S2
33183 0= IF                           \ case of switch S2 pressed
33184     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
33185     U< IF
33186         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
33187     THEN
33188 ELSE
33189     BIT.B #SW1,&SW1_IN          \ test switch S1 input
33190     0= IF                       \ case of Switch S1 pressed
33191         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
33192         U>= IF                  \
33193             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
33194         THEN                    \
33195     THEN                        \
33196 THEN                            \
33197 RETI                            \ CPU is ON, GIE is OFF
33198 ENDASM                          \
33199     \
33200
33201
33202 \ ------------------------------\
33203 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
33204 \ ******************************\
33205 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
33206 \ ******************************\
33207 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
33208 \                               \       SMclock = 8|16|24 MHz
33209 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
33210 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
33211 \                               \       SR(9)=new Toggle bit memory (ADD on)
33212 \ ------------------------------\
33213 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
33214 \ ------------------------------\
33215 \ define LPM mode for ACCEPT    \
33216 \ ------------------------------\
33217 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
33218 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
33219 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
33220 \ ------------------------------\
33221 \ RC5_FirstStartBitHalfCycle:   \
33222 \ ------------------------------\
33223 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
33224 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
33225 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
33226 MOV     #1778,X                 \ RC5_Period in us
33227 MOV     #14,W                   \ count of loop
33228 BEGIN                           \
33229 \ ------------------------------\
33230 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
33231 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
33232     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
33233 \ RC5_Compute_3/4_Period:       \                   |
33234     RRUM    #1,X                \ X=1/2 cycle       |
33235     MOV     X,Y                 \ Y=1/2             ^
33236     RRUM    #1,Y                \ Y=1/4
33237     ADD     X,Y                 \ Y=3/4
33238 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
33239     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
33240     0= UNTIL                    \
33241 \ ------------------------------\
33242 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
33243 \ ------------------------------\
33244     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
33245     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
33246     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
33247     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
33248     SUB     #1,W                \ decrement count loop
33249 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
33250 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
33251 0<> WHILE                       \ ----> out of loop ----+
33252 \ RC5_compute_7/4_Time_out:     \                       |
33253     ADD     X,Y                 \                       |   out of bound = 7/4 period 
33254 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
33255     BEGIN                       \                       |
33256         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
33257         0>= IF                  \                       |   if cycle time out of bound
33258             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
33259             RETI                \                       |   then quit to do nothing
33260         THEN                    \                       |
33261 \ ------------------------------\                       |
33262         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
33263     0<> UNTIL                   \                   |   |
33264     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
33265 REPEAT                          \ ----> loop back --+   |
33266 \ ------------------------------\                       |
33267 \ RC5_SampleEndOf:              \ <---------------------+
33268 \ ------------------------------\
33269 BIC     #$30,&TA0CTL           \ stop timer_A0
33270 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
33271 \ ******************************\
33272 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
33273 \ ******************************\
33274 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
33275 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
33276 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
33277 BIT     #BIT13,X                \ X(13) = New_RC5_command
33278 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
33279 THEN                            \
33280 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
33281 \ ******************************\
33282 \ RC5_ComputeNewRC5word         \
33283 \ ******************************\
33284 SUB     #4,PSP                  \
33285 MOV     &BASE,2(PSP)            \ save variable BASE before use
33286 MOV     TOS,0(PSP)              \ save TOS before use
33287 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
33288 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
33289 \ ******************************\
33290 \ RC5_ComputeC6bit              \
33291 \ ******************************\
33292 BIT     #$4000,IP              \ test /C6 bit in IP
33293 0= IF   BIS #$40,TOS           \ set C6 bit in S
33294 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
33295 \ ******************************\
33296 \ RC5_CommandByteIsDone         \ RC5_code --
33297 \ ******************************\
33298
33299 \ ------------------------------\
33300 \ Display IR_RC5 code           \
33301 \ ------------------------------\
33302 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
33303 \ ------------------------------\
33304 LO2HI                           \ switch from assembler to FORTH
33305     ['] LCD_CLEAR IS CR         \ redirects CR
33306     ['] LCD_WrC  IS EMIT        \ redirects EMIT
33307     $10 BASE !                 \ change BASE to hexadecimal
33308     CR ." $" 2 U.R             \ print IR_RC5 code
33309     ['] (CR) IS CR              \ restore CR
33310     ['] (EMIT) IS EMIT          \ restore EMIT
33311 HI2LO                           \ switch from FORTH to assembler
33312 \ ------------------------------\
33313 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
33314 \ ------------------------------\
33315 MOV @PSP+,&BASE                 \ restore variable BASE
33316 RETI                            \ CPU is ON, GIE is OFF
33317 ENDASM                          \
33318     \ 
33319
33320 CODE START                      \
33321 \ ------------------------------\
33322 \ TB0CTL = %0000 0010 1001 0100\$3C0
33323 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
33324 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
33325 \                      --       \ID input divider \ 10 = /4
33326 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
33327 \                            -  \TBCLR TimerB Clear
33328 \                             - \TBIE
33329 \                              -\TBIFG
33330 \ --------------------------------\\
33331 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
33332 \              --                 \CM Capture Mode
33333 \                --               \CCIS
33334 \                   -             \SCS
33335 \                    --           \CLLD
33336 \                      -          \CAP
33337 \                        ---      \OUTMOD \ 011 = set/reset
33338 \                           -     \CCIE
33339 \                             -   \CCI
33340 \                              -  \OUT
33341 \                               - \COV
33342 \                                -\CCIFG
33343 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
33344 \ TB0EX0                          \$3E0 
33345 \ ------------------------------\
33346 \ set TimerB to make 50kHz PWM  \
33347 \ ------------------------------\
33348 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
33349 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
33350 \ ------------------------------\
33351 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
33352 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
33353 \ ------------------------------\
33354     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
33355     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
33356 \ ------------------------------\
33357 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
33358 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
33359 \ ------------------------------\
33360 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
33361 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
33362 \ ------------------------------\
33363     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
33364 \ ------------------------------\
33365 \ set TimerB to generate PWM for LCD_Vo
33366 \ ------------------------------\
33367     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
33368 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
33369     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
33370 \ ------------------------------\
33371     BIS.B #LCDVo,&LCDVo_DIR     \
33372     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
33373 \ ------------------------------\
33374     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
33375     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
33376 \ ------------------------------\
33377     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
33378     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
33379 \ ------------------------------\
33380 \ WDT interval init part        \
33381 \ ------------------------------\
33382     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
33383 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
33384 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
33385     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
33386 \ ------------------------------\
33387 \ init RC5_Int                  \
33388 \ ------------------------------\
33389     BIS.B #RC5,&IR_IE           \ enable RC5_Int
33390     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
33391 \ ------------------------------\
33392 \ init interrupt vectors
33393 \ ------------------------------\
33394     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
33395     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
33396 \ ------------------------------\
33397 \ define LPM mode for ACCEPT    \
33398 \ ------------------------------\
33399 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
33400 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
33401 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
33402
33403 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
33404
33405 \ ------------------------------\
33406 \ Init LCD 2x20                 \
33407 \ ------------------------------\
33408     $03E8 20_US                \ 1-  wait 20 ms
33409     $03 TOP_LCD                \ 2- send DB5=DB4=1
33410     $CD 20_US                  \ 3- wait 4,1 ms
33411     $03 TOP_LCD                \ 4- send again DB5=DB4=1
33412     $5 20_US                   \ 5- wait 0,1 ms
33413     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
33414     $2 20_US                   \    wait 40 us = LCD cycle
33415     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
33416     $2 20_US                   \    wait 40 us = LCD cycle
33417     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
33418     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
33419     LCD_Clear                   \ 10- "LCD_Clear"
33420     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
33421     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
33422     LCD_Clear                   \ 10- "LCD_Clear"
33423     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
33424     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
33425     CR ." I love you"   
33426     ['] (CR) IS CR              \ ' (CR) is CR
33427     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
33428     CR
33429     ."    RC5toLCD is running. Type STOP to quit"
33430 \    NOECHO                      \ uncomment to run this app without terminal connexion
33431     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
33432     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
33433 ;
33434     \
33435
33436 : STOP                  \ stops multitasking, must to be used before downloading app
33437     ['] (WARM) IS WARM  \ remove START app from FORTH init process
33438     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
33439 ;
33440     \
33441
33442
33443 RST_STATE   ;
33444
33445
33446 CODE MAX    \    n1 n2 -- n3       signed maximum
33447             CMP     @PSP,TOS    \ n2-n1
33448             S<      ?GOTO FW1   \ n2<n1
33449 BW1         ADD     #2,PSP
33450             MOV     @IP+,PC
33451 ENDCODE
33452     \
33453
33454 CODE MIN    \    n1 n2 -- n3       signed minimum
33455             CMP     @PSP,TOS     \ n2-n1
33456             S<      ?GOTO BW1    \ n2<n1
33457 FW1         MOV     @PSP+,TOS
33458             MOV     @IP+,PC
33459 ENDCODE
33460     \
33461
33462 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
33463   >R  <# 0 # #S #>  
33464   R> OVER - 0 MAX SPACES TYPE
33465 ;
33466     \
33467
33468 CODE 20_US                      \ n --      n * 20 us
33469 BEGIN                           \ 3 cycles loop + 6~  
33470 \    MOV     #5,W                \ 3 MCLK = 1 MHz
33471 \    MOV     #23,W               \ 3 MCLK = 4 MHz
33472     MOV     #51,W               \ 3 MCLK = 8 MHz
33473 \    MOV     #104,W              \ 3 MCLK = 16 MHz
33474 \    MOV     #158,W              \ 3 MCLK = 24 MHz
33475     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
33476         SUB #1,W                \ 1
33477     0= UNTIL                    \ 2
33478     SUB     #1,TOS              \ 1
33479 0= UNTIL                        \ 2
33480     MOV     @PSP+,TOS           \ 2
33481     MOV     @IP+,PC             \ 4
33482 ENDCODE
33483     \
33484
33485 CODE TOP_LCD                    \ LCD Sample
33486 \                               \ if write : %xxxxWWWW --
33487 \                               \ if read  : -- %0000RRRR
33488     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
33489     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
33490 0= IF                           \ write LCD bits pattern
33491     AND.B #LCD_DB,TOS           \ 
33492     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
33493     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
33494     MOV @PSP+,TOS               \
33495     MOV @IP+,PC
33496 THEN                            \ read LCD bits pattern
33497     SUB #2,PSP
33498     MOV TOS,0(PSP)
33499     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
33500     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
33501     AND.B #LCD_DB,TOS           \
33502     MOV @IP+,PC
33503 ENDCODE
33504     \
33505
33506 CODE LCD_W                      \ byte --       write byte to LCD 
33507     SUB #2,PSP                  \
33508     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
33509     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
33510     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
33511     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
33512 COLON                           \ high level word starts here 
33513     TOP_LCD 2 20_US             \ write high nibble first
33514     TOP_LCD 2 20_US 
33515 ;
33516     \
33517
33518 CODE LCD_WrC                    \ char --         Write Char
33519     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
33520     JMP LCD_W 
33521 ENDCODE
33522     \
33523
33524 CODE LCD_WrF                    \ func --         Write Fonction
33525     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
33526     JMP LCD_W 
33527 ENDCODE
33528     \
33529
33530 : LCD_Clear 
33531     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
33532 ;
33533     \
33534
33535 : LCD_Home 
33536     $02 LCD_WrF 100 20_us 
33537 ;
33538     \
33539
33540 \ : LCD_Entry_set       $04 OR LCD_WrF ;
33541
33542 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
33543
33544 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
33545
33546 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
33547
33548 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
33549
33550 \ : LCD_Goto            $80 OR LCD_WrF ;
33551
33552 \ CODE LCD_R                      \ -- byte       read byte from LCD
33553 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
33554 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
33555 \ COLON                           \ starts a FORTH word
33556 \     TOP_LCD 2 20_us             \ -- %0000HHHH
33557 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
33558 \ HI2LO                           \ switch from FORTH to assembler
33559 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
33560 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
33561 \     MOV @RSP+,IP                \ restore IP saved by COLON
33562 \     MOV @IP+,PC                 \
33563 \ ENDCODE
33564 \     \
33565
33566 \ CODE LCD_RdS                    \ -- status       Read Status
33567 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
33568 \     JMP LCD_R
33569 \ ENDCODE
33570 \     \
33571
33572 \ CODE LCD_RdC                    \ -- char         Read Char
33573 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
33574 \     JMP LCD_R
33575 \ ENDCODE
33576 \     \
33577
33578 \ -------------+------+------+------+------++---+---+---+---+---------+
33579 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
33580 \ -------------+------+------+------+------++---+---+---+---+---------+
33581 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
33582 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
33583 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
33584 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
33585 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
33586 \ -------------+------+------+------+------++---+---+---+---+---------+
33587
33588
33589 \ ******************************\
33590 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
33591 \ ******************************\
33592 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
33593 \ ------------------------------\
33594 \ define LPM mode for ACCEPT    \
33595 \ ------------------------------\
33596 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
33597 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
33598 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
33599 BIT.B #SW2,&SW2_IN              \ test switch S2
33600 0= IF                           \ case of switch S2 pressed
33601     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
33602     U< IF
33603         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
33604     THEN
33605 ELSE
33606     BIT.B #SW1,&SW1_IN          \ test switch S1 input
33607     0= IF                       \ case of Switch S1 pressed
33608         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
33609         U>= IF                  \
33610             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
33611         THEN                    \
33612     THEN                        \
33613 THEN                            \
33614 RETI                            \ CPU is ON, GIE is OFF
33615 ENDASM                          \
33616     \
33617
33618
33619 \ ------------------------------\
33620 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
33621 \ ******************************\
33622 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
33623 \ ******************************\
33624 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
33625 \                               \       SMclock = 8|16|24 MHz
33626 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
33627 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
33628 \                               \       SR(9)=new Toggle bit memory (ADD on)
33629 \ ------------------------------\
33630 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
33631 \ ------------------------------\
33632 \ define LPM mode for ACCEPT    \
33633 \ ------------------------------\
33634 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
33635 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
33636 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
33637 \ ------------------------------\
33638 \ RC5_FirstStartBitHalfCycle:   \
33639 \ ------------------------------\
33640 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
33641 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
33642 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
33643 MOV     #1778,X                 \ RC5_Period in us
33644 MOV     #14,W                   \ count of loop
33645 BEGIN                           \
33646 \ ------------------------------\
33647 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
33648 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
33649     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
33650 \ RC5_Compute_3/4_Period:       \                   |
33651     RRUM    #1,X                \ X=1/2 cycle       |
33652     MOV     X,Y                 \ Y=1/2             ^
33653     RRUM    #1,Y                \ Y=1/4
33654     ADD     X,Y                 \ Y=3/4
33655 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
33656     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
33657     0= UNTIL                    \
33658 \ ------------------------------\
33659 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
33660 \ ------------------------------\
33661     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
33662     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
33663     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
33664     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
33665     SUB     #1,W                \ decrement count loop
33666 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
33667 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
33668 0<> WHILE                       \ ----> out of loop ----+
33669 \ RC5_compute_7/4_Time_out:     \                       |
33670     ADD     X,Y                 \                       |   out of bound = 7/4 period 
33671 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
33672     BEGIN                       \                       |
33673         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
33674         0>= IF                  \                       |   if cycle time out of bound
33675             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
33676             RETI                \                       |   then quit to do nothing
33677         THEN                    \                       |
33678 \ ------------------------------\                       |
33679         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
33680     0<> UNTIL                   \                   |   |
33681     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
33682 REPEAT                          \ ----> loop back --+   |
33683 \ ------------------------------\                       |
33684 \ RC5_SampleEndOf:              \ <---------------------+
33685 \ ------------------------------\
33686 BIC     #$30,&TA0CTL           \ stop timer_A0
33687 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
33688 \ ******************************\
33689 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
33690 \ ******************************\
33691 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
33692 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
33693 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
33694 BIT     #BIT13,X                \ X(13) = New_RC5_command
33695 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
33696 THEN                            \
33697 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
33698 \ ******************************\
33699 \ RC5_ComputeNewRC5word         \
33700 \ ******************************\
33701 SUB     #4,PSP                  \
33702 MOV     &BASE,2(PSP)            \ save variable BASE before use
33703 MOV     TOS,0(PSP)              \ save TOS before use
33704 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
33705 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
33706 \ ******************************\
33707 \ RC5_ComputeC6bit              \
33708 \ ******************************\
33709 BIT     #$4000,IP              \ test /C6 bit in IP
33710 0= IF   BIS #$40,TOS           \ set C6 bit in S
33711 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
33712 \ ******************************\
33713 \ RC5_CommandByteIsDone         \ RC5_code --
33714 \ ******************************\
33715
33716 \ ------------------------------\
33717 \ Display IR_RC5 code           \
33718 \ ------------------------------\
33719 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
33720 \ ------------------------------\
33721 LO2HI                           \ switch from assembler to FORTH
33722     ['] LCD_CLEAR IS CR         \ redirects CR
33723     ['] LCD_WrC  IS EMIT        \ redirects EMIT
33724     $10 BASE !                 \ change BASE to hexadecimal
33725     CR ." $" 2 U.R             \ print IR_RC5 code
33726     ['] (CR) IS CR              \ restore CR
33727     ['] (EMIT) IS EMIT          \ restore EMIT
33728 HI2LO                           \ switch from FORTH to assembler
33729 \ ------------------------------\
33730 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
33731 \ ------------------------------\
33732 MOV @PSP+,&BASE                 \ restore variable BASE
33733 RETI                            \ CPU is ON, GIE is OFF
33734 ENDASM                          \
33735     \ 
33736
33737 CODE START                      \
33738 \ ------------------------------\
33739 \ TB0CTL = %0000 0010 1001 0100\$3C0
33740 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
33741 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
33742 \                      --       \ID input divider \ 10 = /4
33743 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
33744 \                            -  \TBCLR TimerB Clear
33745 \                             - \TBIE
33746 \                              -\TBIFG
33747 \ --------------------------------\\
33748 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
33749 \              --                 \CM Capture Mode
33750 \                --               \CCIS
33751 \                   -             \SCS
33752 \                    --           \CLLD
33753 \                      -          \CAP
33754 \                        ---      \OUTMOD \ 011 = set/reset
33755 \                           -     \CCIE
33756 \                             -   \CCI
33757 \                              -  \OUT
33758 \                               - \COV
33759 \                                -\CCIFG
33760 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
33761 \ TB0EX0                          \$3E0 
33762 \ ------------------------------\
33763 \ set TimerB to make 50kHz PWM  \
33764 \ ------------------------------\
33765 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
33766 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
33767 \ ------------------------------\
33768 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
33769 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
33770 \ ------------------------------\
33771     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
33772     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
33773 \ ------------------------------\
33774 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
33775 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
33776 \ ------------------------------\
33777 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
33778 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
33779 \ ------------------------------\
33780     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
33781 \ ------------------------------\
33782 \ set TimerB to generate PWM for LCD_Vo
33783 \ ------------------------------\
33784     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
33785 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
33786     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
33787 \ ------------------------------\
33788     BIS.B #LCDVo,&LCDVo_DIR     \
33789     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
33790 \ ------------------------------\
33791     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
33792     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
33793 \ ------------------------------\
33794     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
33795     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
33796 \ ------------------------------\
33797 \ WDT interval init part        \
33798 \ ------------------------------\
33799     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
33800 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
33801 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
33802     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
33803 \ ------------------------------\
33804 \ init RC5_Int                  \
33805 \ ------------------------------\
33806     BIS.B #RC5,&IR_IE           \ enable RC5_Int
33807     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
33808 \ ------------------------------\
33809 \ init interrupt vectors
33810 \ ------------------------------\
33811     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
33812     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
33813 \ ------------------------------\
33814 \ define LPM mode for ACCEPT    \
33815 \ ------------------------------\
33816 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
33817 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
33818 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
33819
33820 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
33821
33822 \ ------------------------------\
33823 \ Init LCD 2x20                 \
33824 \ ------------------------------\
33825     $03E8 20_US                \ 1-  wait 20 ms
33826     $03 TOP_LCD                \ 2- send DB5=DB4=1
33827     $CD 20_US                  \ 3- wait 4,1 ms
33828     $03 TOP_LCD                \ 4- send again DB5=DB4=1
33829     $5 20_US                   \ 5- wait 0,1 ms
33830     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
33831     $2 20_US                   \    wait 40 us = LCD cycle
33832     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
33833     $2 20_US                   \    wait 40 us = LCD cycle
33834     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
33835     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
33836     LCD_Clear                   \ 10- "LCD_Clear"
33837     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
33838     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
33839     LCD_Clear                   \ 10- "LCD_Clear"
33840     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
33841     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
33842     CR ." I love you"   
33843     ['] (CR) IS CR              \ ' (CR) is CR
33844     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
33845     CR
33846     ."    RC5toLCD is running. Type STOP to quit"
33847 \    NOECHO                      \ uncomment to run this app without terminal connexion
33848     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
33849     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
33850 ;
33851     \
33852
33853 : STOP                  \ stops multitasking, must to be used before downloading app
33854     ['] (WARM) IS WARM  \ remove START app from FORTH init process
33855     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
33856 ;
33857     \
33858
33859
33860 RST_STATE   ;
33861
33862
33863 CODE MAX    \    n1 n2 -- n3       signed maximum
33864             CMP     @PSP,TOS    \ n2-n1
33865             S<      ?GOTO FW1   \ n2<n1
33866 BW1         ADD     #2,PSP
33867             MOV     @IP+,PC
33868 ENDCODE
33869     \
33870
33871 CODE MIN    \    n1 n2 -- n3       signed minimum
33872             CMP     @PSP,TOS     \ n2-n1
33873             S<      ?GOTO BW1    \ n2<n1
33874 FW1         MOV     @PSP+,TOS
33875             MOV     @IP+,PC
33876 ENDCODE
33877     \
33878
33879 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
33880   >R  <# 0 # #S #>  
33881   R> OVER - 0 MAX SPACES TYPE
33882 ;
33883     \
33884
33885 CODE 20_US                      \ n --      n * 20 us
33886 BEGIN                           \ 3 cycles loop + 6~  
33887 \    MOV     #5,W                \ 3 MCLK = 1 MHz
33888 \    MOV     #23,W               \ 3 MCLK = 4 MHz
33889     MOV     #51,W               \ 3 MCLK = 8 MHz
33890 \    MOV     #104,W              \ 3 MCLK = 16 MHz
33891 \    MOV     #158,W              \ 3 MCLK = 24 MHz
33892     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
33893         SUB #1,W                \ 1
33894     0= UNTIL                    \ 2
33895     SUB     #1,TOS              \ 1
33896 0= UNTIL                        \ 2
33897     MOV     @PSP+,TOS           \ 2
33898     MOV     @IP+,PC             \ 4
33899 ENDCODE
33900     \
33901
33902 CODE TOP_LCD                    \ LCD Sample
33903 \                               \ if write : %xxxxWWWW --
33904 \                               \ if read  : -- %0000RRRR
33905     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
33906     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
33907 0= IF                           \ write LCD bits pattern
33908     AND.B #LCD_DB,TOS           \ 
33909     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
33910     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
33911     MOV @PSP+,TOS               \
33912     MOV @IP+,PC
33913 THEN                            \ read LCD bits pattern
33914     SUB #2,PSP
33915     MOV TOS,0(PSP)
33916     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
33917     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
33918     AND.B #LCD_DB,TOS           \
33919     MOV @IP+,PC
33920 ENDCODE
33921     \
33922
33923 CODE LCD_W                      \ byte --       write byte to LCD 
33924     SUB #2,PSP                  \
33925     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
33926     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
33927     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
33928     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
33929 COLON                           \ high level word starts here 
33930     TOP_LCD 2 20_US             \ write high nibble first
33931     TOP_LCD 2 20_US 
33932 ;
33933     \
33934
33935 CODE LCD_WrC                    \ char --         Write Char
33936     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
33937     JMP LCD_W 
33938 ENDCODE
33939     \
33940
33941 CODE LCD_WrF                    \ func --         Write Fonction
33942     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
33943     JMP LCD_W 
33944 ENDCODE
33945     \
33946
33947 : LCD_Clear 
33948     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
33949 ;
33950     \
33951
33952 : LCD_Home 
33953     $02 LCD_WrF 100 20_us 
33954 ;
33955     \
33956
33957 \ : LCD_Entry_set       $04 OR LCD_WrF ;
33958
33959 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
33960
33961 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
33962
33963 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
33964
33965 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
33966
33967 \ : LCD_Goto            $80 OR LCD_WrF ;
33968
33969 \ CODE LCD_R                      \ -- byte       read byte from LCD
33970 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
33971 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
33972 \ COLON                           \ starts a FORTH word
33973 \     TOP_LCD 2 20_us             \ -- %0000HHHH
33974 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
33975 \ HI2LO                           \ switch from FORTH to assembler
33976 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
33977 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
33978 \     MOV @RSP+,IP                \ restore IP saved by COLON
33979 \     MOV @IP+,PC                 \
33980 \ ENDCODE
33981 \     \
33982
33983 \ CODE LCD_RdS                    \ -- status       Read Status
33984 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
33985 \     JMP LCD_R
33986 \ ENDCODE
33987 \     \
33988
33989 \ CODE LCD_RdC                    \ -- char         Read Char
33990 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
33991 \     JMP LCD_R
33992 \ ENDCODE
33993 \     \
33994
33995 \ -------------+------+------+------+------++---+---+---+---+---------+
33996 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
33997 \ -------------+------+------+------+------++---+---+---+---+---------+
33998 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
33999 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
34000 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
34001 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
34002 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
34003 \ -------------+------+------+------+------++---+---+---+---+---------+
34004
34005
34006 \ ******************************\
34007 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
34008 \ ******************************\
34009 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
34010 \ ------------------------------\
34011 \ define LPM mode for ACCEPT    \
34012 \ ------------------------------\
34013 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
34014 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
34015 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
34016 BIT.B #SW2,&SW2_IN              \ test switch S2
34017 0= IF                           \ case of switch S2 pressed
34018     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
34019     U< IF
34020         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
34021     THEN
34022 ELSE
34023     BIT.B #SW1,&SW1_IN          \ test switch S1 input
34024     0= IF                       \ case of Switch S1 pressed
34025         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
34026         U>= IF                  \
34027             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
34028         THEN                    \
34029     THEN                        \
34030 THEN                            \
34031 RETI                            \ CPU is ON, GIE is OFF
34032 ENDASM                          \
34033     \
34034
34035
34036 \ ------------------------------\
34037 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
34038 \ ******************************\
34039 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
34040 \ ******************************\
34041 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
34042 \                               \       SMclock = 8|16|24 MHz
34043 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
34044 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
34045 \                               \       SR(9)=new Toggle bit memory (ADD on)
34046 \ ------------------------------\
34047 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
34048 \ ------------------------------\
34049 \ define LPM mode for ACCEPT    \
34050 \ ------------------------------\
34051 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
34052 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
34053 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
34054 \ ------------------------------\
34055 \ RC5_FirstStartBitHalfCycle:   \
34056 \ ------------------------------\
34057 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
34058 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
34059 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
34060 MOV     #1778,X                 \ RC5_Period in us
34061 MOV     #14,W                   \ count of loop
34062 BEGIN                           \
34063 \ ------------------------------\
34064 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
34065 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
34066     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
34067 \ RC5_Compute_3/4_Period:       \                   |
34068     RRUM    #1,X                \ X=1/2 cycle       |
34069     MOV     X,Y                 \ Y=1/2             ^
34070     RRUM    #1,Y                \ Y=1/4
34071     ADD     X,Y                 \ Y=3/4
34072 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
34073     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
34074     0= UNTIL                    \
34075 \ ------------------------------\
34076 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
34077 \ ------------------------------\
34078     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
34079     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
34080     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
34081     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
34082     SUB     #1,W                \ decrement count loop
34083 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
34084 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
34085 0<> WHILE                       \ ----> out of loop ----+
34086 \ RC5_compute_7/4_Time_out:     \                       |
34087     ADD     X,Y                 \                       |   out of bound = 7/4 period 
34088 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
34089     BEGIN                       \                       |
34090         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
34091         0>= IF                  \                       |   if cycle time out of bound
34092             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
34093             RETI                \                       |   then quit to do nothing
34094         THEN                    \                       |
34095 \ ------------------------------\                       |
34096         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
34097     0<> UNTIL                   \                   |   |
34098     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
34099 REPEAT                          \ ----> loop back --+   |
34100 \ ------------------------------\                       |
34101 \ RC5_SampleEndOf:              \ <---------------------+
34102 \ ------------------------------\
34103 BIC     #$30,&TA0CTL           \ stop timer_A0
34104 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
34105 \ ******************************\
34106 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
34107 \ ******************************\
34108 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
34109 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
34110 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
34111 BIT     #BIT13,X                \ X(13) = New_RC5_command
34112 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
34113 THEN                            \
34114 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
34115 \ ******************************\
34116 \ RC5_ComputeNewRC5word         \
34117 \ ******************************\
34118 SUB     #4,PSP                  \
34119 MOV     &BASE,2(PSP)            \ save variable BASE before use
34120 MOV     TOS,0(PSP)              \ save TOS before use
34121 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
34122 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
34123 \ ******************************\
34124 \ RC5_ComputeC6bit              \
34125 \ ******************************\
34126 BIT     #$4000,IP              \ test /C6 bit in IP
34127 0= IF   BIS #$40,TOS           \ set C6 bit in S
34128 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
34129 \ ******************************\
34130 \ RC5_CommandByteIsDone         \ RC5_code --
34131 \ ******************************\
34132
34133 \ ------------------------------\
34134 \ Display IR_RC5 code           \
34135 \ ------------------------------\
34136 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
34137 \ ------------------------------\
34138 LO2HI                           \ switch from assembler to FORTH
34139     ['] LCD_CLEAR IS CR         \ redirects CR
34140     ['] LCD_WrC  IS EMIT        \ redirects EMIT
34141     $10 BASE !                 \ change BASE to hexadecimal
34142     CR ." $" 2 U.R             \ print IR_RC5 code
34143     ['] (CR) IS CR              \ restore CR
34144     ['] (EMIT) IS EMIT          \ restore EMIT
34145 HI2LO                           \ switch from FORTH to assembler
34146 \ ------------------------------\
34147 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
34148 \ ------------------------------\
34149 MOV @PSP+,&BASE                 \ restore variable BASE
34150 RETI                            \ CPU is ON, GIE is OFF
34151 ENDASM                          \
34152     \ 
34153
34154 CODE START                      \
34155 \ ------------------------------\
34156 \ TB0CTL = %0000 0010 1001 0100\$3C0
34157 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
34158 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
34159 \                      --       \ID input divider \ 10 = /4
34160 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
34161 \                            -  \TBCLR TimerB Clear
34162 \                             - \TBIE
34163 \                              -\TBIFG
34164 \ --------------------------------\\
34165 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
34166 \              --                 \CM Capture Mode
34167 \                --               \CCIS
34168 \                   -             \SCS
34169 \                    --           \CLLD
34170 \                      -          \CAP
34171 \                        ---      \OUTMOD \ 011 = set/reset
34172 \                           -     \CCIE
34173 \                             -   \CCI
34174 \                              -  \OUT
34175 \                               - \COV
34176 \                                -\CCIFG
34177 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
34178 \ TB0EX0                          \$3E0 
34179 \ ------------------------------\
34180 \ set TimerB to make 50kHz PWM  \
34181 \ ------------------------------\
34182 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
34183 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
34184 \ ------------------------------\
34185 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
34186 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
34187 \ ------------------------------\
34188     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
34189     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
34190 \ ------------------------------\
34191 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
34192 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
34193 \ ------------------------------\
34194 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
34195 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
34196 \ ------------------------------\
34197     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
34198 \ ------------------------------\
34199 \ set TimerB to generate PWM for LCD_Vo
34200 \ ------------------------------\
34201     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
34202 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
34203     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
34204 \ ------------------------------\
34205     BIS.B #LCDVo,&LCDVo_DIR     \
34206     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
34207 \ ------------------------------\
34208     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
34209     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
34210 \ ------------------------------\
34211     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
34212     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
34213 \ ------------------------------\
34214 \ WDT interval init part        \
34215 \ ------------------------------\
34216     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
34217 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
34218 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
34219     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
34220 \ ------------------------------\
34221 \ init RC5_Int                  \
34222 \ ------------------------------\
34223     BIS.B #RC5,&IR_IE           \ enable RC5_Int
34224     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
34225 \ ------------------------------\
34226 \ init interrupt vectors
34227 \ ------------------------------\
34228     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
34229     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
34230 \ ------------------------------\
34231 \ define LPM mode for ACCEPT    \
34232 \ ------------------------------\
34233 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
34234 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
34235 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
34236
34237 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
34238
34239 \ ------------------------------\
34240 \ Init LCD 2x20                 \
34241 \ ------------------------------\
34242     $03E8 20_US                \ 1-  wait 20 ms
34243     $03 TOP_LCD                \ 2- send DB5=DB4=1
34244     $CD 20_US                  \ 3- wait 4,1 ms
34245     $03 TOP_LCD                \ 4- send again DB5=DB4=1
34246     $5 20_US                   \ 5- wait 0,1 ms
34247     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
34248     $2 20_US                   \    wait 40 us = LCD cycle
34249     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
34250     $2 20_US                   \    wait 40 us = LCD cycle
34251     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
34252     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
34253     LCD_Clear                   \ 10- "LCD_Clear"
34254     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
34255     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
34256     LCD_Clear                   \ 10- "LCD_Clear"
34257     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
34258     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
34259     CR ." I love you"   
34260     ['] (CR) IS CR              \ ' (CR) is CR
34261     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
34262     CR
34263     ."    RC5toLCD is running. Type STOP to quit"
34264 \    NOECHO                      \ uncomment to run this app without terminal connexion
34265     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
34266     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
34267 ;
34268     \
34269
34270 : STOP                  \ stops multitasking, must to be used before downloading app
34271     ['] (WARM) IS WARM  \ remove START app from FORTH init process
34272     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
34273 ;
34274     \
34275
34276
34277 RST_STATE   ;
34278
34279
34280 CODE MAX    \    n1 n2 -- n3       signed maximum
34281             CMP     @PSP,TOS    \ n2-n1
34282             S<      ?GOTO FW1   \ n2<n1
34283 BW1         ADD     #2,PSP
34284             MOV     @IP+,PC
34285 ENDCODE
34286     \
34287
34288 CODE MIN    \    n1 n2 -- n3       signed minimum
34289             CMP     @PSP,TOS     \ n2-n1
34290             S<      ?GOTO BW1    \ n2<n1
34291 FW1         MOV     @PSP+,TOS
34292             MOV     @IP+,PC
34293 ENDCODE
34294     \
34295
34296 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
34297   >R  <# 0 # #S #>  
34298   R> OVER - 0 MAX SPACES TYPE
34299 ;
34300     \
34301
34302 CODE 20_US                      \ n --      n * 20 us
34303 BEGIN                           \ 3 cycles loop + 6~  
34304 \    MOV     #5,W                \ 3 MCLK = 1 MHz
34305 \    MOV     #23,W               \ 3 MCLK = 4 MHz
34306     MOV     #51,W               \ 3 MCLK = 8 MHz
34307 \    MOV     #104,W              \ 3 MCLK = 16 MHz
34308 \    MOV     #158,W              \ 3 MCLK = 24 MHz
34309     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
34310         SUB #1,W                \ 1
34311     0= UNTIL                    \ 2
34312     SUB     #1,TOS              \ 1
34313 0= UNTIL                        \ 2
34314     MOV     @PSP+,TOS           \ 2
34315     MOV     @IP+,PC             \ 4
34316 ENDCODE
34317     \
34318
34319 CODE TOP_LCD                    \ LCD Sample
34320 \                               \ if write : %xxxxWWWW --
34321 \                               \ if read  : -- %0000RRRR
34322     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
34323     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
34324 0= IF                           \ write LCD bits pattern
34325     AND.B #LCD_DB,TOS           \ 
34326     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
34327     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
34328     MOV @PSP+,TOS               \
34329     MOV @IP+,PC
34330 THEN                            \ read LCD bits pattern
34331     SUB #2,PSP
34332     MOV TOS,0(PSP)
34333     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
34334     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
34335     AND.B #LCD_DB,TOS           \
34336     MOV @IP+,PC
34337 ENDCODE
34338     \
34339
34340 CODE LCD_W                      \ byte --       write byte to LCD 
34341     SUB #2,PSP                  \
34342     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
34343     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
34344     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
34345     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
34346 COLON                           \ high level word starts here 
34347     TOP_LCD 2 20_US             \ write high nibble first
34348     TOP_LCD 2 20_US 
34349 ;
34350     \
34351
34352 CODE LCD_WrC                    \ char --         Write Char
34353     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
34354     JMP LCD_W 
34355 ENDCODE
34356     \
34357
34358 CODE LCD_WrF                    \ func --         Write Fonction
34359     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
34360     JMP LCD_W 
34361 ENDCODE
34362     \
34363
34364 : LCD_Clear 
34365     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
34366 ;
34367     \
34368
34369 : LCD_Home 
34370     $02 LCD_WrF 100 20_us 
34371 ;
34372     \
34373
34374 \ : LCD_Entry_set       $04 OR LCD_WrF ;
34375
34376 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
34377
34378 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
34379
34380 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
34381
34382 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
34383
34384 \ : LCD_Goto            $80 OR LCD_WrF ;
34385
34386 \ CODE LCD_R                      \ -- byte       read byte from LCD
34387 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
34388 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
34389 \ COLON                           \ starts a FORTH word
34390 \     TOP_LCD 2 20_us             \ -- %0000HHHH
34391 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
34392 \ HI2LO                           \ switch from FORTH to assembler
34393 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
34394 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
34395 \     MOV @RSP+,IP                \ restore IP saved by COLON
34396 \     MOV @IP+,PC                 \
34397 \ ENDCODE
34398 \     \
34399
34400 \ CODE LCD_RdS                    \ -- status       Read Status
34401 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
34402 \     JMP LCD_R
34403 \ ENDCODE
34404 \     \
34405
34406 \ CODE LCD_RdC                    \ -- char         Read Char
34407 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
34408 \     JMP LCD_R
34409 \ ENDCODE
34410 \     \
34411
34412 \ -------------+------+------+------+------++---+---+---+---+---------+
34413 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
34414 \ -------------+------+------+------+------++---+---+---+---+---------+
34415 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
34416 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
34417 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
34418 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
34419 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
34420 \ -------------+------+------+------+------++---+---+---+---+---------+
34421
34422
34423 \ ******************************\
34424 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
34425 \ ******************************\
34426 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
34427 \ ------------------------------\
34428 \ define LPM mode for ACCEPT    \
34429 \ ------------------------------\
34430 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
34431 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
34432 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
34433 BIT.B #SW2,&SW2_IN              \ test switch S2
34434 0= IF                           \ case of switch S2 pressed
34435     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
34436     U< IF
34437         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
34438     THEN
34439 ELSE
34440     BIT.B #SW1,&SW1_IN          \ test switch S1 input
34441     0= IF                       \ case of Switch S1 pressed
34442         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
34443         U>= IF                  \
34444             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
34445         THEN                    \
34446     THEN                        \
34447 THEN                            \
34448 RETI                            \ CPU is ON, GIE is OFF
34449 ENDASM                          \
34450     \
34451
34452
34453 \ ------------------------------\
34454 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
34455 \ ******************************\
34456 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
34457 \ ******************************\
34458 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
34459 \                               \       SMclock = 8|16|24 MHz
34460 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
34461 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
34462 \                               \       SR(9)=new Toggle bit memory (ADD on)
34463 \ ------------------------------\
34464 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
34465 \ ------------------------------\
34466 \ define LPM mode for ACCEPT    \
34467 \ ------------------------------\
34468 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
34469 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
34470 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
34471 \ ------------------------------\
34472 \ RC5_FirstStartBitHalfCycle:   \
34473 \ ------------------------------\
34474 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
34475 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
34476 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
34477 MOV     #1778,X                 \ RC5_Period in us
34478 MOV     #14,W                   \ count of loop
34479 BEGIN                           \
34480 \ ------------------------------\
34481 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
34482 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
34483     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
34484 \ RC5_Compute_3/4_Period:       \                   |
34485     RRUM    #1,X                \ X=1/2 cycle       |
34486     MOV     X,Y                 \ Y=1/2             ^
34487     RRUM    #1,Y                \ Y=1/4
34488     ADD     X,Y                 \ Y=3/4
34489 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
34490     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
34491     0= UNTIL                    \
34492 \ ------------------------------\
34493 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
34494 \ ------------------------------\
34495     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
34496     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
34497     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
34498     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
34499     SUB     #1,W                \ decrement count loop
34500 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
34501 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
34502 0<> WHILE                       \ ----> out of loop ----+
34503 \ RC5_compute_7/4_Time_out:     \                       |
34504     ADD     X,Y                 \                       |   out of bound = 7/4 period 
34505 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
34506     BEGIN                       \                       |
34507         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
34508         0>= IF                  \                       |   if cycle time out of bound
34509             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
34510             RETI                \                       |   then quit to do nothing
34511         THEN                    \                       |
34512 \ ------------------------------\                       |
34513         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
34514     0<> UNTIL                   \                   |   |
34515     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
34516 REPEAT                          \ ----> loop back --+   |
34517 \ ------------------------------\                       |
34518 \ RC5_SampleEndOf:              \ <---------------------+
34519 \ ------------------------------\
34520 BIC     #$30,&TA0CTL           \ stop timer_A0
34521 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
34522 \ ******************************\
34523 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
34524 \ ******************************\
34525 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
34526 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
34527 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
34528 BIT     #BIT13,X                \ X(13) = New_RC5_command
34529 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
34530 THEN                            \
34531 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
34532 \ ******************************\
34533 \ RC5_ComputeNewRC5word         \
34534 \ ******************************\
34535 SUB     #4,PSP                  \
34536 MOV     &BASE,2(PSP)            \ save variable BASE before use
34537 MOV     TOS,0(PSP)              \ save TOS before use
34538 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
34539 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
34540 \ ******************************\
34541 \ RC5_ComputeC6bit              \
34542 \ ******************************\
34543 BIT     #$4000,IP              \ test /C6 bit in IP
34544 0= IF   BIS #$40,TOS           \ set C6 bit in S
34545 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
34546 \ ******************************\
34547 \ RC5_CommandByteIsDone         \ RC5_code --
34548 \ ******************************\
34549
34550 \ ------------------------------\
34551 \ Display IR_RC5 code           \
34552 \ ------------------------------\
34553 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
34554 \ ------------------------------\
34555 LO2HI                           \ switch from assembler to FORTH
34556     ['] LCD_CLEAR IS CR         \ redirects CR
34557     ['] LCD_WrC  IS EMIT        \ redirects EMIT
34558     $10 BASE !                 \ change BASE to hexadecimal
34559     CR ." $" 2 U.R             \ print IR_RC5 code
34560     ['] (CR) IS CR              \ restore CR
34561     ['] (EMIT) IS EMIT          \ restore EMIT
34562 HI2LO                           \ switch from FORTH to assembler
34563 \ ------------------------------\
34564 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
34565 \ ------------------------------\
34566 MOV @PSP+,&BASE                 \ restore variable BASE
34567 RETI                            \ CPU is ON, GIE is OFF
34568 ENDASM                          \
34569     \ 
34570
34571 CODE START                      \
34572 \ ------------------------------\
34573 \ TB0CTL = %0000 0010 1001 0100\$3C0
34574 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
34575 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
34576 \                      --       \ID input divider \ 10 = /4
34577 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
34578 \                            -  \TBCLR TimerB Clear
34579 \                             - \TBIE
34580 \                              -\TBIFG
34581 \ --------------------------------\\
34582 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
34583 \              --                 \CM Capture Mode
34584 \                --               \CCIS
34585 \                   -             \SCS
34586 \                    --           \CLLD
34587 \                      -          \CAP
34588 \                        ---      \OUTMOD \ 011 = set/reset
34589 \                           -     \CCIE
34590 \                             -   \CCI
34591 \                              -  \OUT
34592 \                               - \COV
34593 \                                -\CCIFG
34594 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
34595 \ TB0EX0                          \$3E0 
34596 \ ------------------------------\
34597 \ set TimerB to make 50kHz PWM  \
34598 \ ------------------------------\
34599 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
34600 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
34601 \ ------------------------------\
34602 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
34603 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
34604 \ ------------------------------\
34605     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
34606     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
34607 \ ------------------------------\
34608 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
34609 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
34610 \ ------------------------------\
34611 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
34612 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
34613 \ ------------------------------\
34614     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
34615 \ ------------------------------\
34616 \ set TimerB to generate PWM for LCD_Vo
34617 \ ------------------------------\
34618     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
34619 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
34620     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
34621 \ ------------------------------\
34622     BIS.B #LCDVo,&LCDVo_DIR     \
34623     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
34624 \ ------------------------------\
34625     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
34626     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
34627 \ ------------------------------\
34628     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
34629     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
34630 \ ------------------------------\
34631 \ WDT interval init part        \
34632 \ ------------------------------\
34633     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
34634 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
34635 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
34636     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
34637 \ ------------------------------\
34638 \ init RC5_Int                  \
34639 \ ------------------------------\
34640     BIS.B #RC5,&IR_IE           \ enable RC5_Int
34641     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
34642 \ ------------------------------\
34643 \ init interrupt vectors
34644 \ ------------------------------\
34645     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
34646     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
34647 \ ------------------------------\
34648 \ define LPM mode for ACCEPT    \
34649 \ ------------------------------\
34650 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
34651 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
34652 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
34653
34654 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
34655
34656 \ ------------------------------\
34657 \ Init LCD 2x20                 \
34658 \ ------------------------------\
34659     $03E8 20_US                \ 1-  wait 20 ms
34660     $03 TOP_LCD                \ 2- send DB5=DB4=1
34661     $CD 20_US                  \ 3- wait 4,1 ms
34662     $03 TOP_LCD                \ 4- send again DB5=DB4=1
34663     $5 20_US                   \ 5- wait 0,1 ms
34664     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
34665     $2 20_US                   \    wait 40 us = LCD cycle
34666     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
34667     $2 20_US                   \    wait 40 us = LCD cycle
34668     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
34669     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
34670     LCD_Clear                   \ 10- "LCD_Clear"
34671     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
34672     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
34673     LCD_Clear                   \ 10- "LCD_Clear"
34674     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
34675     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
34676     CR ." I love you"   
34677     ['] (CR) IS CR              \ ' (CR) is CR
34678     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
34679     CR
34680     ."    RC5toLCD is running. Type STOP to quit"
34681 \    NOECHO                      \ uncomment to run this app without terminal connexion
34682     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
34683     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
34684 ;
34685     \
34686
34687 : STOP                  \ stops multitasking, must to be used before downloading app
34688     ['] (WARM) IS WARM  \ remove START app from FORTH init process
34689     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
34690 ;
34691     \
34692
34693
34694 RST_STATE   ;
34695
34696
34697 CODE MAX    \    n1 n2 -- n3       signed maximum
34698             CMP     @PSP,TOS    \ n2-n1
34699             S<      ?GOTO FW1   \ n2<n1
34700 BW1         ADD     #2,PSP
34701             MOV     @IP+,PC
34702 ENDCODE
34703     \
34704
34705 CODE MIN    \    n1 n2 -- n3       signed minimum
34706             CMP     @PSP,TOS     \ n2-n1
34707             S<      ?GOTO BW1    \ n2<n1
34708 FW1         MOV     @PSP+,TOS
34709             MOV     @IP+,PC
34710 ENDCODE
34711     \
34712
34713 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
34714   >R  <# 0 # #S #>  
34715   R> OVER - 0 MAX SPACES TYPE
34716 ;
34717     \
34718
34719 CODE 20_US                      \ n --      n * 20 us
34720 BEGIN                           \ 3 cycles loop + 6~  
34721 \    MOV     #5,W                \ 3 MCLK = 1 MHz
34722 \    MOV     #23,W               \ 3 MCLK = 4 MHz
34723     MOV     #51,W               \ 3 MCLK = 8 MHz
34724 \    MOV     #104,W              \ 3 MCLK = 16 MHz
34725 \    MOV     #158,W              \ 3 MCLK = 24 MHz
34726     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
34727         SUB #1,W                \ 1
34728     0= UNTIL                    \ 2
34729     SUB     #1,TOS              \ 1
34730 0= UNTIL                        \ 2
34731     MOV     @PSP+,TOS           \ 2
34732     MOV     @IP+,PC             \ 4
34733 ENDCODE
34734     \
34735
34736 CODE TOP_LCD                    \ LCD Sample
34737 \                               \ if write : %xxxxWWWW --
34738 \                               \ if read  : -- %0000RRRR
34739     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
34740     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
34741 0= IF                           \ write LCD bits pattern
34742     AND.B #LCD_DB,TOS           \ 
34743     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
34744     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
34745     MOV @PSP+,TOS               \
34746     MOV @IP+,PC
34747 THEN                            \ read LCD bits pattern
34748     SUB #2,PSP
34749     MOV TOS,0(PSP)
34750     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
34751     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
34752     AND.B #LCD_DB,TOS           \
34753     MOV @IP+,PC
34754 ENDCODE
34755     \
34756
34757 CODE LCD_W                      \ byte --       write byte to LCD 
34758     SUB #2,PSP                  \
34759     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
34760     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
34761     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
34762     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
34763 COLON                           \ high level word starts here 
34764     TOP_LCD 2 20_US             \ write high nibble first
34765     TOP_LCD 2 20_US 
34766 ;
34767     \
34768
34769 CODE LCD_WrC                    \ char --         Write Char
34770     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
34771     JMP LCD_W 
34772 ENDCODE
34773     \
34774
34775 CODE LCD_WrF                    \ func --         Write Fonction
34776     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
34777     JMP LCD_W 
34778 ENDCODE
34779     \
34780
34781 : LCD_Clear 
34782     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
34783 ;
34784     \
34785
34786 : LCD_Home 
34787     $02 LCD_WrF 100 20_us 
34788 ;
34789     \
34790
34791 \ : LCD_Entry_set       $04 OR LCD_WrF ;
34792
34793 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
34794
34795 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
34796
34797 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
34798
34799 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
34800
34801 \ : LCD_Goto            $80 OR LCD_WrF ;
34802
34803 \ CODE LCD_R                      \ -- byte       read byte from LCD
34804 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
34805 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
34806 \ COLON                           \ starts a FORTH word
34807 \     TOP_LCD 2 20_us             \ -- %0000HHHH
34808 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
34809 \ HI2LO                           \ switch from FORTH to assembler
34810 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
34811 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
34812 \     MOV @RSP+,IP                \ restore IP saved by COLON
34813 \     MOV @IP+,PC                 \
34814 \ ENDCODE
34815 \     \
34816
34817 \ CODE LCD_RdS                    \ -- status       Read Status
34818 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
34819 \     JMP LCD_R
34820 \ ENDCODE
34821 \     \
34822
34823 \ CODE LCD_RdC                    \ -- char         Read Char
34824 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
34825 \     JMP LCD_R
34826 \ ENDCODE
34827 \     \
34828
34829 \ -------------+------+------+------+------++---+---+---+---+---------+
34830 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
34831 \ -------------+------+------+------+------++---+---+---+---+---------+
34832 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
34833 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
34834 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
34835 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
34836 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
34837 \ -------------+------+------+------+------++---+---+---+---+---------+
34838
34839
34840 \ ******************************\
34841 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
34842 \ ******************************\
34843 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
34844 \ ------------------------------\
34845 \ define LPM mode for ACCEPT    \
34846 \ ------------------------------\
34847 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
34848 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
34849 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
34850 BIT.B #SW2,&SW2_IN              \ test switch S2
34851 0= IF                           \ case of switch S2 pressed
34852     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
34853     U< IF
34854         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
34855     THEN
34856 ELSE
34857     BIT.B #SW1,&SW1_IN          \ test switch S1 input
34858     0= IF                       \ case of Switch S1 pressed
34859         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
34860         U>= IF                  \
34861             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
34862         THEN                    \
34863     THEN                        \
34864 THEN                            \
34865 RETI                            \ CPU is ON, GIE is OFF
34866 ENDASM                          \
34867     \
34868
34869
34870 \ ------------------------------\
34871 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
34872 \ ******************************\
34873 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
34874 \ ******************************\
34875 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
34876 \                               \       SMclock = 8|16|24 MHz
34877 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
34878 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
34879 \                               \       SR(9)=new Toggle bit memory (ADD on)
34880 \ ------------------------------\
34881 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
34882 \ ------------------------------\
34883 \ define LPM mode for ACCEPT    \
34884 \ ------------------------------\
34885 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
34886 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
34887 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
34888 \ ------------------------------\
34889 \ RC5_FirstStartBitHalfCycle:   \
34890 \ ------------------------------\
34891 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
34892 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
34893 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
34894 MOV     #1778,X                 \ RC5_Period in us
34895 MOV     #14,W                   \ count of loop
34896 BEGIN                           \
34897 \ ------------------------------\
34898 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
34899 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
34900     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
34901 \ RC5_Compute_3/4_Period:       \                   |
34902     RRUM    #1,X                \ X=1/2 cycle       |
34903     MOV     X,Y                 \ Y=1/2             ^
34904     RRUM    #1,Y                \ Y=1/4
34905     ADD     X,Y                 \ Y=3/4
34906 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
34907     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
34908     0= UNTIL                    \
34909 \ ------------------------------\
34910 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
34911 \ ------------------------------\
34912     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
34913     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
34914     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
34915     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
34916     SUB     #1,W                \ decrement count loop
34917 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
34918 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
34919 0<> WHILE                       \ ----> out of loop ----+
34920 \ RC5_compute_7/4_Time_out:     \                       |
34921     ADD     X,Y                 \                       |   out of bound = 7/4 period 
34922 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
34923     BEGIN                       \                       |
34924         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
34925         0>= IF                  \                       |   if cycle time out of bound
34926             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
34927             RETI                \                       |   then quit to do nothing
34928         THEN                    \                       |
34929 \ ------------------------------\                       |
34930         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
34931     0<> UNTIL                   \                   |   |
34932     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
34933 REPEAT                          \ ----> loop back --+   |
34934 \ ------------------------------\                       |
34935 \ RC5_SampleEndOf:              \ <---------------------+
34936 \ ------------------------------\
34937 BIC     #$30,&TA0CTL           \ stop timer_A0
34938 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
34939 \ ******************************\
34940 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
34941 \ ******************************\
34942 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
34943 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
34944 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
34945 BIT     #BIT13,X                \ X(13) = New_RC5_command
34946 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
34947 THEN                            \
34948 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
34949 \ ******************************\
34950 \ RC5_ComputeNewRC5word         \
34951 \ ******************************\
34952 SUB     #4,PSP                  \
34953 MOV     &BASE,2(PSP)            \ save variable BASE before use
34954 MOV     TOS,0(PSP)              \ save TOS before use
34955 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
34956 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
34957 \ ******************************\
34958 \ RC5_ComputeC6bit              \
34959 \ ******************************\
34960 BIT     #$4000,IP              \ test /C6 bit in IP
34961 0= IF   BIS #$40,TOS           \ set C6 bit in S
34962 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
34963 \ ******************************\
34964 \ RC5_CommandByteIsDone         \ RC5_code --
34965 \ ******************************\
34966
34967 \ ------------------------------\
34968 \ Display IR_RC5 code           \
34969 \ ------------------------------\
34970 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
34971 \ ------------------------------\
34972 LO2HI                           \ switch from assembler to FORTH
34973     ['] LCD_CLEAR IS CR         \ redirects CR
34974     ['] LCD_WrC  IS EMIT        \ redirects EMIT
34975     $10 BASE !                 \ change BASE to hexadecimal
34976     CR ." $" 2 U.R             \ print IR_RC5 code
34977     ['] (CR) IS CR              \ restore CR
34978     ['] (EMIT) IS EMIT          \ restore EMIT
34979 HI2LO                           \ switch from FORTH to assembler
34980 \ ------------------------------\
34981 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
34982 \ ------------------------------\
34983 MOV @PSP+,&BASE                 \ restore variable BASE
34984 RETI                            \ CPU is ON, GIE is OFF
34985 ENDASM                          \
34986     \ 
34987
34988 CODE START                      \
34989 \ ------------------------------\
34990 \ TB0CTL = %0000 0010 1001 0100\$3C0
34991 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
34992 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
34993 \                      --       \ID input divider \ 10 = /4
34994 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
34995 \                            -  \TBCLR TimerB Clear
34996 \                             - \TBIE
34997 \                              -\TBIFG
34998 \ --------------------------------\\
34999 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
35000 \              --                 \CM Capture Mode
35001 \                --               \CCIS
35002 \                   -             \SCS
35003 \                    --           \CLLD
35004 \                      -          \CAP
35005 \                        ---      \OUTMOD \ 011 = set/reset
35006 \                           -     \CCIE
35007 \                             -   \CCI
35008 \                              -  \OUT
35009 \                               - \COV
35010 \                                -\CCIFG
35011 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
35012 \ TB0EX0                          \$3E0 
35013 \ ------------------------------\
35014 \ set TimerB to make 50kHz PWM  \
35015 \ ------------------------------\
35016 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
35017 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
35018 \ ------------------------------\
35019 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
35020 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
35021 \ ------------------------------\
35022     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
35023     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
35024 \ ------------------------------\
35025 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
35026 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
35027 \ ------------------------------\
35028 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
35029 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
35030 \ ------------------------------\
35031     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
35032 \ ------------------------------\
35033 \ set TimerB to generate PWM for LCD_Vo
35034 \ ------------------------------\
35035     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
35036 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
35037     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
35038 \ ------------------------------\
35039     BIS.B #LCDVo,&LCDVo_DIR     \
35040     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
35041 \ ------------------------------\
35042     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
35043     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
35044 \ ------------------------------\
35045     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
35046     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
35047 \ ------------------------------\
35048 \ WDT interval init part        \
35049 \ ------------------------------\
35050     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
35051 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
35052 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
35053     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
35054 \ ------------------------------\
35055 \ init RC5_Int                  \
35056 \ ------------------------------\
35057     BIS.B #RC5,&IR_IE           \ enable RC5_Int
35058     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
35059 \ ------------------------------\
35060 \ init interrupt vectors
35061 \ ------------------------------\
35062     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
35063     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
35064 \ ------------------------------\
35065 \ define LPM mode for ACCEPT    \
35066 \ ------------------------------\
35067 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
35068 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
35069 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
35070
35071 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
35072
35073 \ ------------------------------\
35074 \ Init LCD 2x20                 \
35075 \ ------------------------------\
35076     $03E8 20_US                \ 1-  wait 20 ms
35077     $03 TOP_LCD                \ 2- send DB5=DB4=1
35078     $CD 20_US                  \ 3- wait 4,1 ms
35079     $03 TOP_LCD                \ 4- send again DB5=DB4=1
35080     $5 20_US                   \ 5- wait 0,1 ms
35081     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
35082     $2 20_US                   \    wait 40 us = LCD cycle
35083     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
35084     $2 20_US                   \    wait 40 us = LCD cycle
35085     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
35086     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
35087     LCD_Clear                   \ 10- "LCD_Clear"
35088     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
35089     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
35090     LCD_Clear                   \ 10- "LCD_Clear"
35091     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
35092     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
35093     CR ." I love you"   
35094     ['] (CR) IS CR              \ ' (CR) is CR
35095     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
35096     CR
35097     ."    RC5toLCD is running. Type STOP to quit"
35098 \    NOECHO                      \ uncomment to run this app without terminal connexion
35099     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
35100     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
35101 ;
35102     \
35103
35104 : STOP                  \ stops multitasking, must to be used before downloading app
35105     ['] (WARM) IS WARM  \ remove START app from FORTH init process
35106     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
35107 ;
35108     \
35109
35110
35111 RST_STATE   ;
35112
35113
35114 CODE MAX    \    n1 n2 -- n3       signed maximum
35115             CMP     @PSP,TOS    \ n2-n1
35116             S<      ?GOTO FW1   \ n2<n1
35117 BW1         ADD     #2,PSP
35118             MOV     @IP+,PC
35119 ENDCODE
35120     \
35121
35122 CODE MIN    \    n1 n2 -- n3       signed minimum
35123             CMP     @PSP,TOS     \ n2-n1
35124             S<      ?GOTO BW1    \ n2<n1
35125 FW1         MOV     @PSP+,TOS
35126             MOV     @IP+,PC
35127 ENDCODE
35128     \
35129
35130 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
35131   >R  <# 0 # #S #>  
35132   R> OVER - 0 MAX SPACES TYPE
35133 ;
35134     \
35135
35136 CODE 20_US                      \ n --      n * 20 us
35137 BEGIN                           \ 3 cycles loop + 6~  
35138 \    MOV     #5,W                \ 3 MCLK = 1 MHz
35139 \    MOV     #23,W               \ 3 MCLK = 4 MHz
35140     MOV     #51,W               \ 3 MCLK = 8 MHz
35141 \    MOV     #104,W              \ 3 MCLK = 16 MHz
35142 \    MOV     #158,W              \ 3 MCLK = 24 MHz
35143     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
35144         SUB #1,W                \ 1
35145     0= UNTIL                    \ 2
35146     SUB     #1,TOS              \ 1
35147 0= UNTIL                        \ 2
35148     MOV     @PSP+,TOS           \ 2
35149     MOV     @IP+,PC             \ 4
35150 ENDCODE
35151     \
35152
35153 CODE TOP_LCD                    \ LCD Sample
35154 \                               \ if write : %xxxxWWWW --
35155 \                               \ if read  : -- %0000RRRR
35156     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
35157     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
35158 0= IF                           \ write LCD bits pattern
35159     AND.B #LCD_DB,TOS           \ 
35160     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
35161     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
35162     MOV @PSP+,TOS               \
35163     MOV @IP+,PC
35164 THEN                            \ read LCD bits pattern
35165     SUB #2,PSP
35166     MOV TOS,0(PSP)
35167     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
35168     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
35169     AND.B #LCD_DB,TOS           \
35170     MOV @IP+,PC
35171 ENDCODE
35172     \
35173
35174 CODE LCD_W                      \ byte --       write byte to LCD 
35175     SUB #2,PSP                  \
35176     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
35177     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
35178     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
35179     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
35180 COLON                           \ high level word starts here 
35181     TOP_LCD 2 20_US             \ write high nibble first
35182     TOP_LCD 2 20_US 
35183 ;
35184     \
35185
35186 CODE LCD_WrC                    \ char --         Write Char
35187     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
35188     JMP LCD_W 
35189 ENDCODE
35190     \
35191
35192 CODE LCD_WrF                    \ func --         Write Fonction
35193     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
35194     JMP LCD_W 
35195 ENDCODE
35196     \
35197
35198 : LCD_Clear 
35199     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
35200 ;
35201     \
35202
35203 : LCD_Home 
35204     $02 LCD_WrF 100 20_us 
35205 ;
35206     \
35207
35208 \ : LCD_Entry_set       $04 OR LCD_WrF ;
35209
35210 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
35211
35212 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
35213
35214 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
35215
35216 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
35217
35218 \ : LCD_Goto            $80 OR LCD_WrF ;
35219
35220 \ CODE LCD_R                      \ -- byte       read byte from LCD
35221 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
35222 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
35223 \ COLON                           \ starts a FORTH word
35224 \     TOP_LCD 2 20_us             \ -- %0000HHHH
35225 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
35226 \ HI2LO                           \ switch from FORTH to assembler
35227 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
35228 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
35229 \     MOV @RSP+,IP                \ restore IP saved by COLON
35230 \     MOV @IP+,PC                 \
35231 \ ENDCODE
35232 \     \
35233
35234 \ CODE LCD_RdS                    \ -- status       Read Status
35235 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
35236 \     JMP LCD_R
35237 \ ENDCODE
35238 \     \
35239
35240 \ CODE LCD_RdC                    \ -- char         Read Char
35241 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
35242 \     JMP LCD_R
35243 \ ENDCODE
35244 \     \
35245
35246 \ -------------+------+------+------+------++---+---+---+---+---------+
35247 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
35248 \ -------------+------+------+------+------++---+---+---+---+---------+
35249 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
35250 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
35251 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
35252 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
35253 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
35254 \ -------------+------+------+------+------++---+---+---+---+---------+
35255
35256
35257 \ ******************************\
35258 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
35259 \ ******************************\
35260 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
35261 \ ------------------------------\
35262 \ define LPM mode for ACCEPT    \
35263 \ ------------------------------\
35264 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
35265 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
35266 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
35267 BIT.B #SW2,&SW2_IN              \ test switch S2
35268 0= IF                           \ case of switch S2 pressed
35269     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
35270     U< IF
35271         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
35272     THEN
35273 ELSE
35274     BIT.B #SW1,&SW1_IN          \ test switch S1 input
35275     0= IF                       \ case of Switch S1 pressed
35276         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
35277         U>= IF                  \
35278             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
35279         THEN                    \
35280     THEN                        \
35281 THEN                            \
35282 RETI                            \ CPU is ON, GIE is OFF
35283 ENDASM                          \
35284     \
35285
35286
35287 \ ------------------------------\
35288 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
35289 \ ******************************\
35290 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
35291 \ ******************************\
35292 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
35293 \                               \       SMclock = 8|16|24 MHz
35294 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
35295 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
35296 \                               \       SR(9)=new Toggle bit memory (ADD on)
35297 \ ------------------------------\
35298 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
35299 \ ------------------------------\
35300 \ define LPM mode for ACCEPT    \
35301 \ ------------------------------\
35302 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
35303 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
35304 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
35305 \ ------------------------------\
35306 \ RC5_FirstStartBitHalfCycle:   \
35307 \ ------------------------------\
35308 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
35309 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
35310 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
35311 MOV     #1778,X                 \ RC5_Period in us
35312 MOV     #14,W                   \ count of loop
35313 BEGIN                           \
35314 \ ------------------------------\
35315 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
35316 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
35317     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
35318 \ RC5_Compute_3/4_Period:       \                   |
35319     RRUM    #1,X                \ X=1/2 cycle       |
35320     MOV     X,Y                 \ Y=1/2             ^
35321     RRUM    #1,Y                \ Y=1/4
35322     ADD     X,Y                 \ Y=3/4
35323 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
35324     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
35325     0= UNTIL                    \
35326 \ ------------------------------\
35327 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
35328 \ ------------------------------\
35329     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
35330     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
35331     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
35332     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
35333     SUB     #1,W                \ decrement count loop
35334 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
35335 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
35336 0<> WHILE                       \ ----> out of loop ----+
35337 \ RC5_compute_7/4_Time_out:     \                       |
35338     ADD     X,Y                 \                       |   out of bound = 7/4 period 
35339 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
35340     BEGIN                       \                       |
35341         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
35342         0>= IF                  \                       |   if cycle time out of bound
35343             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
35344             RETI                \                       |   then quit to do nothing
35345         THEN                    \                       |
35346 \ ------------------------------\                       |
35347         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
35348     0<> UNTIL                   \                   |   |
35349     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
35350 REPEAT                          \ ----> loop back --+   |
35351 \ ------------------------------\                       |
35352 \ RC5_SampleEndOf:              \ <---------------------+
35353 \ ------------------------------\
35354 BIC     #$30,&TA0CTL           \ stop timer_A0
35355 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
35356 \ ******************************\
35357 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
35358 \ ******************************\
35359 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
35360 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
35361 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
35362 BIT     #BIT13,X                \ X(13) = New_RC5_command
35363 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
35364 THEN                            \
35365 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
35366 \ ******************************\
35367 \ RC5_ComputeNewRC5word         \
35368 \ ******************************\
35369 SUB     #4,PSP                  \
35370 MOV     &BASE,2(PSP)            \ save variable BASE before use
35371 MOV     TOS,0(PSP)              \ save TOS before use
35372 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
35373 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
35374 \ ******************************\
35375 \ RC5_ComputeC6bit              \
35376 \ ******************************\
35377 BIT     #$4000,IP              \ test /C6 bit in IP
35378 0= IF   BIS #$40,TOS           \ set C6 bit in S
35379 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
35380 \ ******************************\
35381 \ RC5_CommandByteIsDone         \ RC5_code --
35382 \ ******************************\
35383
35384 \ ------------------------------\
35385 \ Display IR_RC5 code           \
35386 \ ------------------------------\
35387 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
35388 \ ------------------------------\
35389 LO2HI                           \ switch from assembler to FORTH
35390     ['] LCD_CLEAR IS CR         \ redirects CR
35391     ['] LCD_WrC  IS EMIT        \ redirects EMIT
35392     $10 BASE !                 \ change BASE to hexadecimal
35393     CR ." $" 2 U.R             \ print IR_RC5 code
35394     ['] (CR) IS CR              \ restore CR
35395     ['] (EMIT) IS EMIT          \ restore EMIT
35396 HI2LO                           \ switch from FORTH to assembler
35397 \ ------------------------------\
35398 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
35399 \ ------------------------------\
35400 MOV @PSP+,&BASE                 \ restore variable BASE
35401 RETI                            \ CPU is ON, GIE is OFF
35402 ENDASM                          \
35403     \ 
35404
35405 CODE START                      \
35406 \ ------------------------------\
35407 \ TB0CTL = %0000 0010 1001 0100\$3C0
35408 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
35409 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
35410 \                      --       \ID input divider \ 10 = /4
35411 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
35412 \                            -  \TBCLR TimerB Clear
35413 \                             - \TBIE
35414 \                              -\TBIFG
35415 \ --------------------------------\\
35416 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
35417 \              --                 \CM Capture Mode
35418 \                --               \CCIS
35419 \                   -             \SCS
35420 \                    --           \CLLD
35421 \                      -          \CAP
35422 \                        ---      \OUTMOD \ 011 = set/reset
35423 \                           -     \CCIE
35424 \                             -   \CCI
35425 \                              -  \OUT
35426 \                               - \COV
35427 \                                -\CCIFG
35428 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
35429 \ TB0EX0                          \$3E0 
35430 \ ------------------------------\
35431 \ set TimerB to make 50kHz PWM  \
35432 \ ------------------------------\
35433 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
35434 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
35435 \ ------------------------------\
35436 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
35437 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
35438 \ ------------------------------\
35439     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
35440     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
35441 \ ------------------------------\
35442 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
35443 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
35444 \ ------------------------------\
35445 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
35446 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
35447 \ ------------------------------\
35448     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
35449 \ ------------------------------\
35450 \ set TimerB to generate PWM for LCD_Vo
35451 \ ------------------------------\
35452     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
35453 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
35454     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
35455 \ ------------------------------\
35456     BIS.B #LCDVo,&LCDVo_DIR     \
35457     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
35458 \ ------------------------------\
35459     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
35460     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
35461 \ ------------------------------\
35462     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
35463     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
35464 \ ------------------------------\
35465 \ WDT interval init part        \
35466 \ ------------------------------\
35467     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
35468 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
35469 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
35470     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
35471 \ ------------------------------\
35472 \ init RC5_Int                  \
35473 \ ------------------------------\
35474     BIS.B #RC5,&IR_IE           \ enable RC5_Int
35475     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
35476 \ ------------------------------\
35477 \ init interrupt vectors
35478 \ ------------------------------\
35479     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
35480     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
35481 \ ------------------------------\
35482 \ define LPM mode for ACCEPT    \
35483 \ ------------------------------\
35484 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
35485 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
35486 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
35487
35488 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
35489
35490 \ ------------------------------\
35491 \ Init LCD 2x20                 \
35492 \ ------------------------------\
35493     $03E8 20_US                \ 1-  wait 20 ms
35494     $03 TOP_LCD                \ 2- send DB5=DB4=1
35495     $CD 20_US                  \ 3- wait 4,1 ms
35496     $03 TOP_LCD                \ 4- send again DB5=DB4=1
35497     $5 20_US                   \ 5- wait 0,1 ms
35498     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
35499     $2 20_US                   \    wait 40 us = LCD cycle
35500     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
35501     $2 20_US                   \    wait 40 us = LCD cycle
35502     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
35503     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
35504     LCD_Clear                   \ 10- "LCD_Clear"
35505     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
35506     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
35507     LCD_Clear                   \ 10- "LCD_Clear"
35508     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
35509     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
35510     CR ." I love you"   
35511     ['] (CR) IS CR              \ ' (CR) is CR
35512     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
35513     CR
35514     ."    RC5toLCD is running. Type STOP to quit"
35515 \    NOECHO                      \ uncomment to run this app without terminal connexion
35516     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
35517     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
35518 ;
35519     \
35520
35521 : STOP                  \ stops multitasking, must to be used before downloading app
35522     ['] (WARM) IS WARM  \ remove START app from FORTH init process
35523     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
35524 ;
35525     \
35526
35527
35528 RST_STATE   ;
35529
35530
35531 CODE MAX    \    n1 n2 -- n3       signed maximum
35532             CMP     @PSP,TOS    \ n2-n1
35533             S<      ?GOTO FW1   \ n2<n1
35534 BW1         ADD     #2,PSP
35535             MOV     @IP+,PC
35536 ENDCODE
35537     \
35538
35539 CODE MIN    \    n1 n2 -- n3       signed minimum
35540             CMP     @PSP,TOS     \ n2-n1
35541             S<      ?GOTO BW1    \ n2<n1
35542 FW1         MOV     @PSP+,TOS
35543             MOV     @IP+,PC
35544 ENDCODE
35545     \
35546
35547 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
35548   >R  <# 0 # #S #>  
35549   R> OVER - 0 MAX SPACES TYPE
35550 ;
35551     \
35552
35553 CODE 20_US                      \ n --      n * 20 us
35554 BEGIN                           \ 3 cycles loop + 6~  
35555 \    MOV     #5,W                \ 3 MCLK = 1 MHz
35556 \    MOV     #23,W               \ 3 MCLK = 4 MHz
35557     MOV     #51,W               \ 3 MCLK = 8 MHz
35558 \    MOV     #104,W              \ 3 MCLK = 16 MHz
35559 \    MOV     #158,W              \ 3 MCLK = 24 MHz
35560     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
35561         SUB #1,W                \ 1
35562     0= UNTIL                    \ 2
35563     SUB     #1,TOS              \ 1
35564 0= UNTIL                        \ 2
35565     MOV     @PSP+,TOS           \ 2
35566     MOV     @IP+,PC             \ 4
35567 ENDCODE
35568     \
35569
35570 CODE TOP_LCD                    \ LCD Sample
35571 \                               \ if write : %xxxxWWWW --
35572 \                               \ if read  : -- %0000RRRR
35573     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
35574     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
35575 0= IF                           \ write LCD bits pattern
35576     AND.B #LCD_DB,TOS           \ 
35577     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
35578     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
35579     MOV @PSP+,TOS               \
35580     MOV @IP+,PC
35581 THEN                            \ read LCD bits pattern
35582     SUB #2,PSP
35583     MOV TOS,0(PSP)
35584     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
35585     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
35586     AND.B #LCD_DB,TOS           \
35587     MOV @IP+,PC
35588 ENDCODE
35589     \
35590
35591 CODE LCD_W                      \ byte --       write byte to LCD 
35592     SUB #2,PSP                  \
35593     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
35594     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
35595     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
35596     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
35597 COLON                           \ high level word starts here 
35598     TOP_LCD 2 20_US             \ write high nibble first
35599     TOP_LCD 2 20_US 
35600 ;
35601     \
35602
35603 CODE LCD_WrC                    \ char --         Write Char
35604     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
35605     JMP LCD_W 
35606 ENDCODE
35607     \
35608
35609 CODE LCD_WrF                    \ func --         Write Fonction
35610     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
35611     JMP LCD_W 
35612 ENDCODE
35613     \
35614
35615 : LCD_Clear 
35616     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
35617 ;
35618     \
35619
35620 : LCD_Home 
35621     $02 LCD_WrF 100 20_us 
35622 ;
35623     \
35624
35625 \ : LCD_Entry_set       $04 OR LCD_WrF ;
35626
35627 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
35628
35629 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
35630
35631 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
35632
35633 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
35634
35635 \ : LCD_Goto            $80 OR LCD_WrF ;
35636
35637 \ CODE LCD_R                      \ -- byte       read byte from LCD
35638 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
35639 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
35640 \ COLON                           \ starts a FORTH word
35641 \     TOP_LCD 2 20_us             \ -- %0000HHHH
35642 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
35643 \ HI2LO                           \ switch from FORTH to assembler
35644 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
35645 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
35646 \     MOV @RSP+,IP                \ restore IP saved by COLON
35647 \     MOV @IP+,PC                 \
35648 \ ENDCODE
35649 \     \
35650
35651 \ CODE LCD_RdS                    \ -- status       Read Status
35652 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
35653 \     JMP LCD_R
35654 \ ENDCODE
35655 \     \
35656
35657 \ CODE LCD_RdC                    \ -- char         Read Char
35658 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
35659 \     JMP LCD_R
35660 \ ENDCODE
35661 \     \
35662
35663 \ -------------+------+------+------+------++---+---+---+---+---------+
35664 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
35665 \ -------------+------+------+------+------++---+---+---+---+---------+
35666 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
35667 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
35668 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
35669 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
35670 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
35671 \ -------------+------+------+------+------++---+---+---+---+---------+
35672
35673
35674 \ ******************************\
35675 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
35676 \ ******************************\
35677 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
35678 \ ------------------------------\
35679 \ define LPM mode for ACCEPT    \
35680 \ ------------------------------\
35681 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
35682 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
35683 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
35684 BIT.B #SW2,&SW2_IN              \ test switch S2
35685 0= IF                           \ case of switch S2 pressed
35686     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
35687     U< IF
35688         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
35689     THEN
35690 ELSE
35691     BIT.B #SW1,&SW1_IN          \ test switch S1 input
35692     0= IF                       \ case of Switch S1 pressed
35693         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
35694         U>= IF                  \
35695             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
35696         THEN                    \
35697     THEN                        \
35698 THEN                            \
35699 RETI                            \ CPU is ON, GIE is OFF
35700 ENDASM                          \
35701     \
35702
35703
35704 \ ------------------------------\
35705 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
35706 \ ******************************\
35707 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
35708 \ ******************************\
35709 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
35710 \                               \       SMclock = 8|16|24 MHz
35711 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
35712 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
35713 \                               \       SR(9)=new Toggle bit memory (ADD on)
35714 \ ------------------------------\
35715 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
35716 \ ------------------------------\
35717 \ define LPM mode for ACCEPT    \
35718 \ ------------------------------\
35719 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
35720 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
35721 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
35722 \ ------------------------------\
35723 \ RC5_FirstStartBitHalfCycle:   \
35724 \ ------------------------------\
35725 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
35726 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
35727 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
35728 MOV     #1778,X                 \ RC5_Period in us
35729 MOV     #14,W                   \ count of loop
35730 BEGIN                           \
35731 \ ------------------------------\
35732 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
35733 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
35734     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
35735 \ RC5_Compute_3/4_Period:       \                   |
35736     RRUM    #1,X                \ X=1/2 cycle       |
35737     MOV     X,Y                 \ Y=1/2             ^
35738     RRUM    #1,Y                \ Y=1/4
35739     ADD     X,Y                 \ Y=3/4
35740 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
35741     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
35742     0= UNTIL                    \
35743 \ ------------------------------\
35744 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
35745 \ ------------------------------\
35746     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
35747     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
35748     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
35749     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
35750     SUB     #1,W                \ decrement count loop
35751 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
35752 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
35753 0<> WHILE                       \ ----> out of loop ----+
35754 \ RC5_compute_7/4_Time_out:     \                       |
35755     ADD     X,Y                 \                       |   out of bound = 7/4 period 
35756 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
35757     BEGIN                       \                       |
35758         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
35759         0>= IF                  \                       |   if cycle time out of bound
35760             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
35761             RETI                \                       |   then quit to do nothing
35762         THEN                    \                       |
35763 \ ------------------------------\                       |
35764         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
35765     0<> UNTIL                   \                   |   |
35766     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
35767 REPEAT                          \ ----> loop back --+   |
35768 \ ------------------------------\                       |
35769 \ RC5_SampleEndOf:              \ <---------------------+
35770 \ ------------------------------\
35771 BIC     #$30,&TA0CTL           \ stop timer_A0
35772 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
35773 \ ******************************\
35774 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
35775 \ ******************************\
35776 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
35777 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
35778 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
35779 BIT     #BIT13,X                \ X(13) = New_RC5_command
35780 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
35781 THEN                            \
35782 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
35783 \ ******************************\
35784 \ RC5_ComputeNewRC5word         \
35785 \ ******************************\
35786 SUB     #4,PSP                  \
35787 MOV     &BASE,2(PSP)            \ save variable BASE before use
35788 MOV     TOS,0(PSP)              \ save TOS before use
35789 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
35790 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
35791 \ ******************************\
35792 \ RC5_ComputeC6bit              \
35793 \ ******************************\
35794 BIT     #$4000,IP              \ test /C6 bit in IP
35795 0= IF   BIS #$40,TOS           \ set C6 bit in S
35796 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
35797 \ ******************************\
35798 \ RC5_CommandByteIsDone         \ RC5_code --
35799 \ ******************************\
35800
35801 \ ------------------------------\
35802 \ Display IR_RC5 code           \
35803 \ ------------------------------\
35804 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
35805 \ ------------------------------\
35806 LO2HI                           \ switch from assembler to FORTH
35807     ['] LCD_CLEAR IS CR         \ redirects CR
35808     ['] LCD_WrC  IS EMIT        \ redirects EMIT
35809     $10 BASE !                 \ change BASE to hexadecimal
35810     CR ." $" 2 U.R             \ print IR_RC5 code
35811     ['] (CR) IS CR              \ restore CR
35812     ['] (EMIT) IS EMIT          \ restore EMIT
35813 HI2LO                           \ switch from FORTH to assembler
35814 \ ------------------------------\
35815 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
35816 \ ------------------------------\
35817 MOV @PSP+,&BASE                 \ restore variable BASE
35818 RETI                            \ CPU is ON, GIE is OFF
35819 ENDASM                          \
35820     \ 
35821
35822 CODE START                      \
35823 \ ------------------------------\
35824 \ TB0CTL = %0000 0010 1001 0100\$3C0
35825 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
35826 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
35827 \                      --       \ID input divider \ 10 = /4
35828 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
35829 \                            -  \TBCLR TimerB Clear
35830 \                             - \TBIE
35831 \                              -\TBIFG
35832 \ --------------------------------\\
35833 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
35834 \              --                 \CM Capture Mode
35835 \                --               \CCIS
35836 \                   -             \SCS
35837 \                    --           \CLLD
35838 \                      -          \CAP
35839 \                        ---      \OUTMOD \ 011 = set/reset
35840 \                           -     \CCIE
35841 \                             -   \CCI
35842 \                              -  \OUT
35843 \                               - \COV
35844 \                                -\CCIFG
35845 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
35846 \ TB0EX0                          \$3E0 
35847 \ ------------------------------\
35848 \ set TimerB to make 50kHz PWM  \
35849 \ ------------------------------\
35850 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
35851 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
35852 \ ------------------------------\
35853 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
35854 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
35855 \ ------------------------------\
35856     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
35857     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
35858 \ ------------------------------\
35859 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
35860 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
35861 \ ------------------------------\
35862 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
35863 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
35864 \ ------------------------------\
35865     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
35866 \ ------------------------------\
35867 \ set TimerB to generate PWM for LCD_Vo
35868 \ ------------------------------\
35869     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
35870 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
35871     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
35872 \ ------------------------------\
35873     BIS.B #LCDVo,&LCDVo_DIR     \
35874     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
35875 \ ------------------------------\
35876     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
35877     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
35878 \ ------------------------------\
35879     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
35880     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
35881 \ ------------------------------\
35882 \ WDT interval init part        \
35883 \ ------------------------------\
35884     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
35885 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
35886 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
35887     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
35888 \ ------------------------------\
35889 \ init RC5_Int                  \
35890 \ ------------------------------\
35891     BIS.B #RC5,&IR_IE           \ enable RC5_Int
35892     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
35893 \ ------------------------------\
35894 \ init interrupt vectors
35895 \ ------------------------------\
35896     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
35897     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
35898 \ ------------------------------\
35899 \ define LPM mode for ACCEPT    \
35900 \ ------------------------------\
35901 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
35902 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
35903 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
35904
35905 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
35906
35907 \ ------------------------------\
35908 \ Init LCD 2x20                 \
35909 \ ------------------------------\
35910     $03E8 20_US                \ 1-  wait 20 ms
35911     $03 TOP_LCD                \ 2- send DB5=DB4=1
35912     $CD 20_US                  \ 3- wait 4,1 ms
35913     $03 TOP_LCD                \ 4- send again DB5=DB4=1
35914     $5 20_US                   \ 5- wait 0,1 ms
35915     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
35916     $2 20_US                   \    wait 40 us = LCD cycle
35917     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
35918     $2 20_US                   \    wait 40 us = LCD cycle
35919     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
35920     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
35921     LCD_Clear                   \ 10- "LCD_Clear"
35922     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
35923     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
35924     LCD_Clear                   \ 10- "LCD_Clear"
35925     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
35926     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
35927     CR ." I love you"   
35928     ['] (CR) IS CR              \ ' (CR) is CR
35929     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
35930     CR
35931     ."    RC5toLCD is running. Type STOP to quit"
35932 \    NOECHO                      \ uncomment to run this app without terminal connexion
35933     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
35934     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
35935 ;
35936     \
35937
35938 : STOP                  \ stops multitasking, must to be used before downloading app
35939     ['] (WARM) IS WARM  \ remove START app from FORTH init process
35940     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
35941 ;
35942     \
35943
35944
35945 RST_STATE   ;
35946
35947
35948 CODE MAX    \    n1 n2 -- n3       signed maximum
35949             CMP     @PSP,TOS    \ n2-n1
35950             S<      ?GOTO FW1   \ n2<n1
35951 BW1         ADD     #2,PSP
35952             MOV     @IP+,PC
35953 ENDCODE
35954     \
35955
35956 CODE MIN    \    n1 n2 -- n3       signed minimum
35957             CMP     @PSP,TOS     \ n2-n1
35958             S<      ?GOTO BW1    \ n2<n1
35959 FW1         MOV     @PSP+,TOS
35960             MOV     @IP+,PC
35961 ENDCODE
35962     \
35963
35964 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
35965   >R  <# 0 # #S #>  
35966   R> OVER - 0 MAX SPACES TYPE
35967 ;
35968     \
35969
35970 CODE 20_US                      \ n --      n * 20 us
35971 BEGIN                           \ 3 cycles loop + 6~  
35972 \    MOV     #5,W                \ 3 MCLK = 1 MHz
35973 \    MOV     #23,W               \ 3 MCLK = 4 MHz
35974     MOV     #51,W               \ 3 MCLK = 8 MHz
35975 \    MOV     #104,W              \ 3 MCLK = 16 MHz
35976 \    MOV     #158,W              \ 3 MCLK = 24 MHz
35977     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
35978         SUB #1,W                \ 1
35979     0= UNTIL                    \ 2
35980     SUB     #1,TOS              \ 1
35981 0= UNTIL                        \ 2
35982     MOV     @PSP+,TOS           \ 2
35983     MOV     @IP+,PC             \ 4
35984 ENDCODE
35985     \
35986
35987 CODE TOP_LCD                    \ LCD Sample
35988 \                               \ if write : %xxxxWWWW --
35989 \                               \ if read  : -- %0000RRRR
35990     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
35991     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
35992 0= IF                           \ write LCD bits pattern
35993     AND.B #LCD_DB,TOS           \ 
35994     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
35995     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
35996     MOV @PSP+,TOS               \
35997     MOV @IP+,PC
35998 THEN                            \ read LCD bits pattern
35999     SUB #2,PSP
36000     MOV TOS,0(PSP)
36001     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
36002     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
36003     AND.B #LCD_DB,TOS           \
36004     MOV @IP+,PC
36005 ENDCODE
36006     \
36007
36008 CODE LCD_W                      \ byte --       write byte to LCD 
36009     SUB #2,PSP                  \
36010     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
36011     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
36012     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
36013     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
36014 COLON                           \ high level word starts here 
36015     TOP_LCD 2 20_US             \ write high nibble first
36016     TOP_LCD 2 20_US 
36017 ;
36018     \
36019
36020 CODE LCD_WrC                    \ char --         Write Char
36021     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
36022     JMP LCD_W 
36023 ENDCODE
36024     \
36025
36026 CODE LCD_WrF                    \ func --         Write Fonction
36027     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
36028     JMP LCD_W 
36029 ENDCODE
36030     \
36031
36032 : LCD_Clear 
36033     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
36034 ;
36035     \
36036
36037 : LCD_Home 
36038     $02 LCD_WrF 100 20_us 
36039 ;
36040     \
36041
36042 \ : LCD_Entry_set       $04 OR LCD_WrF ;
36043
36044 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
36045
36046 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
36047
36048 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
36049
36050 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
36051
36052 \ : LCD_Goto            $80 OR LCD_WrF ;
36053
36054 \ CODE LCD_R                      \ -- byte       read byte from LCD
36055 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
36056 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
36057 \ COLON                           \ starts a FORTH word
36058 \     TOP_LCD 2 20_us             \ -- %0000HHHH
36059 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
36060 \ HI2LO                           \ switch from FORTH to assembler
36061 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
36062 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
36063 \     MOV @RSP+,IP                \ restore IP saved by COLON
36064 \     MOV @IP+,PC                 \
36065 \ ENDCODE
36066 \     \
36067
36068 \ CODE LCD_RdS                    \ -- status       Read Status
36069 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
36070 \     JMP LCD_R
36071 \ ENDCODE
36072 \     \
36073
36074 \ CODE LCD_RdC                    \ -- char         Read Char
36075 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
36076 \     JMP LCD_R
36077 \ ENDCODE
36078 \     \
36079
36080 \ -------------+------+------+------+------++---+---+---+---+---------+
36081 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
36082 \ -------------+------+------+------+------++---+---+---+---+---------+
36083 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
36084 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
36085 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
36086 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
36087 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
36088 \ -------------+------+------+------+------++---+---+---+---+---------+
36089
36090
36091 \ ******************************\
36092 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
36093 \ ******************************\
36094 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
36095 \ ------------------------------\
36096 \ define LPM mode for ACCEPT    \
36097 \ ------------------------------\
36098 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
36099 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
36100 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
36101 BIT.B #SW2,&SW2_IN              \ test switch S2
36102 0= IF                           \ case of switch S2 pressed
36103     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
36104     U< IF
36105         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
36106     THEN
36107 ELSE
36108     BIT.B #SW1,&SW1_IN          \ test switch S1 input
36109     0= IF                       \ case of Switch S1 pressed
36110         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
36111         U>= IF                  \
36112             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
36113         THEN                    \
36114     THEN                        \
36115 THEN                            \
36116 RETI                            \ CPU is ON, GIE is OFF
36117 ENDASM                          \
36118     \
36119
36120
36121 \ ------------------------------\
36122 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
36123 \ ******************************\
36124 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
36125 \ ******************************\
36126 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
36127 \                               \       SMclock = 8|16|24 MHz
36128 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
36129 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
36130 \                               \       SR(9)=new Toggle bit memory (ADD on)
36131 \ ------------------------------\
36132 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
36133 \ ------------------------------\
36134 \ define LPM mode for ACCEPT    \
36135 \ ------------------------------\
36136 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
36137 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
36138 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
36139 \ ------------------------------\
36140 \ RC5_FirstStartBitHalfCycle:   \
36141 \ ------------------------------\
36142 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
36143 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
36144 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
36145 MOV     #1778,X                 \ RC5_Period in us
36146 MOV     #14,W                   \ count of loop
36147 BEGIN                           \
36148 \ ------------------------------\
36149 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
36150 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
36151     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
36152 \ RC5_Compute_3/4_Period:       \                   |
36153     RRUM    #1,X                \ X=1/2 cycle       |
36154     MOV     X,Y                 \ Y=1/2             ^
36155     RRUM    #1,Y                \ Y=1/4
36156     ADD     X,Y                 \ Y=3/4
36157 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
36158     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
36159     0= UNTIL                    \
36160 \ ------------------------------\
36161 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
36162 \ ------------------------------\
36163     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
36164     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
36165     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
36166     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
36167     SUB     #1,W                \ decrement count loop
36168 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
36169 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
36170 0<> WHILE                       \ ----> out of loop ----+
36171 \ RC5_compute_7/4_Time_out:     \                       |
36172     ADD     X,Y                 \                       |   out of bound = 7/4 period 
36173 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
36174     BEGIN                       \                       |
36175         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
36176         0>= IF                  \                       |   if cycle time out of bound
36177             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
36178             RETI                \                       |   then quit to do nothing
36179         THEN                    \                       |
36180 \ ------------------------------\                       |
36181         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
36182     0<> UNTIL                   \                   |   |
36183     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
36184 REPEAT                          \ ----> loop back --+   |
36185 \ ------------------------------\                       |
36186 \ RC5_SampleEndOf:              \ <---------------------+
36187 \ ------------------------------\
36188 BIC     #$30,&TA0CTL           \ stop timer_A0
36189 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
36190 \ ******************************\
36191 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
36192 \ ******************************\
36193 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
36194 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
36195 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
36196 BIT     #BIT13,X                \ X(13) = New_RC5_command
36197 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
36198 THEN                            \
36199 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
36200 \ ******************************\
36201 \ RC5_ComputeNewRC5word         \
36202 \ ******************************\
36203 SUB     #4,PSP                  \
36204 MOV     &BASE,2(PSP)            \ save variable BASE before use
36205 MOV     TOS,0(PSP)              \ save TOS before use
36206 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
36207 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
36208 \ ******************************\
36209 \ RC5_ComputeC6bit              \
36210 \ ******************************\
36211 BIT     #$4000,IP              \ test /C6 bit in IP
36212 0= IF   BIS #$40,TOS           \ set C6 bit in S
36213 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
36214 \ ******************************\
36215 \ RC5_CommandByteIsDone         \ RC5_code --
36216 \ ******************************\
36217
36218 \ ------------------------------\
36219 \ Display IR_RC5 code           \
36220 \ ------------------------------\
36221 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
36222 \ ------------------------------\
36223 LO2HI                           \ switch from assembler to FORTH
36224     ['] LCD_CLEAR IS CR         \ redirects CR
36225     ['] LCD_WrC  IS EMIT        \ redirects EMIT
36226     $10 BASE !                 \ change BASE to hexadecimal
36227     CR ." $" 2 U.R             \ print IR_RC5 code
36228     ['] (CR) IS CR              \ restore CR
36229     ['] (EMIT) IS EMIT          \ restore EMIT
36230 HI2LO                           \ switch from FORTH to assembler
36231 \ ------------------------------\
36232 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
36233 \ ------------------------------\
36234 MOV @PSP+,&BASE                 \ restore variable BASE
36235 RETI                            \ CPU is ON, GIE is OFF
36236 ENDASM                          \
36237     \ 
36238
36239 CODE START                      \
36240 \ ------------------------------\
36241 \ TB0CTL = %0000 0010 1001 0100\$3C0
36242 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
36243 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
36244 \                      --       \ID input divider \ 10 = /4
36245 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
36246 \                            -  \TBCLR TimerB Clear
36247 \                             - \TBIE
36248 \                              -\TBIFG
36249 \ --------------------------------\\
36250 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
36251 \              --                 \CM Capture Mode
36252 \                --               \CCIS
36253 \                   -             \SCS
36254 \                    --           \CLLD
36255 \                      -          \CAP
36256 \                        ---      \OUTMOD \ 011 = set/reset
36257 \                           -     \CCIE
36258 \                             -   \CCI
36259 \                              -  \OUT
36260 \                               - \COV
36261 \                                -\CCIFG
36262 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
36263 \ TB0EX0                          \$3E0 
36264 \ ------------------------------\
36265 \ set TimerB to make 50kHz PWM  \
36266 \ ------------------------------\
36267 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
36268 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
36269 \ ------------------------------\
36270 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
36271 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
36272 \ ------------------------------\
36273     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
36274     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
36275 \ ------------------------------\
36276 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
36277 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
36278 \ ------------------------------\
36279 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
36280 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
36281 \ ------------------------------\
36282     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
36283 \ ------------------------------\
36284 \ set TimerB to generate PWM for LCD_Vo
36285 \ ------------------------------\
36286     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
36287 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
36288     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
36289 \ ------------------------------\
36290     BIS.B #LCDVo,&LCDVo_DIR     \
36291     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
36292 \ ------------------------------\
36293     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
36294     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
36295 \ ------------------------------\
36296     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
36297     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
36298 \ ------------------------------\
36299 \ WDT interval init part        \
36300 \ ------------------------------\
36301     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
36302 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
36303 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
36304     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
36305 \ ------------------------------\
36306 \ init RC5_Int                  \
36307 \ ------------------------------\
36308     BIS.B #RC5,&IR_IE           \ enable RC5_Int
36309     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
36310 \ ------------------------------\
36311 \ init interrupt vectors
36312 \ ------------------------------\
36313     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
36314     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
36315 \ ------------------------------\
36316 \ define LPM mode for ACCEPT    \
36317 \ ------------------------------\
36318 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
36319 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
36320 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
36321
36322 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
36323
36324 \ ------------------------------\
36325 \ Init LCD 2x20                 \
36326 \ ------------------------------\
36327     $03E8 20_US                \ 1-  wait 20 ms
36328     $03 TOP_LCD                \ 2- send DB5=DB4=1
36329     $CD 20_US                  \ 3- wait 4,1 ms
36330     $03 TOP_LCD                \ 4- send again DB5=DB4=1
36331     $5 20_US                   \ 5- wait 0,1 ms
36332     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
36333     $2 20_US                   \    wait 40 us = LCD cycle
36334     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
36335     $2 20_US                   \    wait 40 us = LCD cycle
36336     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
36337     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
36338     LCD_Clear                   \ 10- "LCD_Clear"
36339     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
36340     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
36341     LCD_Clear                   \ 10- "LCD_Clear"
36342     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
36343     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
36344     CR ." I love you"   
36345     ['] (CR) IS CR              \ ' (CR) is CR
36346     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
36347     CR
36348     ."    RC5toLCD is running. Type STOP to quit"
36349 \    NOECHO                      \ uncomment to run this app without terminal connexion
36350     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
36351     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
36352 ;
36353     \
36354
36355 : STOP                  \ stops multitasking, must to be used before downloading app
36356     ['] (WARM) IS WARM  \ remove START app from FORTH init process
36357     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
36358 ;
36359     \
36360
36361
36362 RST_STATE   ;
36363
36364
36365 CODE MAX    \    n1 n2 -- n3       signed maximum
36366             CMP     @PSP,TOS    \ n2-n1
36367             S<      ?GOTO FW1   \ n2<n1
36368 BW1         ADD     #2,PSP
36369             MOV     @IP+,PC
36370 ENDCODE
36371     \
36372
36373 CODE MIN    \    n1 n2 -- n3       signed minimum
36374             CMP     @PSP,TOS     \ n2-n1
36375             S<      ?GOTO BW1    \ n2<n1
36376 FW1         MOV     @PSP+,TOS
36377             MOV     @IP+,PC
36378 ENDCODE
36379     \
36380
36381 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
36382   >R  <# 0 # #S #>  
36383   R> OVER - 0 MAX SPACES TYPE
36384 ;
36385     \
36386
36387 CODE 20_US                      \ n --      n * 20 us
36388 BEGIN                           \ 3 cycles loop + 6~  
36389 \    MOV     #5,W                \ 3 MCLK = 1 MHz
36390 \    MOV     #23,W               \ 3 MCLK = 4 MHz
36391     MOV     #51,W               \ 3 MCLK = 8 MHz
36392 \    MOV     #104,W              \ 3 MCLK = 16 MHz
36393 \    MOV     #158,W              \ 3 MCLK = 24 MHz
36394     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
36395         SUB #1,W                \ 1
36396     0= UNTIL                    \ 2
36397     SUB     #1,TOS              \ 1
36398 0= UNTIL                        \ 2
36399     MOV     @PSP+,TOS           \ 2
36400     MOV     @IP+,PC             \ 4
36401 ENDCODE
36402     \
36403
36404 CODE TOP_LCD                    \ LCD Sample
36405 \                               \ if write : %xxxxWWWW --
36406 \                               \ if read  : -- %0000RRRR
36407     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
36408     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
36409 0= IF                           \ write LCD bits pattern
36410     AND.B #LCD_DB,TOS           \ 
36411     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
36412     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
36413     MOV @PSP+,TOS               \
36414     MOV @IP+,PC
36415 THEN                            \ read LCD bits pattern
36416     SUB #2,PSP
36417     MOV TOS,0(PSP)
36418     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
36419     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
36420     AND.B #LCD_DB,TOS           \
36421     MOV @IP+,PC
36422 ENDCODE
36423     \
36424
36425 CODE LCD_W                      \ byte --       write byte to LCD 
36426     SUB #2,PSP                  \
36427     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
36428     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
36429     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
36430     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
36431 COLON                           \ high level word starts here 
36432     TOP_LCD 2 20_US             \ write high nibble first
36433     TOP_LCD 2 20_US 
36434 ;
36435     \
36436
36437 CODE LCD_WrC                    \ char --         Write Char
36438     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
36439     JMP LCD_W 
36440 ENDCODE
36441     \
36442
36443 CODE LCD_WrF                    \ func --         Write Fonction
36444     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
36445     JMP LCD_W 
36446 ENDCODE
36447     \
36448
36449 : LCD_Clear 
36450     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
36451 ;
36452     \
36453
36454 : LCD_Home 
36455     $02 LCD_WrF 100 20_us 
36456 ;
36457     \
36458
36459 \ : LCD_Entry_set       $04 OR LCD_WrF ;
36460
36461 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
36462
36463 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
36464
36465 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
36466
36467 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
36468
36469 \ : LCD_Goto            $80 OR LCD_WrF ;
36470
36471 \ CODE LCD_R                      \ -- byte       read byte from LCD
36472 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
36473 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
36474 \ COLON                           \ starts a FORTH word
36475 \     TOP_LCD 2 20_us             \ -- %0000HHHH
36476 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
36477 \ HI2LO                           \ switch from FORTH to assembler
36478 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
36479 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
36480 \     MOV @RSP+,IP                \ restore IP saved by COLON
36481 \     MOV @IP+,PC                 \
36482 \ ENDCODE
36483 \     \
36484
36485 \ CODE LCD_RdS                    \ -- status       Read Status
36486 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
36487 \     JMP LCD_R
36488 \ ENDCODE
36489 \     \
36490
36491 \ CODE LCD_RdC                    \ -- char         Read Char
36492 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
36493 \     JMP LCD_R
36494 \ ENDCODE
36495 \     \
36496
36497 \ -------------+------+------+------+------++---+---+---+---+---------+
36498 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
36499 \ -------------+------+------+------+------++---+---+---+---+---------+
36500 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
36501 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
36502 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
36503 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
36504 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
36505 \ -------------+------+------+------+------++---+---+---+---+---------+
36506
36507
36508 \ ******************************\
36509 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
36510 \ ******************************\
36511 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
36512 \ ------------------------------\
36513 \ define LPM mode for ACCEPT    \
36514 \ ------------------------------\
36515 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
36516 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
36517 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
36518 BIT.B #SW2,&SW2_IN              \ test switch S2
36519 0= IF                           \ case of switch S2 pressed
36520     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
36521     U< IF
36522         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
36523     THEN
36524 ELSE
36525     BIT.B #SW1,&SW1_IN          \ test switch S1 input
36526     0= IF                       \ case of Switch S1 pressed
36527         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
36528         U>= IF                  \
36529             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
36530         THEN                    \
36531     THEN                        \
36532 THEN                            \
36533 RETI                            \ CPU is ON, GIE is OFF
36534 ENDASM                          \
36535     \
36536
36537
36538 \ ------------------------------\
36539 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
36540 \ ******************************\
36541 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
36542 \ ******************************\
36543 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
36544 \                               \       SMclock = 8|16|24 MHz
36545 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
36546 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
36547 \                               \       SR(9)=new Toggle bit memory (ADD on)
36548 \ ------------------------------\
36549 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
36550 \ ------------------------------\
36551 \ define LPM mode for ACCEPT    \
36552 \ ------------------------------\
36553 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
36554 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
36555 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
36556 \ ------------------------------\
36557 \ RC5_FirstStartBitHalfCycle:   \
36558 \ ------------------------------\
36559 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
36560 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
36561 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
36562 MOV     #1778,X                 \ RC5_Period in us
36563 MOV     #14,W                   \ count of loop
36564 BEGIN                           \
36565 \ ------------------------------\
36566 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
36567 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
36568     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
36569 \ RC5_Compute_3/4_Period:       \                   |
36570     RRUM    #1,X                \ X=1/2 cycle       |
36571     MOV     X,Y                 \ Y=1/2             ^
36572     RRUM    #1,Y                \ Y=1/4
36573     ADD     X,Y                 \ Y=3/4
36574 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
36575     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
36576     0= UNTIL                    \
36577 \ ------------------------------\
36578 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
36579 \ ------------------------------\
36580     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
36581     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
36582     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
36583     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
36584     SUB     #1,W                \ decrement count loop
36585 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
36586 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
36587 0<> WHILE                       \ ----> out of loop ----+
36588 \ RC5_compute_7/4_Time_out:     \                       |
36589     ADD     X,Y                 \                       |   out of bound = 7/4 period 
36590 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
36591     BEGIN                       \                       |
36592         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
36593         0>= IF                  \                       |   if cycle time out of bound
36594             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
36595             RETI                \                       |   then quit to do nothing
36596         THEN                    \                       |
36597 \ ------------------------------\                       |
36598         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
36599     0<> UNTIL                   \                   |   |
36600     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
36601 REPEAT                          \ ----> loop back --+   |
36602 \ ------------------------------\                       |
36603 \ RC5_SampleEndOf:              \ <---------------------+
36604 \ ------------------------------\
36605 BIC     #$30,&TA0CTL           \ stop timer_A0
36606 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
36607 \ ******************************\
36608 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
36609 \ ******************************\
36610 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
36611 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
36612 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
36613 BIT     #BIT13,X                \ X(13) = New_RC5_command
36614 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
36615 THEN                            \
36616 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
36617 \ ******************************\
36618 \ RC5_ComputeNewRC5word         \
36619 \ ******************************\
36620 SUB     #4,PSP                  \
36621 MOV     &BASE,2(PSP)            \ save variable BASE before use
36622 MOV     TOS,0(PSP)              \ save TOS before use
36623 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
36624 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
36625 \ ******************************\
36626 \ RC5_ComputeC6bit              \
36627 \ ******************************\
36628 BIT     #$4000,IP              \ test /C6 bit in IP
36629 0= IF   BIS #$40,TOS           \ set C6 bit in S
36630 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
36631 \ ******************************\
36632 \ RC5_CommandByteIsDone         \ RC5_code --
36633 \ ******************************\
36634
36635 \ ------------------------------\
36636 \ Display IR_RC5 code           \
36637 \ ------------------------------\
36638 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
36639 \ ------------------------------\
36640 LO2HI                           \ switch from assembler to FORTH
36641     ['] LCD_CLEAR IS CR         \ redirects CR
36642     ['] LCD_WrC  IS EMIT        \ redirects EMIT
36643     $10 BASE !                 \ change BASE to hexadecimal
36644     CR ." $" 2 U.R             \ print IR_RC5 code
36645     ['] (CR) IS CR              \ restore CR
36646     ['] (EMIT) IS EMIT          \ restore EMIT
36647 HI2LO                           \ switch from FORTH to assembler
36648 \ ------------------------------\
36649 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
36650 \ ------------------------------\
36651 MOV @PSP+,&BASE                 \ restore variable BASE
36652 RETI                            \ CPU is ON, GIE is OFF
36653 ENDASM                          \
36654     \ 
36655
36656 CODE START                      \
36657 \ ------------------------------\
36658 \ TB0CTL = %0000 0010 1001 0100\$3C0
36659 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
36660 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
36661 \                      --       \ID input divider \ 10 = /4
36662 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
36663 \                            -  \TBCLR TimerB Clear
36664 \                             - \TBIE
36665 \                              -\TBIFG
36666 \ --------------------------------\\
36667 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
36668 \              --                 \CM Capture Mode
36669 \                --               \CCIS
36670 \                   -             \SCS
36671 \                    --           \CLLD
36672 \                      -          \CAP
36673 \                        ---      \OUTMOD \ 011 = set/reset
36674 \                           -     \CCIE
36675 \                             -   \CCI
36676 \                              -  \OUT
36677 \                               - \COV
36678 \                                -\CCIFG
36679 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
36680 \ TB0EX0                          \$3E0 
36681 \ ------------------------------\
36682 \ set TimerB to make 50kHz PWM  \
36683 \ ------------------------------\
36684 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
36685 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
36686 \ ------------------------------\
36687 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
36688 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
36689 \ ------------------------------\
36690     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
36691     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
36692 \ ------------------------------\
36693 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
36694 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
36695 \ ------------------------------\
36696 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
36697 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
36698 \ ------------------------------\
36699     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
36700 \ ------------------------------\
36701 \ set TimerB to generate PWM for LCD_Vo
36702 \ ------------------------------\
36703     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
36704 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
36705     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
36706 \ ------------------------------\
36707     BIS.B #LCDVo,&LCDVo_DIR     \
36708     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
36709 \ ------------------------------\
36710     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
36711     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
36712 \ ------------------------------\
36713     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
36714     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
36715 \ ------------------------------\
36716 \ WDT interval init part        \
36717 \ ------------------------------\
36718     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
36719 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
36720 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
36721     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
36722 \ ------------------------------\
36723 \ init RC5_Int                  \
36724 \ ------------------------------\
36725     BIS.B #RC5,&IR_IE           \ enable RC5_Int
36726     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
36727 \ ------------------------------\
36728 \ init interrupt vectors
36729 \ ------------------------------\
36730     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
36731     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
36732 \ ------------------------------\
36733 \ define LPM mode for ACCEPT    \
36734 \ ------------------------------\
36735 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
36736 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
36737 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
36738
36739 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
36740
36741 \ ------------------------------\
36742 \ Init LCD 2x20                 \
36743 \ ------------------------------\
36744     $03E8 20_US                \ 1-  wait 20 ms
36745     $03 TOP_LCD                \ 2- send DB5=DB4=1
36746     $CD 20_US                  \ 3- wait 4,1 ms
36747     $03 TOP_LCD                \ 4- send again DB5=DB4=1
36748     $5 20_US                   \ 5- wait 0,1 ms
36749     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
36750     $2 20_US                   \    wait 40 us = LCD cycle
36751     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
36752     $2 20_US                   \    wait 40 us = LCD cycle
36753     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
36754     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
36755     LCD_Clear                   \ 10- "LCD_Clear"
36756     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
36757     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
36758     LCD_Clear                   \ 10- "LCD_Clear"
36759     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
36760     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
36761     CR ." I love you"   
36762     ['] (CR) IS CR              \ ' (CR) is CR
36763     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
36764     CR
36765     ."    RC5toLCD is running. Type STOP to quit"
36766 \    NOECHO                      \ uncomment to run this app without terminal connexion
36767     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
36768     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
36769 ;
36770     \
36771
36772 : STOP                  \ stops multitasking, must to be used before downloading app
36773     ['] (WARM) IS WARM  \ remove START app from FORTH init process
36774     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
36775 ;
36776     \
36777
36778
36779 RST_STATE   ;
36780
36781
36782 CODE MAX    \    n1 n2 -- n3       signed maximum
36783             CMP     @PSP,TOS    \ n2-n1
36784             S<      ?GOTO FW1   \ n2<n1
36785 BW1         ADD     #2,PSP
36786             MOV     @IP+,PC
36787 ENDCODE
36788     \
36789
36790 CODE MIN    \    n1 n2 -- n3       signed minimum
36791             CMP     @PSP,TOS     \ n2-n1
36792             S<      ?GOTO BW1    \ n2<n1
36793 FW1         MOV     @PSP+,TOS
36794             MOV     @IP+,PC
36795 ENDCODE
36796     \
36797
36798 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
36799   >R  <# 0 # #S #>  
36800   R> OVER - 0 MAX SPACES TYPE
36801 ;
36802     \
36803
36804 CODE 20_US                      \ n --      n * 20 us
36805 BEGIN                           \ 3 cycles loop + 6~  
36806 \    MOV     #5,W                \ 3 MCLK = 1 MHz
36807 \    MOV     #23,W               \ 3 MCLK = 4 MHz
36808     MOV     #51,W               \ 3 MCLK = 8 MHz
36809 \    MOV     #104,W              \ 3 MCLK = 16 MHz
36810 \    MOV     #158,W              \ 3 MCLK = 24 MHz
36811     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
36812         SUB #1,W                \ 1
36813     0= UNTIL                    \ 2
36814     SUB     #1,TOS              \ 1
36815 0= UNTIL                        \ 2
36816     MOV     @PSP+,TOS           \ 2
36817     MOV     @IP+,PC             \ 4
36818 ENDCODE
36819     \
36820
36821 CODE TOP_LCD                    \ LCD Sample
36822 \                               \ if write : %xxxxWWWW --
36823 \                               \ if read  : -- %0000RRRR
36824     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
36825     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
36826 0= IF                           \ write LCD bits pattern
36827     AND.B #LCD_DB,TOS           \ 
36828     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
36829     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
36830     MOV @PSP+,TOS               \
36831     MOV @IP+,PC
36832 THEN                            \ read LCD bits pattern
36833     SUB #2,PSP
36834     MOV TOS,0(PSP)
36835     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
36836     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
36837     AND.B #LCD_DB,TOS           \
36838     MOV @IP+,PC
36839 ENDCODE
36840     \
36841
36842 CODE LCD_W                      \ byte --       write byte to LCD 
36843     SUB #2,PSP                  \
36844     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
36845     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
36846     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
36847     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
36848 COLON                           \ high level word starts here 
36849     TOP_LCD 2 20_US             \ write high nibble first
36850     TOP_LCD 2 20_US 
36851 ;
36852     \
36853
36854 CODE LCD_WrC                    \ char --         Write Char
36855     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
36856     JMP LCD_W 
36857 ENDCODE
36858     \
36859
36860 CODE LCD_WrF                    \ func --         Write Fonction
36861     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
36862     JMP LCD_W 
36863 ENDCODE
36864     \
36865
36866 : LCD_Clear 
36867     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
36868 ;
36869     \
36870
36871 : LCD_Home 
36872     $02 LCD_WrF 100 20_us 
36873 ;
36874     \
36875
36876 \ : LCD_Entry_set       $04 OR LCD_WrF ;
36877
36878 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
36879
36880 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
36881
36882 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
36883
36884 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
36885
36886 \ : LCD_Goto            $80 OR LCD_WrF ;
36887
36888 \ CODE LCD_R                      \ -- byte       read byte from LCD
36889 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
36890 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
36891 \ COLON                           \ starts a FORTH word
36892 \     TOP_LCD 2 20_us             \ -- %0000HHHH
36893 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
36894 \ HI2LO                           \ switch from FORTH to assembler
36895 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
36896 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
36897 \     MOV @RSP+,IP                \ restore IP saved by COLON
36898 \     MOV @IP+,PC                 \
36899 \ ENDCODE
36900 \     \
36901
36902 \ CODE LCD_RdS                    \ -- status       Read Status
36903 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
36904 \     JMP LCD_R
36905 \ ENDCODE
36906 \     \
36907
36908 \ CODE LCD_RdC                    \ -- char         Read Char
36909 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
36910 \     JMP LCD_R
36911 \ ENDCODE
36912 \     \
36913
36914 \ -------------+------+------+------+------++---+---+---+---+---------+
36915 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
36916 \ -------------+------+------+------+------++---+---+---+---+---------+
36917 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
36918 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
36919 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
36920 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
36921 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
36922 \ -------------+------+------+------+------++---+---+---+---+---------+
36923
36924
36925 \ ******************************\
36926 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
36927 \ ******************************\
36928 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
36929 \ ------------------------------\
36930 \ define LPM mode for ACCEPT    \
36931 \ ------------------------------\
36932 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
36933 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
36934 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
36935 BIT.B #SW2,&SW2_IN              \ test switch S2
36936 0= IF                           \ case of switch S2 pressed
36937     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
36938     U< IF
36939         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
36940     THEN
36941 ELSE
36942     BIT.B #SW1,&SW1_IN          \ test switch S1 input
36943     0= IF                       \ case of Switch S1 pressed
36944         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
36945         U>= IF                  \
36946             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
36947         THEN                    \
36948     THEN                        \
36949 THEN                            \
36950 RETI                            \ CPU is ON, GIE is OFF
36951 ENDASM                          \
36952     \
36953
36954
36955 \ ------------------------------\
36956 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
36957 \ ******************************\
36958 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
36959 \ ******************************\
36960 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
36961 \                               \       SMclock = 8|16|24 MHz
36962 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
36963 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
36964 \                               \       SR(9)=new Toggle bit memory (ADD on)
36965 \ ------------------------------\
36966 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
36967 \ ------------------------------\
36968 \ define LPM mode for ACCEPT    \
36969 \ ------------------------------\
36970 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
36971 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
36972 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
36973 \ ------------------------------\
36974 \ RC5_FirstStartBitHalfCycle:   \
36975 \ ------------------------------\
36976 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
36977 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
36978 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
36979 MOV     #1778,X                 \ RC5_Period in us
36980 MOV     #14,W                   \ count of loop
36981 BEGIN                           \
36982 \ ------------------------------\
36983 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
36984 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
36985     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
36986 \ RC5_Compute_3/4_Period:       \                   |
36987     RRUM    #1,X                \ X=1/2 cycle       |
36988     MOV     X,Y                 \ Y=1/2             ^
36989     RRUM    #1,Y                \ Y=1/4
36990     ADD     X,Y                 \ Y=3/4
36991 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
36992     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
36993     0= UNTIL                    \
36994 \ ------------------------------\
36995 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
36996 \ ------------------------------\
36997     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
36998     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
36999     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
37000     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
37001     SUB     #1,W                \ decrement count loop
37002 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
37003 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
37004 0<> WHILE                       \ ----> out of loop ----+
37005 \ RC5_compute_7/4_Time_out:     \                       |
37006     ADD     X,Y                 \                       |   out of bound = 7/4 period 
37007 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
37008     BEGIN                       \                       |
37009         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
37010         0>= IF                  \                       |   if cycle time out of bound
37011             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
37012             RETI                \                       |   then quit to do nothing
37013         THEN                    \                       |
37014 \ ------------------------------\                       |
37015         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
37016     0<> UNTIL                   \                   |   |
37017     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
37018 REPEAT                          \ ----> loop back --+   |
37019 \ ------------------------------\                       |
37020 \ RC5_SampleEndOf:              \ <---------------------+
37021 \ ------------------------------\
37022 BIC     #$30,&TA0CTL           \ stop timer_A0
37023 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
37024 \ ******************************\
37025 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
37026 \ ******************************\
37027 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
37028 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
37029 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
37030 BIT     #BIT13,X                \ X(13) = New_RC5_command
37031 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
37032 THEN                            \
37033 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
37034 \ ******************************\
37035 \ RC5_ComputeNewRC5word         \
37036 \ ******************************\
37037 SUB     #4,PSP                  \
37038 MOV     &BASE,2(PSP)            \ save variable BASE before use
37039 MOV     TOS,0(PSP)              \ save TOS before use
37040 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
37041 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
37042 \ ******************************\
37043 \ RC5_ComputeC6bit              \
37044 \ ******************************\
37045 BIT     #$4000,IP              \ test /C6 bit in IP
37046 0= IF   BIS #$40,TOS           \ set C6 bit in S
37047 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
37048 \ ******************************\
37049 \ RC5_CommandByteIsDone         \ RC5_code --
37050 \ ******************************\
37051
37052 \ ------------------------------\
37053 \ Display IR_RC5 code           \
37054 \ ------------------------------\
37055 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
37056 \ ------------------------------\
37057 LO2HI                           \ switch from assembler to FORTH
37058     ['] LCD_CLEAR IS CR         \ redirects CR
37059     ['] LCD_WrC  IS EMIT        \ redirects EMIT
37060     $10 BASE !                 \ change BASE to hexadecimal
37061     CR ." $" 2 U.R             \ print IR_RC5 code
37062     ['] (CR) IS CR              \ restore CR
37063     ['] (EMIT) IS EMIT          \ restore EMIT
37064 HI2LO                           \ switch from FORTH to assembler
37065 \ ------------------------------\
37066 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
37067 \ ------------------------------\
37068 MOV @PSP+,&BASE                 \ restore variable BASE
37069 RETI                            \ CPU is ON, GIE is OFF
37070 ENDASM                          \
37071     \ 
37072
37073 CODE START                      \
37074 \ ------------------------------\
37075 \ TB0CTL = %0000 0010 1001 0100\$3C0
37076 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
37077 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
37078 \                      --       \ID input divider \ 10 = /4
37079 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
37080 \                            -  \TBCLR TimerB Clear
37081 \                             - \TBIE
37082 \                              -\TBIFG
37083 \ --------------------------------\\
37084 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
37085 \              --                 \CM Capture Mode
37086 \                --               \CCIS
37087 \                   -             \SCS
37088 \                    --           \CLLD
37089 \                      -          \CAP
37090 \                        ---      \OUTMOD \ 011 = set/reset
37091 \                           -     \CCIE
37092 \                             -   \CCI
37093 \                              -  \OUT
37094 \                               - \COV
37095 \                                -\CCIFG
37096 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
37097 \ TB0EX0                          \$3E0 
37098 \ ------------------------------\
37099 \ set TimerB to make 50kHz PWM  \
37100 \ ------------------------------\
37101 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
37102 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
37103 \ ------------------------------\
37104 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
37105 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
37106 \ ------------------------------\
37107     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
37108     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
37109 \ ------------------------------\
37110 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
37111 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
37112 \ ------------------------------\
37113 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
37114 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
37115 \ ------------------------------\
37116     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
37117 \ ------------------------------\
37118 \ set TimerB to generate PWM for LCD_Vo
37119 \ ------------------------------\
37120     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
37121 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
37122     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
37123 \ ------------------------------\
37124     BIS.B #LCDVo,&LCDVo_DIR     \
37125     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
37126 \ ------------------------------\
37127     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
37128     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
37129 \ ------------------------------\
37130     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
37131     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
37132 \ ------------------------------\
37133 \ WDT interval init part        \
37134 \ ------------------------------\
37135     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
37136 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
37137 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
37138     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
37139 \ ------------------------------\
37140 \ init RC5_Int                  \
37141 \ ------------------------------\
37142     BIS.B #RC5,&IR_IE           \ enable RC5_Int
37143     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
37144 \ ------------------------------\
37145 \ init interrupt vectors
37146 \ ------------------------------\
37147     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
37148     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
37149 \ ------------------------------\
37150 \ define LPM mode for ACCEPT    \
37151 \ ------------------------------\
37152 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
37153 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
37154 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
37155
37156 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
37157
37158 \ ------------------------------\
37159 \ Init LCD 2x20                 \
37160 \ ------------------------------\
37161     $03E8 20_US                \ 1-  wait 20 ms
37162     $03 TOP_LCD                \ 2- send DB5=DB4=1
37163     $CD 20_US                  \ 3- wait 4,1 ms
37164     $03 TOP_LCD                \ 4- send again DB5=DB4=1
37165     $5 20_US                   \ 5- wait 0,1 ms
37166     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
37167     $2 20_US                   \    wait 40 us = LCD cycle
37168     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
37169     $2 20_US                   \    wait 40 us = LCD cycle
37170     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
37171     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
37172     LCD_Clear                   \ 10- "LCD_Clear"
37173     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
37174     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
37175     LCD_Clear                   \ 10- "LCD_Clear"
37176     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
37177     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
37178     CR ." I love you"   
37179     ['] (CR) IS CR              \ ' (CR) is CR
37180     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
37181     CR
37182     ."    RC5toLCD is running. Type STOP to quit"
37183 \    NOECHO                      \ uncomment to run this app without terminal connexion
37184     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
37185     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
37186 ;
37187     \
37188
37189 : STOP                  \ stops multitasking, must to be used before downloading app
37190     ['] (WARM) IS WARM  \ remove START app from FORTH init process
37191     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
37192 ;
37193     \
37194
37195
37196 RST_STATE   ;
37197
37198
37199 CODE MAX    \    n1 n2 -- n3       signed maximum
37200             CMP     @PSP,TOS    \ n2-n1
37201             S<      ?GOTO FW1   \ n2<n1
37202 BW1         ADD     #2,PSP
37203             MOV     @IP+,PC
37204 ENDCODE
37205     \
37206
37207 CODE MIN    \    n1 n2 -- n3       signed minimum
37208             CMP     @PSP,TOS     \ n2-n1
37209             S<      ?GOTO BW1    \ n2<n1
37210 FW1         MOV     @PSP+,TOS
37211             MOV     @IP+,PC
37212 ENDCODE
37213     \
37214
37215 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
37216   >R  <# 0 # #S #>  
37217   R> OVER - 0 MAX SPACES TYPE
37218 ;
37219     \
37220
37221 CODE 20_US                      \ n --      n * 20 us
37222 BEGIN                           \ 3 cycles loop + 6~  
37223 \    MOV     #5,W                \ 3 MCLK = 1 MHz
37224 \    MOV     #23,W               \ 3 MCLK = 4 MHz
37225     MOV     #51,W               \ 3 MCLK = 8 MHz
37226 \    MOV     #104,W              \ 3 MCLK = 16 MHz
37227 \    MOV     #158,W              \ 3 MCLK = 24 MHz
37228     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
37229         SUB #1,W                \ 1
37230     0= UNTIL                    \ 2
37231     SUB     #1,TOS              \ 1
37232 0= UNTIL                        \ 2
37233     MOV     @PSP+,TOS           \ 2
37234     MOV     @IP+,PC             \ 4
37235 ENDCODE
37236     \
37237
37238 CODE TOP_LCD                    \ LCD Sample
37239 \                               \ if write : %xxxxWWWW --
37240 \                               \ if read  : -- %0000RRRR
37241     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
37242     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
37243 0= IF                           \ write LCD bits pattern
37244     AND.B #LCD_DB,TOS           \ 
37245     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
37246     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
37247     MOV @PSP+,TOS               \
37248     MOV @IP+,PC
37249 THEN                            \ read LCD bits pattern
37250     SUB #2,PSP
37251     MOV TOS,0(PSP)
37252     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
37253     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
37254     AND.B #LCD_DB,TOS           \
37255     MOV @IP+,PC
37256 ENDCODE
37257     \
37258
37259 CODE LCD_W                      \ byte --       write byte to LCD 
37260     SUB #2,PSP                  \
37261     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
37262     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
37263     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
37264     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
37265 COLON                           \ high level word starts here 
37266     TOP_LCD 2 20_US             \ write high nibble first
37267     TOP_LCD 2 20_US 
37268 ;
37269     \
37270
37271 CODE LCD_WrC                    \ char --         Write Char
37272     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
37273     JMP LCD_W 
37274 ENDCODE
37275     \
37276
37277 CODE LCD_WrF                    \ func --         Write Fonction
37278     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
37279     JMP LCD_W 
37280 ENDCODE
37281     \
37282
37283 : LCD_Clear 
37284     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
37285 ;
37286     \
37287
37288 : LCD_Home 
37289     $02 LCD_WrF 100 20_us 
37290 ;
37291     \
37292
37293 \ : LCD_Entry_set       $04 OR LCD_WrF ;
37294
37295 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
37296
37297 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
37298
37299 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
37300
37301 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
37302
37303 \ : LCD_Goto            $80 OR LCD_WrF ;
37304
37305 \ CODE LCD_R                      \ -- byte       read byte from LCD
37306 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
37307 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
37308 \ COLON                           \ starts a FORTH word
37309 \     TOP_LCD 2 20_us             \ -- %0000HHHH
37310 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
37311 \ HI2LO                           \ switch from FORTH to assembler
37312 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
37313 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
37314 \     MOV @RSP+,IP                \ restore IP saved by COLON
37315 \     MOV @IP+,PC                 \
37316 \ ENDCODE
37317 \     \
37318
37319 \ CODE LCD_RdS                    \ -- status       Read Status
37320 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
37321 \     JMP LCD_R
37322 \ ENDCODE
37323 \     \
37324
37325 \ CODE LCD_RdC                    \ -- char         Read Char
37326 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
37327 \     JMP LCD_R
37328 \ ENDCODE
37329 \     \
37330
37331 \ -------------+------+------+------+------++---+---+---+---+---------+
37332 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
37333 \ -------------+------+------+------+------++---+---+---+---+---------+
37334 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
37335 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
37336 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
37337 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
37338 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
37339 \ -------------+------+------+------+------++---+---+---+---+---------+
37340
37341
37342 \ ******************************\
37343 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
37344 \ ******************************\
37345 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
37346 \ ------------------------------\
37347 \ define LPM mode for ACCEPT    \
37348 \ ------------------------------\
37349 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
37350 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
37351 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
37352 BIT.B #SW2,&SW2_IN              \ test switch S2
37353 0= IF                           \ case of switch S2 pressed
37354     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
37355     U< IF
37356         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
37357     THEN
37358 ELSE
37359     BIT.B #SW1,&SW1_IN          \ test switch S1 input
37360     0= IF                       \ case of Switch S1 pressed
37361         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
37362         U>= IF                  \
37363             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
37364         THEN                    \
37365     THEN                        \
37366 THEN                            \
37367 RETI                            \ CPU is ON, GIE is OFF
37368 ENDASM                          \
37369     \
37370
37371
37372 \ ------------------------------\
37373 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
37374 \ ******************************\
37375 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
37376 \ ******************************\
37377 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
37378 \                               \       SMclock = 8|16|24 MHz
37379 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
37380 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
37381 \                               \       SR(9)=new Toggle bit memory (ADD on)
37382 \ ------------------------------\
37383 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
37384 \ ------------------------------\
37385 \ define LPM mode for ACCEPT    \
37386 \ ------------------------------\
37387 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
37388 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
37389 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
37390 \ ------------------------------\
37391 \ RC5_FirstStartBitHalfCycle:   \
37392 \ ------------------------------\
37393 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
37394 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
37395 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
37396 MOV     #1778,X                 \ RC5_Period in us
37397 MOV     #14,W                   \ count of loop
37398 BEGIN                           \
37399 \ ------------------------------\
37400 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
37401 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
37402     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
37403 \ RC5_Compute_3/4_Period:       \                   |
37404     RRUM    #1,X                \ X=1/2 cycle       |
37405     MOV     X,Y                 \ Y=1/2             ^
37406     RRUM    #1,Y                \ Y=1/4
37407     ADD     X,Y                 \ Y=3/4
37408 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
37409     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
37410     0= UNTIL                    \
37411 \ ------------------------------\
37412 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
37413 \ ------------------------------\
37414     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
37415     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
37416     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
37417     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
37418     SUB     #1,W                \ decrement count loop
37419 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
37420 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
37421 0<> WHILE                       \ ----> out of loop ----+
37422 \ RC5_compute_7/4_Time_out:     \                       |
37423     ADD     X,Y                 \                       |   out of bound = 7/4 period 
37424 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
37425     BEGIN                       \                       |
37426         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
37427         0>= IF                  \                       |   if cycle time out of bound
37428             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
37429             RETI                \                       |   then quit to do nothing
37430         THEN                    \                       |
37431 \ ------------------------------\                       |
37432         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
37433     0<> UNTIL                   \                   |   |
37434     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
37435 REPEAT                          \ ----> loop back --+   |
37436 \ ------------------------------\                       |
37437 \ RC5_SampleEndOf:              \ <---------------------+
37438 \ ------------------------------\
37439 BIC     #$30,&TA0CTL           \ stop timer_A0
37440 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
37441 \ ******************************\
37442 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
37443 \ ******************************\
37444 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
37445 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
37446 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
37447 BIT     #BIT13,X                \ X(13) = New_RC5_command
37448 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
37449 THEN                            \
37450 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
37451 \ ******************************\
37452 \ RC5_ComputeNewRC5word         \
37453 \ ******************************\
37454 SUB     #4,PSP                  \
37455 MOV     &BASE,2(PSP)            \ save variable BASE before use
37456 MOV     TOS,0(PSP)              \ save TOS before use
37457 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
37458 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
37459 \ ******************************\
37460 \ RC5_ComputeC6bit              \
37461 \ ******************************\
37462 BIT     #$4000,IP              \ test /C6 bit in IP
37463 0= IF   BIS #$40,TOS           \ set C6 bit in S
37464 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
37465 \ ******************************\
37466 \ RC5_CommandByteIsDone         \ RC5_code --
37467 \ ******************************\
37468
37469 \ ------------------------------\
37470 \ Display IR_RC5 code           \
37471 \ ------------------------------\
37472 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
37473 \ ------------------------------\
37474 LO2HI                           \ switch from assembler to FORTH
37475     ['] LCD_CLEAR IS CR         \ redirects CR
37476     ['] LCD_WrC  IS EMIT        \ redirects EMIT
37477     $10 BASE !                 \ change BASE to hexadecimal
37478     CR ." $" 2 U.R             \ print IR_RC5 code
37479     ['] (CR) IS CR              \ restore CR
37480     ['] (EMIT) IS EMIT          \ restore EMIT
37481 HI2LO                           \ switch from FORTH to assembler
37482 \ ------------------------------\
37483 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
37484 \ ------------------------------\
37485 MOV @PSP+,&BASE                 \ restore variable BASE
37486 RETI                            \ CPU is ON, GIE is OFF
37487 ENDASM                          \
37488     \ 
37489
37490 CODE START                      \
37491 \ ------------------------------\
37492 \ TB0CTL = %0000 0010 1001 0100\$3C0
37493 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
37494 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
37495 \                      --       \ID input divider \ 10 = /4
37496 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
37497 \                            -  \TBCLR TimerB Clear
37498 \                             - \TBIE
37499 \                              -\TBIFG
37500 \ --------------------------------\\
37501 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
37502 \              --                 \CM Capture Mode
37503 \                --               \CCIS
37504 \                   -             \SCS
37505 \                    --           \CLLD
37506 \                      -          \CAP
37507 \                        ---      \OUTMOD \ 011 = set/reset
37508 \                           -     \CCIE
37509 \                             -   \CCI
37510 \                              -  \OUT
37511 \                               - \COV
37512 \                                -\CCIFG
37513 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
37514 \ TB0EX0                          \$3E0 
37515 \ ------------------------------\
37516 \ set TimerB to make 50kHz PWM  \
37517 \ ------------------------------\
37518 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
37519 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
37520 \ ------------------------------\
37521 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
37522 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
37523 \ ------------------------------\
37524     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
37525     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
37526 \ ------------------------------\
37527 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
37528 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
37529 \ ------------------------------\
37530 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
37531 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
37532 \ ------------------------------\
37533     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
37534 \ ------------------------------\
37535 \ set TimerB to generate PWM for LCD_Vo
37536 \ ------------------------------\
37537     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
37538 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
37539     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
37540 \ ------------------------------\
37541     BIS.B #LCDVo,&LCDVo_DIR     \
37542     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
37543 \ ------------------------------\
37544     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
37545     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
37546 \ ------------------------------\
37547     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
37548     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
37549 \ ------------------------------\
37550 \ WDT interval init part        \
37551 \ ------------------------------\
37552     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
37553 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
37554 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
37555     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
37556 \ ------------------------------\
37557 \ init RC5_Int                  \
37558 \ ------------------------------\
37559     BIS.B #RC5,&IR_IE           \ enable RC5_Int
37560     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
37561 \ ------------------------------\
37562 \ init interrupt vectors
37563 \ ------------------------------\
37564     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
37565     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
37566 \ ------------------------------\
37567 \ define LPM mode for ACCEPT    \
37568 \ ------------------------------\
37569 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
37570 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
37571 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
37572
37573 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
37574
37575 \ ------------------------------\
37576 \ Init LCD 2x20                 \
37577 \ ------------------------------\
37578     $03E8 20_US                \ 1-  wait 20 ms
37579     $03 TOP_LCD                \ 2- send DB5=DB4=1
37580     $CD 20_US                  \ 3- wait 4,1 ms
37581     $03 TOP_LCD                \ 4- send again DB5=DB4=1
37582     $5 20_US                   \ 5- wait 0,1 ms
37583     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
37584     $2 20_US                   \    wait 40 us = LCD cycle
37585     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
37586     $2 20_US                   \    wait 40 us = LCD cycle
37587     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
37588     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
37589     LCD_Clear                   \ 10- "LCD_Clear"
37590     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
37591     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
37592     LCD_Clear                   \ 10- "LCD_Clear"
37593     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
37594     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
37595     CR ." I love you"   
37596     ['] (CR) IS CR              \ ' (CR) is CR
37597     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
37598     CR
37599     ."    RC5toLCD is running. Type STOP to quit"
37600 \    NOECHO                      \ uncomment to run this app without terminal connexion
37601     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
37602     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
37603 ;
37604     \
37605
37606 : STOP                  \ stops multitasking, must to be used before downloading app
37607     ['] (WARM) IS WARM  \ remove START app from FORTH init process
37608     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
37609 ;
37610     \
37611
37612
37613 RST_STATE   ;
37614
37615
37616 CODE MAX    \    n1 n2 -- n3       signed maximum
37617             CMP     @PSP,TOS    \ n2-n1
37618             S<      ?GOTO FW1   \ n2<n1
37619 BW1         ADD     #2,PSP
37620             MOV     @IP+,PC
37621 ENDCODE
37622     \
37623
37624 CODE MIN    \    n1 n2 -- n3       signed minimum
37625             CMP     @PSP,TOS     \ n2-n1
37626             S<      ?GOTO BW1    \ n2<n1
37627 FW1         MOV     @PSP+,TOS
37628             MOV     @IP+,PC
37629 ENDCODE
37630     \
37631
37632 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
37633   >R  <# 0 # #S #>  
37634   R> OVER - 0 MAX SPACES TYPE
37635 ;
37636     \
37637
37638 CODE 20_US                      \ n --      n * 20 us
37639 BEGIN                           \ 3 cycles loop + 6~  
37640 \    MOV     #5,W                \ 3 MCLK = 1 MHz
37641 \    MOV     #23,W               \ 3 MCLK = 4 MHz
37642     MOV     #51,W               \ 3 MCLK = 8 MHz
37643 \    MOV     #104,W              \ 3 MCLK = 16 MHz
37644 \    MOV     #158,W              \ 3 MCLK = 24 MHz
37645     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
37646         SUB #1,W                \ 1
37647     0= UNTIL                    \ 2
37648     SUB     #1,TOS              \ 1
37649 0= UNTIL                        \ 2
37650     MOV     @PSP+,TOS           \ 2
37651     MOV     @IP+,PC             \ 4
37652 ENDCODE
37653     \
37654
37655 CODE TOP_LCD                    \ LCD Sample
37656 \                               \ if write : %xxxxWWWW --
37657 \                               \ if read  : -- %0000RRRR
37658     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
37659     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
37660 0= IF                           \ write LCD bits pattern
37661     AND.B #LCD_DB,TOS           \ 
37662     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
37663     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
37664     MOV @PSP+,TOS               \
37665     MOV @IP+,PC
37666 THEN                            \ read LCD bits pattern
37667     SUB #2,PSP
37668     MOV TOS,0(PSP)
37669     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
37670     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
37671     AND.B #LCD_DB,TOS           \
37672     MOV @IP+,PC
37673 ENDCODE
37674     \
37675
37676 CODE LCD_W                      \ byte --       write byte to LCD 
37677     SUB #2,PSP                  \
37678     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
37679     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
37680     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
37681     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
37682 COLON                           \ high level word starts here 
37683     TOP_LCD 2 20_US             \ write high nibble first
37684     TOP_LCD 2 20_US 
37685 ;
37686     \
37687
37688 CODE LCD_WrC                    \ char --         Write Char
37689     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
37690     JMP LCD_W 
37691 ENDCODE
37692     \
37693
37694 CODE LCD_WrF                    \ func --         Write Fonction
37695     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
37696     JMP LCD_W 
37697 ENDCODE
37698     \
37699
37700 : LCD_Clear 
37701     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
37702 ;
37703     \
37704
37705 : LCD_Home 
37706     $02 LCD_WrF 100 20_us 
37707 ;
37708     \
37709
37710 \ : LCD_Entry_set       $04 OR LCD_WrF ;
37711
37712 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
37713
37714 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
37715
37716 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
37717
37718 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
37719
37720 \ : LCD_Goto            $80 OR LCD_WrF ;
37721
37722 \ CODE LCD_R                      \ -- byte       read byte from LCD
37723 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
37724 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
37725 \ COLON                           \ starts a FORTH word
37726 \     TOP_LCD 2 20_us             \ -- %0000HHHH
37727 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
37728 \ HI2LO                           \ switch from FORTH to assembler
37729 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
37730 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
37731 \     MOV @RSP+,IP                \ restore IP saved by COLON
37732 \     MOV @IP+,PC                 \
37733 \ ENDCODE
37734 \     \
37735
37736 \ CODE LCD_RdS                    \ -- status       Read Status
37737 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
37738 \     JMP LCD_R
37739 \ ENDCODE
37740 \     \
37741
37742 \ CODE LCD_RdC                    \ -- char         Read Char
37743 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
37744 \     JMP LCD_R
37745 \ ENDCODE
37746 \     \
37747
37748 \ -------------+------+------+------+------++---+---+---+---+---------+
37749 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
37750 \ -------------+------+------+------+------++---+---+---+---+---------+
37751 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
37752 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
37753 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
37754 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
37755 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
37756 \ -------------+------+------+------+------++---+---+---+---+---------+
37757
37758
37759 \ ******************************\
37760 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
37761 \ ******************************\
37762 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
37763 \ ------------------------------\
37764 \ define LPM mode for ACCEPT    \
37765 \ ------------------------------\
37766 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
37767 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
37768 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
37769 BIT.B #SW2,&SW2_IN              \ test switch S2
37770 0= IF                           \ case of switch S2 pressed
37771     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
37772     U< IF
37773         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
37774     THEN
37775 ELSE
37776     BIT.B #SW1,&SW1_IN          \ test switch S1 input
37777     0= IF                       \ case of Switch S1 pressed
37778         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
37779         U>= IF                  \
37780             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
37781         THEN                    \
37782     THEN                        \
37783 THEN                            \
37784 RETI                            \ CPU is ON, GIE is OFF
37785 ENDASM                          \
37786     \
37787
37788
37789 \ ------------------------------\
37790 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
37791 \ ******************************\
37792 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
37793 \ ******************************\
37794 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
37795 \                               \       SMclock = 8|16|24 MHz
37796 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
37797 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
37798 \                               \       SR(9)=new Toggle bit memory (ADD on)
37799 \ ------------------------------\
37800 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
37801 \ ------------------------------\
37802 \ define LPM mode for ACCEPT    \
37803 \ ------------------------------\
37804 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
37805 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
37806 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
37807 \ ------------------------------\
37808 \ RC5_FirstStartBitHalfCycle:   \
37809 \ ------------------------------\
37810 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
37811 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
37812 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
37813 MOV     #1778,X                 \ RC5_Period in us
37814 MOV     #14,W                   \ count of loop
37815 BEGIN                           \
37816 \ ------------------------------\
37817 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
37818 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
37819     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
37820 \ RC5_Compute_3/4_Period:       \                   |
37821     RRUM    #1,X                \ X=1/2 cycle       |
37822     MOV     X,Y                 \ Y=1/2             ^
37823     RRUM    #1,Y                \ Y=1/4
37824     ADD     X,Y                 \ Y=3/4
37825 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
37826     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
37827     0= UNTIL                    \
37828 \ ------------------------------\
37829 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
37830 \ ------------------------------\
37831     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
37832     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
37833     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
37834     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
37835     SUB     #1,W                \ decrement count loop
37836 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
37837 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
37838 0<> WHILE                       \ ----> out of loop ----+
37839 \ RC5_compute_7/4_Time_out:     \                       |
37840     ADD     X,Y                 \                       |   out of bound = 7/4 period 
37841 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
37842     BEGIN                       \                       |
37843         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
37844         0>= IF                  \                       |   if cycle time out of bound
37845             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
37846             RETI                \                       |   then quit to do nothing
37847         THEN                    \                       |
37848 \ ------------------------------\                       |
37849         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
37850     0<> UNTIL                   \                   |   |
37851     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
37852 REPEAT                          \ ----> loop back --+   |
37853 \ ------------------------------\                       |
37854 \ RC5_SampleEndOf:              \ <---------------------+
37855 \ ------------------------------\
37856 BIC     #$30,&TA0CTL           \ stop timer_A0
37857 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
37858 \ ******************************\
37859 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
37860 \ ******************************\
37861 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
37862 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
37863 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
37864 BIT     #BIT13,X                \ X(13) = New_RC5_command
37865 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
37866 THEN                            \
37867 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
37868 \ ******************************\
37869 \ RC5_ComputeNewRC5word         \
37870 \ ******************************\
37871 SUB     #4,PSP                  \
37872 MOV     &BASE,2(PSP)            \ save variable BASE before use
37873 MOV     TOS,0(PSP)              \ save TOS before use
37874 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
37875 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
37876 \ ******************************\
37877 \ RC5_ComputeC6bit              \
37878 \ ******************************\
37879 BIT     #$4000,IP              \ test /C6 bit in IP
37880 0= IF   BIS #$40,TOS           \ set C6 bit in S
37881 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
37882 \ ******************************\
37883 \ RC5_CommandByteIsDone         \ RC5_code --
37884 \ ******************************\
37885
37886 \ ------------------------------\
37887 \ Display IR_RC5 code           \
37888 \ ------------------------------\
37889 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
37890 \ ------------------------------\
37891 LO2HI                           \ switch from assembler to FORTH
37892     ['] LCD_CLEAR IS CR         \ redirects CR
37893     ['] LCD_WrC  IS EMIT        \ redirects EMIT
37894     $10 BASE !                 \ change BASE to hexadecimal
37895     CR ." $" 2 U.R             \ print IR_RC5 code
37896     ['] (CR) IS CR              \ restore CR
37897     ['] (EMIT) IS EMIT          \ restore EMIT
37898 HI2LO                           \ switch from FORTH to assembler
37899 \ ------------------------------\
37900 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
37901 \ ------------------------------\
37902 MOV @PSP+,&BASE                 \ restore variable BASE
37903 RETI                            \ CPU is ON, GIE is OFF
37904 ENDASM                          \
37905     \ 
37906
37907 CODE START                      \
37908 \ ------------------------------\
37909 \ TB0CTL = %0000 0010 1001 0100\$3C0
37910 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
37911 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
37912 \                      --       \ID input divider \ 10 = /4
37913 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
37914 \                            -  \TBCLR TimerB Clear
37915 \                             - \TBIE
37916 \                              -\TBIFG
37917 \ --------------------------------\\
37918 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
37919 \              --                 \CM Capture Mode
37920 \                --               \CCIS
37921 \                   -             \SCS
37922 \                    --           \CLLD
37923 \                      -          \CAP
37924 \                        ---      \OUTMOD \ 011 = set/reset
37925 \                           -     \CCIE
37926 \                             -   \CCI
37927 \                              -  \OUT
37928 \                               - \COV
37929 \                                -\CCIFG
37930 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
37931 \ TB0EX0                          \$3E0 
37932 \ ------------------------------\
37933 \ set TimerB to make 50kHz PWM  \
37934 \ ------------------------------\
37935 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
37936 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
37937 \ ------------------------------\
37938 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
37939 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
37940 \ ------------------------------\
37941     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
37942     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
37943 \ ------------------------------\
37944 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
37945 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
37946 \ ------------------------------\
37947 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
37948 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
37949 \ ------------------------------\
37950     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
37951 \ ------------------------------\
37952 \ set TimerB to generate PWM for LCD_Vo
37953 \ ------------------------------\
37954     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
37955 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
37956     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
37957 \ ------------------------------\
37958     BIS.B #LCDVo,&LCDVo_DIR     \
37959     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
37960 \ ------------------------------\
37961     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
37962     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
37963 \ ------------------------------\
37964     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
37965     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
37966 \ ------------------------------\
37967 \ WDT interval init part        \
37968 \ ------------------------------\
37969     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
37970 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
37971 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
37972     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
37973 \ ------------------------------\
37974 \ init RC5_Int                  \
37975 \ ------------------------------\
37976     BIS.B #RC5,&IR_IE           \ enable RC5_Int
37977     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
37978 \ ------------------------------\
37979 \ init interrupt vectors
37980 \ ------------------------------\
37981     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
37982     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
37983 \ ------------------------------\
37984 \ define LPM mode for ACCEPT    \
37985 \ ------------------------------\
37986 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
37987 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
37988 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
37989
37990 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
37991
37992 \ ------------------------------\
37993 \ Init LCD 2x20                 \
37994 \ ------------------------------\
37995     $03E8 20_US                \ 1-  wait 20 ms
37996     $03 TOP_LCD                \ 2- send DB5=DB4=1
37997     $CD 20_US                  \ 3- wait 4,1 ms
37998     $03 TOP_LCD                \ 4- send again DB5=DB4=1
37999     $5 20_US                   \ 5- wait 0,1 ms
38000     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
38001     $2 20_US                   \    wait 40 us = LCD cycle
38002     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
38003     $2 20_US                   \    wait 40 us = LCD cycle
38004     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
38005     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
38006     LCD_Clear                   \ 10- "LCD_Clear"
38007     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
38008     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
38009     LCD_Clear                   \ 10- "LCD_Clear"
38010     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
38011     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
38012     CR ." I love you"   
38013     ['] (CR) IS CR              \ ' (CR) is CR
38014     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
38015     CR
38016     ."    RC5toLCD is running. Type STOP to quit"
38017 \    NOECHO                      \ uncomment to run this app without terminal connexion
38018     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
38019     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
38020 ;
38021     \
38022
38023 : STOP                  \ stops multitasking, must to be used before downloading app
38024     ['] (WARM) IS WARM  \ remove START app from FORTH init process
38025     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
38026 ;
38027     \
38028
38029
38030 RST_STATE   ;
38031
38032
38033 CODE MAX    \    n1 n2 -- n3       signed maximum
38034             CMP     @PSP,TOS    \ n2-n1
38035             S<      ?GOTO FW1   \ n2<n1
38036 BW1         ADD     #2,PSP
38037             MOV     @IP+,PC
38038 ENDCODE
38039     \
38040
38041 CODE MIN    \    n1 n2 -- n3       signed minimum
38042             CMP     @PSP,TOS     \ n2-n1
38043             S<      ?GOTO BW1    \ n2<n1
38044 FW1         MOV     @PSP+,TOS
38045             MOV     @IP+,PC
38046 ENDCODE
38047     \
38048
38049 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
38050   >R  <# 0 # #S #>  
38051   R> OVER - 0 MAX SPACES TYPE
38052 ;
38053     \
38054
38055 CODE 20_US                      \ n --      n * 20 us
38056 BEGIN                           \ 3 cycles loop + 6~  
38057 \    MOV     #5,W                \ 3 MCLK = 1 MHz
38058 \    MOV     #23,W               \ 3 MCLK = 4 MHz
38059     MOV     #51,W               \ 3 MCLK = 8 MHz
38060 \    MOV     #104,W              \ 3 MCLK = 16 MHz
38061 \    MOV     #158,W              \ 3 MCLK = 24 MHz
38062     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
38063         SUB #1,W                \ 1
38064     0= UNTIL                    \ 2
38065     SUB     #1,TOS              \ 1
38066 0= UNTIL                        \ 2
38067     MOV     @PSP+,TOS           \ 2
38068     MOV     @IP+,PC             \ 4
38069 ENDCODE
38070     \
38071
38072 CODE TOP_LCD                    \ LCD Sample
38073 \                               \ if write : %xxxxWWWW --
38074 \                               \ if read  : -- %0000RRRR
38075     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
38076     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
38077 0= IF                           \ write LCD bits pattern
38078     AND.B #LCD_DB,TOS           \ 
38079     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
38080     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
38081     MOV @PSP+,TOS               \
38082     MOV @IP+,PC
38083 THEN                            \ read LCD bits pattern
38084     SUB #2,PSP
38085     MOV TOS,0(PSP)
38086     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
38087     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
38088     AND.B #LCD_DB,TOS           \
38089     MOV @IP+,PC
38090 ENDCODE
38091     \
38092
38093 CODE LCD_W                      \ byte --       write byte to LCD 
38094     SUB #2,PSP                  \
38095     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
38096     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
38097     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
38098     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
38099 COLON                           \ high level word starts here 
38100     TOP_LCD 2 20_US             \ write high nibble first
38101     TOP_LCD 2 20_US 
38102 ;
38103     \
38104
38105 CODE LCD_WrC                    \ char --         Write Char
38106     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
38107     JMP LCD_W 
38108 ENDCODE
38109     \
38110
38111 CODE LCD_WrF                    \ func --         Write Fonction
38112     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
38113     JMP LCD_W 
38114 ENDCODE
38115     \
38116
38117 : LCD_Clear 
38118     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
38119 ;
38120     \
38121
38122 : LCD_Home 
38123     $02 LCD_WrF 100 20_us 
38124 ;
38125     \
38126
38127 \ : LCD_Entry_set       $04 OR LCD_WrF ;
38128
38129 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
38130
38131 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
38132
38133 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
38134
38135 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
38136
38137 \ : LCD_Goto            $80 OR LCD_WrF ;
38138
38139 \ CODE LCD_R                      \ -- byte       read byte from LCD
38140 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
38141 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
38142 \ COLON                           \ starts a FORTH word
38143 \     TOP_LCD 2 20_us             \ -- %0000HHHH
38144 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
38145 \ HI2LO                           \ switch from FORTH to assembler
38146 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
38147 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
38148 \     MOV @RSP+,IP                \ restore IP saved by COLON
38149 \     MOV @IP+,PC                 \
38150 \ ENDCODE
38151 \     \
38152
38153 \ CODE LCD_RdS                    \ -- status       Read Status
38154 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
38155 \     JMP LCD_R
38156 \ ENDCODE
38157 \     \
38158
38159 \ CODE LCD_RdC                    \ -- char         Read Char
38160 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
38161 \     JMP LCD_R
38162 \ ENDCODE
38163 \     \
38164
38165 \ -------------+------+------+------+------++---+---+---+---+---------+
38166 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
38167 \ -------------+------+------+------+------++---+---+---+---+---------+
38168 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
38169 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
38170 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
38171 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
38172 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
38173 \ -------------+------+------+------+------++---+---+---+---+---------+
38174
38175
38176 \ ******************************\
38177 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
38178 \ ******************************\
38179 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
38180 \ ------------------------------\
38181 \ define LPM mode for ACCEPT    \
38182 \ ------------------------------\
38183 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
38184 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
38185 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
38186 BIT.B #SW2,&SW2_IN              \ test switch S2
38187 0= IF                           \ case of switch S2 pressed
38188     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
38189     U< IF
38190         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
38191     THEN
38192 ELSE
38193     BIT.B #SW1,&SW1_IN          \ test switch S1 input
38194     0= IF                       \ case of Switch S1 pressed
38195         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
38196         U>= IF                  \
38197             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
38198         THEN                    \
38199     THEN                        \
38200 THEN                            \
38201 RETI                            \ CPU is ON, GIE is OFF
38202 ENDASM                          \
38203     \
38204
38205
38206 \ ------------------------------\
38207 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
38208 \ ******************************\
38209 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
38210 \ ******************************\
38211 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
38212 \                               \       SMclock = 8|16|24 MHz
38213 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
38214 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
38215 \                               \       SR(9)=new Toggle bit memory (ADD on)
38216 \ ------------------------------\
38217 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
38218 \ ------------------------------\
38219 \ define LPM mode for ACCEPT    \
38220 \ ------------------------------\
38221 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
38222 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
38223 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
38224 \ ------------------------------\
38225 \ RC5_FirstStartBitHalfCycle:   \
38226 \ ------------------------------\
38227 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
38228 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
38229 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
38230 MOV     #1778,X                 \ RC5_Period in us
38231 MOV     #14,W                   \ count of loop
38232 BEGIN                           \
38233 \ ------------------------------\
38234 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
38235 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
38236     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
38237 \ RC5_Compute_3/4_Period:       \                   |
38238     RRUM    #1,X                \ X=1/2 cycle       |
38239     MOV     X,Y                 \ Y=1/2             ^
38240     RRUM    #1,Y                \ Y=1/4
38241     ADD     X,Y                 \ Y=3/4
38242 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
38243     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
38244     0= UNTIL                    \
38245 \ ------------------------------\
38246 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
38247 \ ------------------------------\
38248     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
38249     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
38250     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
38251     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
38252     SUB     #1,W                \ decrement count loop
38253 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
38254 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
38255 0<> WHILE                       \ ----> out of loop ----+
38256 \ RC5_compute_7/4_Time_out:     \                       |
38257     ADD     X,Y                 \                       |   out of bound = 7/4 period 
38258 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
38259     BEGIN                       \                       |
38260         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
38261         0>= IF                  \                       |   if cycle time out of bound
38262             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
38263             RETI                \                       |   then quit to do nothing
38264         THEN                    \                       |
38265 \ ------------------------------\                       |
38266         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
38267     0<> UNTIL                   \                   |   |
38268     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
38269 REPEAT                          \ ----> loop back --+   |
38270 \ ------------------------------\                       |
38271 \ RC5_SampleEndOf:              \ <---------------------+
38272 \ ------------------------------\
38273 BIC     #$30,&TA0CTL           \ stop timer_A0
38274 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
38275 \ ******************************\
38276 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
38277 \ ******************************\
38278 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
38279 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
38280 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
38281 BIT     #BIT13,X                \ X(13) = New_RC5_command
38282 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
38283 THEN                            \
38284 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
38285 \ ******************************\
38286 \ RC5_ComputeNewRC5word         \
38287 \ ******************************\
38288 SUB     #4,PSP                  \
38289 MOV     &BASE,2(PSP)            \ save variable BASE before use
38290 MOV     TOS,0(PSP)              \ save TOS before use
38291 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
38292 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
38293 \ ******************************\
38294 \ RC5_ComputeC6bit              \
38295 \ ******************************\
38296 BIT     #$4000,IP              \ test /C6 bit in IP
38297 0= IF   BIS #$40,TOS           \ set C6 bit in S
38298 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
38299 \ ******************************\
38300 \ RC5_CommandByteIsDone         \ RC5_code --
38301 \ ******************************\
38302
38303 \ ------------------------------\
38304 \ Display IR_RC5 code           \
38305 \ ------------------------------\
38306 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
38307 \ ------------------------------\
38308 LO2HI                           \ switch from assembler to FORTH
38309     ['] LCD_CLEAR IS CR         \ redirects CR
38310     ['] LCD_WrC  IS EMIT        \ redirects EMIT
38311     $10 BASE !                 \ change BASE to hexadecimal
38312     CR ." $" 2 U.R             \ print IR_RC5 code
38313     ['] (CR) IS CR              \ restore CR
38314     ['] (EMIT) IS EMIT          \ restore EMIT
38315 HI2LO                           \ switch from FORTH to assembler
38316 \ ------------------------------\
38317 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
38318 \ ------------------------------\
38319 MOV @PSP+,&BASE                 \ restore variable BASE
38320 RETI                            \ CPU is ON, GIE is OFF
38321 ENDASM                          \
38322     \ 
38323
38324 CODE START                      \
38325 \ ------------------------------\
38326 \ TB0CTL = %0000 0010 1001 0100\$3C0
38327 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
38328 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
38329 \                      --       \ID input divider \ 10 = /4
38330 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
38331 \                            -  \TBCLR TimerB Clear
38332 \                             - \TBIE
38333 \                              -\TBIFG
38334 \ --------------------------------\\
38335 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
38336 \              --                 \CM Capture Mode
38337 \                --               \CCIS
38338 \                   -             \SCS
38339 \                    --           \CLLD
38340 \                      -          \CAP
38341 \                        ---      \OUTMOD \ 011 = set/reset
38342 \                           -     \CCIE
38343 \                             -   \CCI
38344 \                              -  \OUT
38345 \                               - \COV
38346 \                                -\CCIFG
38347 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
38348 \ TB0EX0                          \$3E0 
38349 \ ------------------------------\
38350 \ set TimerB to make 50kHz PWM  \
38351 \ ------------------------------\
38352 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
38353 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
38354 \ ------------------------------\
38355 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
38356 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
38357 \ ------------------------------\
38358     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
38359     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
38360 \ ------------------------------\
38361 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
38362 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
38363 \ ------------------------------\
38364 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
38365 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
38366 \ ------------------------------\
38367     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
38368 \ ------------------------------\
38369 \ set TimerB to generate PWM for LCD_Vo
38370 \ ------------------------------\
38371     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
38372 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
38373     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
38374 \ ------------------------------\
38375     BIS.B #LCDVo,&LCDVo_DIR     \
38376     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
38377 \ ------------------------------\
38378     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
38379     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
38380 \ ------------------------------\
38381     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
38382     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
38383 \ ------------------------------\
38384 \ WDT interval init part        \
38385 \ ------------------------------\
38386     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
38387 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
38388 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
38389     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
38390 \ ------------------------------\
38391 \ init RC5_Int                  \
38392 \ ------------------------------\
38393     BIS.B #RC5,&IR_IE           \ enable RC5_Int
38394     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
38395 \ ------------------------------\
38396 \ init interrupt vectors
38397 \ ------------------------------\
38398     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
38399     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
38400 \ ------------------------------\
38401 \ define LPM mode for ACCEPT    \
38402 \ ------------------------------\
38403 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
38404 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
38405 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
38406
38407 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
38408
38409 \ ------------------------------\
38410 \ Init LCD 2x20                 \
38411 \ ------------------------------\
38412     $03E8 20_US                \ 1-  wait 20 ms
38413     $03 TOP_LCD                \ 2- send DB5=DB4=1
38414     $CD 20_US                  \ 3- wait 4,1 ms
38415     $03 TOP_LCD                \ 4- send again DB5=DB4=1
38416     $5 20_US                   \ 5- wait 0,1 ms
38417     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
38418     $2 20_US                   \    wait 40 us = LCD cycle
38419     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
38420     $2 20_US                   \    wait 40 us = LCD cycle
38421     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
38422     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
38423     LCD_Clear                   \ 10- "LCD_Clear"
38424     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
38425     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
38426     LCD_Clear                   \ 10- "LCD_Clear"
38427     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
38428     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
38429     CR ." I love you"   
38430     ['] (CR) IS CR              \ ' (CR) is CR
38431     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
38432     CR
38433     ."    RC5toLCD is running. Type STOP to quit"
38434 \    NOECHO                      \ uncomment to run this app without terminal connexion
38435     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
38436     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
38437 ;
38438     \
38439
38440 : STOP                  \ stops multitasking, must to be used before downloading app
38441     ['] (WARM) IS WARM  \ remove START app from FORTH init process
38442     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
38443 ;
38444     \
38445
38446
38447 RST_STATE   ;
38448
38449
38450 CODE MAX    \    n1 n2 -- n3       signed maximum
38451             CMP     @PSP,TOS    \ n2-n1
38452             S<      ?GOTO FW1   \ n2<n1
38453 BW1         ADD     #2,PSP
38454             MOV     @IP+,PC
38455 ENDCODE
38456     \
38457
38458 CODE MIN    \    n1 n2 -- n3       signed minimum
38459             CMP     @PSP,TOS     \ n2-n1
38460             S<      ?GOTO BW1    \ n2<n1
38461 FW1         MOV     @PSP+,TOS
38462             MOV     @IP+,PC
38463 ENDCODE
38464     \
38465
38466 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
38467   >R  <# 0 # #S #>  
38468   R> OVER - 0 MAX SPACES TYPE
38469 ;
38470     \
38471
38472 CODE 20_US                      \ n --      n * 20 us
38473 BEGIN                           \ 3 cycles loop + 6~  
38474 \    MOV     #5,W                \ 3 MCLK = 1 MHz
38475 \    MOV     #23,W               \ 3 MCLK = 4 MHz
38476     MOV     #51,W               \ 3 MCLK = 8 MHz
38477 \    MOV     #104,W              \ 3 MCLK = 16 MHz
38478 \    MOV     #158,W              \ 3 MCLK = 24 MHz
38479     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
38480         SUB #1,W                \ 1
38481     0= UNTIL                    \ 2
38482     SUB     #1,TOS              \ 1
38483 0= UNTIL                        \ 2
38484     MOV     @PSP+,TOS           \ 2
38485     MOV     @IP+,PC             \ 4
38486 ENDCODE
38487     \
38488
38489 CODE TOP_LCD                    \ LCD Sample
38490 \                               \ if write : %xxxxWWWW --
38491 \                               \ if read  : -- %0000RRRR
38492     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
38493     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
38494 0= IF                           \ write LCD bits pattern
38495     AND.B #LCD_DB,TOS           \ 
38496     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
38497     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
38498     MOV @PSP+,TOS               \
38499     MOV @IP+,PC
38500 THEN                            \ read LCD bits pattern
38501     SUB #2,PSP
38502     MOV TOS,0(PSP)
38503     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
38504     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
38505     AND.B #LCD_DB,TOS           \
38506     MOV @IP+,PC
38507 ENDCODE
38508     \
38509
38510 CODE LCD_W                      \ byte --       write byte to LCD 
38511     SUB #2,PSP                  \
38512     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
38513     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
38514     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
38515     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
38516 COLON                           \ high level word starts here 
38517     TOP_LCD 2 20_US             \ write high nibble first
38518     TOP_LCD 2 20_US 
38519 ;
38520     \
38521
38522 CODE LCD_WrC                    \ char --         Write Char
38523     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
38524     JMP LCD_W 
38525 ENDCODE
38526     \
38527
38528 CODE LCD_WrF                    \ func --         Write Fonction
38529     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
38530     JMP LCD_W 
38531 ENDCODE
38532     \
38533
38534 : LCD_Clear 
38535     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
38536 ;
38537     \
38538
38539 : LCD_Home 
38540     $02 LCD_WrF 100 20_us 
38541 ;
38542     \
38543
38544 \ : LCD_Entry_set       $04 OR LCD_WrF ;
38545
38546 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
38547
38548 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
38549
38550 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
38551
38552 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
38553
38554 \ : LCD_Goto            $80 OR LCD_WrF ;
38555
38556 \ CODE LCD_R                      \ -- byte       read byte from LCD
38557 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
38558 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
38559 \ COLON                           \ starts a FORTH word
38560 \     TOP_LCD 2 20_us             \ -- %0000HHHH
38561 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
38562 \ HI2LO                           \ switch from FORTH to assembler
38563 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
38564 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
38565 \     MOV @RSP+,IP                \ restore IP saved by COLON
38566 \     MOV @IP+,PC                 \
38567 \ ENDCODE
38568 \     \
38569
38570 \ CODE LCD_RdS                    \ -- status       Read Status
38571 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
38572 \     JMP LCD_R
38573 \ ENDCODE
38574 \     \
38575
38576 \ CODE LCD_RdC                    \ -- char         Read Char
38577 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
38578 \     JMP LCD_R
38579 \ ENDCODE
38580 \     \
38581
38582 \ -------------+------+------+------+------++---+---+---+---+---------+
38583 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
38584 \ -------------+------+------+------+------++---+---+---+---+---------+
38585 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
38586 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
38587 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
38588 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
38589 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
38590 \ -------------+------+------+------+------++---+---+---+---+---------+
38591
38592
38593 \ ******************************\
38594 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
38595 \ ******************************\
38596 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
38597 \ ------------------------------\
38598 \ define LPM mode for ACCEPT    \
38599 \ ------------------------------\
38600 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
38601 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
38602 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
38603 BIT.B #SW2,&SW2_IN              \ test switch S2
38604 0= IF                           \ case of switch S2 pressed
38605     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
38606     U< IF
38607         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
38608     THEN
38609 ELSE
38610     BIT.B #SW1,&SW1_IN          \ test switch S1 input
38611     0= IF                       \ case of Switch S1 pressed
38612         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
38613         U>= IF                  \
38614             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
38615         THEN                    \
38616     THEN                        \
38617 THEN                            \
38618 RETI                            \ CPU is ON, GIE is OFF
38619 ENDASM                          \
38620     \
38621
38622
38623 \ ------------------------------\
38624 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
38625 \ ******************************\
38626 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
38627 \ ******************************\
38628 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
38629 \                               \       SMclock = 8|16|24 MHz
38630 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
38631 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
38632 \                               \       SR(9)=new Toggle bit memory (ADD on)
38633 \ ------------------------------\
38634 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
38635 \ ------------------------------\
38636 \ define LPM mode for ACCEPT    \
38637 \ ------------------------------\
38638 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
38639 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
38640 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
38641 \ ------------------------------\
38642 \ RC5_FirstStartBitHalfCycle:   \
38643 \ ------------------------------\
38644 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
38645 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
38646 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
38647 MOV     #1778,X                 \ RC5_Period in us
38648 MOV     #14,W                   \ count of loop
38649 BEGIN                           \
38650 \ ------------------------------\
38651 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
38652 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
38653     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
38654 \ RC5_Compute_3/4_Period:       \                   |
38655     RRUM    #1,X                \ X=1/2 cycle       |
38656     MOV     X,Y                 \ Y=1/2             ^
38657     RRUM    #1,Y                \ Y=1/4
38658     ADD     X,Y                 \ Y=3/4
38659 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
38660     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
38661     0= UNTIL                    \
38662 \ ------------------------------\
38663 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
38664 \ ------------------------------\
38665     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
38666     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
38667     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
38668     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
38669     SUB     #1,W                \ decrement count loop
38670 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
38671 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
38672 0<> WHILE                       \ ----> out of loop ----+
38673 \ RC5_compute_7/4_Time_out:     \                       |
38674     ADD     X,Y                 \                       |   out of bound = 7/4 period 
38675 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
38676     BEGIN                       \                       |
38677         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
38678         0>= IF                  \                       |   if cycle time out of bound
38679             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
38680             RETI                \                       |   then quit to do nothing
38681         THEN                    \                       |
38682 \ ------------------------------\                       |
38683         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
38684     0<> UNTIL                   \                   |   |
38685     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
38686 REPEAT                          \ ----> loop back --+   |
38687 \ ------------------------------\                       |
38688 \ RC5_SampleEndOf:              \ <---------------------+
38689 \ ------------------------------\
38690 BIC     #$30,&TA0CTL           \ stop timer_A0
38691 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
38692 \ ******************************\
38693 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
38694 \ ******************************\
38695 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
38696 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
38697 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
38698 BIT     #BIT13,X                \ X(13) = New_RC5_command
38699 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
38700 THEN                            \
38701 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
38702 \ ******************************\
38703 \ RC5_ComputeNewRC5word         \
38704 \ ******************************\
38705 SUB     #4,PSP                  \
38706 MOV     &BASE,2(PSP)            \ save variable BASE before use
38707 MOV     TOS,0(PSP)              \ save TOS before use
38708 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
38709 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
38710 \ ******************************\
38711 \ RC5_ComputeC6bit              \
38712 \ ******************************\
38713 BIT     #$4000,IP              \ test /C6 bit in IP
38714 0= IF   BIS #$40,TOS           \ set C6 bit in S
38715 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
38716 \ ******************************\
38717 \ RC5_CommandByteIsDone         \ RC5_code --
38718 \ ******************************\
38719
38720 \ ------------------------------\
38721 \ Display IR_RC5 code           \
38722 \ ------------------------------\
38723 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
38724 \ ------------------------------\
38725 LO2HI                           \ switch from assembler to FORTH
38726     ['] LCD_CLEAR IS CR         \ redirects CR
38727     ['] LCD_WrC  IS EMIT        \ redirects EMIT
38728     $10 BASE !                 \ change BASE to hexadecimal
38729     CR ." $" 2 U.R             \ print IR_RC5 code
38730     ['] (CR) IS CR              \ restore CR
38731     ['] (EMIT) IS EMIT          \ restore EMIT
38732 HI2LO                           \ switch from FORTH to assembler
38733 \ ------------------------------\
38734 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
38735 \ ------------------------------\
38736 MOV @PSP+,&BASE                 \ restore variable BASE
38737 RETI                            \ CPU is ON, GIE is OFF
38738 ENDASM                          \
38739     \ 
38740
38741 CODE START                      \
38742 \ ------------------------------\
38743 \ TB0CTL = %0000 0010 1001 0100\$3C0
38744 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
38745 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
38746 \                      --       \ID input divider \ 10 = /4
38747 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
38748 \                            -  \TBCLR TimerB Clear
38749 \                             - \TBIE
38750 \                              -\TBIFG
38751 \ --------------------------------\\
38752 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
38753 \              --                 \CM Capture Mode
38754 \                --               \CCIS
38755 \                   -             \SCS
38756 \                    --           \CLLD
38757 \                      -          \CAP
38758 \                        ---      \OUTMOD \ 011 = set/reset
38759 \                           -     \CCIE
38760 \                             -   \CCI
38761 \                              -  \OUT
38762 \                               - \COV
38763 \                                -\CCIFG
38764 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
38765 \ TB0EX0                          \$3E0 
38766 \ ------------------------------\
38767 \ set TimerB to make 50kHz PWM  \
38768 \ ------------------------------\
38769 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
38770 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
38771 \ ------------------------------\
38772 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
38773 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
38774 \ ------------------------------\
38775     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
38776     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
38777 \ ------------------------------\
38778 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
38779 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
38780 \ ------------------------------\
38781 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
38782 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
38783 \ ------------------------------\
38784     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
38785 \ ------------------------------\
38786 \ set TimerB to generate PWM for LCD_Vo
38787 \ ------------------------------\
38788     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
38789 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
38790     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
38791 \ ------------------------------\
38792     BIS.B #LCDVo,&LCDVo_DIR     \
38793     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
38794 \ ------------------------------\
38795     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
38796     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
38797 \ ------------------------------\
38798     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
38799     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
38800 \ ------------------------------\
38801 \ WDT interval init part        \
38802 \ ------------------------------\
38803     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
38804 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
38805 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
38806     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
38807 \ ------------------------------\
38808 \ init RC5_Int                  \
38809 \ ------------------------------\
38810     BIS.B #RC5,&IR_IE           \ enable RC5_Int
38811     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
38812 \ ------------------------------\
38813 \ init interrupt vectors
38814 \ ------------------------------\
38815     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
38816     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
38817 \ ------------------------------\
38818 \ define LPM mode for ACCEPT    \
38819 \ ------------------------------\
38820 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
38821 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
38822 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
38823
38824 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
38825
38826 \ ------------------------------\
38827 \ Init LCD 2x20                 \
38828 \ ------------------------------\
38829     $03E8 20_US                \ 1-  wait 20 ms
38830     $03 TOP_LCD                \ 2- send DB5=DB4=1
38831     $CD 20_US                  \ 3- wait 4,1 ms
38832     $03 TOP_LCD                \ 4- send again DB5=DB4=1
38833     $5 20_US                   \ 5- wait 0,1 ms
38834     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
38835     $2 20_US                   \    wait 40 us = LCD cycle
38836     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
38837     $2 20_US                   \    wait 40 us = LCD cycle
38838     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
38839     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
38840     LCD_Clear                   \ 10- "LCD_Clear"
38841     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
38842     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
38843     LCD_Clear                   \ 10- "LCD_Clear"
38844     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
38845     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
38846     CR ." I love you"   
38847     ['] (CR) IS CR              \ ' (CR) is CR
38848     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
38849     CR
38850     ."    RC5toLCD is running. Type STOP to quit"
38851 \    NOECHO                      \ uncomment to run this app without terminal connexion
38852     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
38853     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
38854 ;
38855     \
38856
38857 : STOP                  \ stops multitasking, must to be used before downloading app
38858     ['] (WARM) IS WARM  \ remove START app from FORTH init process
38859     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
38860 ;
38861     \
38862
38863
38864 RST_STATE   ;
38865
38866
38867 CODE MAX    \    n1 n2 -- n3       signed maximum
38868             CMP     @PSP,TOS    \ n2-n1
38869             S<      ?GOTO FW1   \ n2<n1
38870 BW1         ADD     #2,PSP
38871             MOV     @IP+,PC
38872 ENDCODE
38873     \
38874
38875 CODE MIN    \    n1 n2 -- n3       signed minimum
38876             CMP     @PSP,TOS     \ n2-n1
38877             S<      ?GOTO BW1    \ n2<n1
38878 FW1         MOV     @PSP+,TOS
38879             MOV     @IP+,PC
38880 ENDCODE
38881     \
38882
38883 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
38884   >R  <# 0 # #S #>  
38885   R> OVER - 0 MAX SPACES TYPE
38886 ;
38887     \
38888
38889 CODE 20_US                      \ n --      n * 20 us
38890 BEGIN                           \ 3 cycles loop + 6~  
38891 \    MOV     #5,W                \ 3 MCLK = 1 MHz
38892 \    MOV     #23,W               \ 3 MCLK = 4 MHz
38893     MOV     #51,W               \ 3 MCLK = 8 MHz
38894 \    MOV     #104,W              \ 3 MCLK = 16 MHz
38895 \    MOV     #158,W              \ 3 MCLK = 24 MHz
38896     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
38897         SUB #1,W                \ 1
38898     0= UNTIL                    \ 2
38899     SUB     #1,TOS              \ 1
38900 0= UNTIL                        \ 2
38901     MOV     @PSP+,TOS           \ 2
38902     MOV     @IP+,PC             \ 4
38903 ENDCODE
38904     \
38905
38906 CODE TOP_LCD                    \ LCD Sample
38907 \                               \ if write : %xxxxWWWW --
38908 \                               \ if read  : -- %0000RRRR
38909     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
38910     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
38911 0= IF                           \ write LCD bits pattern
38912     AND.B #LCD_DB,TOS           \ 
38913     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
38914     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
38915     MOV @PSP+,TOS               \
38916     MOV @IP+,PC
38917 THEN                            \ read LCD bits pattern
38918     SUB #2,PSP
38919     MOV TOS,0(PSP)
38920     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
38921     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
38922     AND.B #LCD_DB,TOS           \
38923     MOV @IP+,PC
38924 ENDCODE
38925     \
38926
38927 CODE LCD_W                      \ byte --       write byte to LCD 
38928     SUB #2,PSP                  \
38929     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
38930     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
38931     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
38932     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
38933 COLON                           \ high level word starts here 
38934     TOP_LCD 2 20_US             \ write high nibble first
38935     TOP_LCD 2 20_US 
38936 ;
38937     \
38938
38939 CODE LCD_WrC                    \ char --         Write Char
38940     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
38941     JMP LCD_W 
38942 ENDCODE
38943     \
38944
38945 CODE LCD_WrF                    \ func --         Write Fonction
38946     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
38947     JMP LCD_W 
38948 ENDCODE
38949     \
38950
38951 : LCD_Clear 
38952     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
38953 ;
38954     \
38955
38956 : LCD_Home 
38957     $02 LCD_WrF 100 20_us 
38958 ;
38959     \
38960
38961 \ : LCD_Entry_set       $04 OR LCD_WrF ;
38962
38963 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
38964
38965 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
38966
38967 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
38968
38969 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
38970
38971 \ : LCD_Goto            $80 OR LCD_WrF ;
38972
38973 \ CODE LCD_R                      \ -- byte       read byte from LCD
38974 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
38975 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
38976 \ COLON                           \ starts a FORTH word
38977 \     TOP_LCD 2 20_us             \ -- %0000HHHH
38978 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
38979 \ HI2LO                           \ switch from FORTH to assembler
38980 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
38981 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
38982 \     MOV @RSP+,IP                \ restore IP saved by COLON
38983 \     MOV @IP+,PC                 \
38984 \ ENDCODE
38985 \     \
38986
38987 \ CODE LCD_RdS                    \ -- status       Read Status
38988 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
38989 \     JMP LCD_R
38990 \ ENDCODE
38991 \     \
38992
38993 \ CODE LCD_RdC                    \ -- char         Read Char
38994 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
38995 \     JMP LCD_R
38996 \ ENDCODE
38997 \     \
38998
38999 \ -------------+------+------+------+------++---+---+---+---+---------+
39000 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
39001 \ -------------+------+------+------+------++---+---+---+---+---------+
39002 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
39003 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
39004 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
39005 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
39006 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
39007 \ -------------+------+------+------+------++---+---+---+---+---------+
39008
39009
39010 \ ******************************\
39011 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
39012 \ ******************************\
39013 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
39014 \ ------------------------------\
39015 \ define LPM mode for ACCEPT    \
39016 \ ------------------------------\
39017 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
39018 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
39019 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
39020 BIT.B #SW2,&SW2_IN              \ test switch S2
39021 0= IF                           \ case of switch S2 pressed
39022     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
39023     U< IF
39024         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
39025     THEN
39026 ELSE
39027     BIT.B #SW1,&SW1_IN          \ test switch S1 input
39028     0= IF                       \ case of Switch S1 pressed
39029         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
39030         U>= IF                  \
39031             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
39032         THEN                    \
39033     THEN                        \
39034 THEN                            \
39035 RETI                            \ CPU is ON, GIE is OFF
39036 ENDASM                          \
39037     \
39038
39039
39040 \ ------------------------------\
39041 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
39042 \ ******************************\
39043 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
39044 \ ******************************\
39045 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
39046 \                               \       SMclock = 8|16|24 MHz
39047 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
39048 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
39049 \                               \       SR(9)=new Toggle bit memory (ADD on)
39050 \ ------------------------------\
39051 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
39052 \ ------------------------------\
39053 \ define LPM mode for ACCEPT    \
39054 \ ------------------------------\
39055 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
39056 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
39057 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
39058 \ ------------------------------\
39059 \ RC5_FirstStartBitHalfCycle:   \
39060 \ ------------------------------\
39061 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
39062 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
39063 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
39064 MOV     #1778,X                 \ RC5_Period in us
39065 MOV     #14,W                   \ count of loop
39066 BEGIN                           \
39067 \ ------------------------------\
39068 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
39069 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
39070     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
39071 \ RC5_Compute_3/4_Period:       \                   |
39072     RRUM    #1,X                \ X=1/2 cycle       |
39073     MOV     X,Y                 \ Y=1/2             ^
39074     RRUM    #1,Y                \ Y=1/4
39075     ADD     X,Y                 \ Y=3/4
39076 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
39077     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
39078     0= UNTIL                    \
39079 \ ------------------------------\
39080 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
39081 \ ------------------------------\
39082     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
39083     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
39084     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
39085     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
39086     SUB     #1,W                \ decrement count loop
39087 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
39088 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
39089 0<> WHILE                       \ ----> out of loop ----+
39090 \ RC5_compute_7/4_Time_out:     \                       |
39091     ADD     X,Y                 \                       |   out of bound = 7/4 period 
39092 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
39093     BEGIN                       \                       |
39094         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
39095         0>= IF                  \                       |   if cycle time out of bound
39096             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
39097             RETI                \                       |   then quit to do nothing
39098         THEN                    \                       |
39099 \ ------------------------------\                       |
39100         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
39101     0<> UNTIL                   \                   |   |
39102     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
39103 REPEAT                          \ ----> loop back --+   |
39104 \ ------------------------------\                       |
39105 \ RC5_SampleEndOf:              \ <---------------------+
39106 \ ------------------------------\
39107 BIC     #$30,&TA0CTL           \ stop timer_A0
39108 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
39109 \ ******************************\
39110 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
39111 \ ******************************\
39112 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
39113 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
39114 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
39115 BIT     #BIT13,X                \ X(13) = New_RC5_command
39116 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
39117 THEN                            \
39118 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
39119 \ ******************************\
39120 \ RC5_ComputeNewRC5word         \
39121 \ ******************************\
39122 SUB     #4,PSP                  \
39123 MOV     &BASE,2(PSP)            \ save variable BASE before use
39124 MOV     TOS,0(PSP)              \ save TOS before use
39125 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
39126 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
39127 \ ******************************\
39128 \ RC5_ComputeC6bit              \
39129 \ ******************************\
39130 BIT     #$4000,IP              \ test /C6 bit in IP
39131 0= IF   BIS #$40,TOS           \ set C6 bit in S
39132 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
39133 \ ******************************\
39134 \ RC5_CommandByteIsDone         \ RC5_code --
39135 \ ******************************\
39136
39137 \ ------------------------------\
39138 \ Display IR_RC5 code           \
39139 \ ------------------------------\
39140 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
39141 \ ------------------------------\
39142 LO2HI                           \ switch from assembler to FORTH
39143     ['] LCD_CLEAR IS CR         \ redirects CR
39144     ['] LCD_WrC  IS EMIT        \ redirects EMIT
39145     $10 BASE !                 \ change BASE to hexadecimal
39146     CR ." $" 2 U.R             \ print IR_RC5 code
39147     ['] (CR) IS CR              \ restore CR
39148     ['] (EMIT) IS EMIT          \ restore EMIT
39149 HI2LO                           \ switch from FORTH to assembler
39150 \ ------------------------------\
39151 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
39152 \ ------------------------------\
39153 MOV @PSP+,&BASE                 \ restore variable BASE
39154 RETI                            \ CPU is ON, GIE is OFF
39155 ENDASM                          \
39156     \ 
39157
39158 CODE START                      \
39159 \ ------------------------------\
39160 \ TB0CTL = %0000 0010 1001 0100\$3C0
39161 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
39162 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
39163 \                      --       \ID input divider \ 10 = /4
39164 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
39165 \                            -  \TBCLR TimerB Clear
39166 \                             - \TBIE
39167 \                              -\TBIFG
39168 \ --------------------------------\\
39169 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
39170 \              --                 \CM Capture Mode
39171 \                --               \CCIS
39172 \                   -             \SCS
39173 \                    --           \CLLD
39174 \                      -          \CAP
39175 \                        ---      \OUTMOD \ 011 = set/reset
39176 \                           -     \CCIE
39177 \                             -   \CCI
39178 \                              -  \OUT
39179 \                               - \COV
39180 \                                -\CCIFG
39181 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
39182 \ TB0EX0                          \$3E0 
39183 \ ------------------------------\
39184 \ set TimerB to make 50kHz PWM  \
39185 \ ------------------------------\
39186 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
39187 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
39188 \ ------------------------------\
39189 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
39190 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
39191 \ ------------------------------\
39192     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
39193     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
39194 \ ------------------------------\
39195 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
39196 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
39197 \ ------------------------------\
39198 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
39199 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
39200 \ ------------------------------\
39201     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
39202 \ ------------------------------\
39203 \ set TimerB to generate PWM for LCD_Vo
39204 \ ------------------------------\
39205     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
39206 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
39207     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
39208 \ ------------------------------\
39209     BIS.B #LCDVo,&LCDVo_DIR     \
39210     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
39211 \ ------------------------------\
39212     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
39213     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
39214 \ ------------------------------\
39215     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
39216     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
39217 \ ------------------------------\
39218 \ WDT interval init part        \
39219 \ ------------------------------\
39220     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
39221 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
39222 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
39223     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
39224 \ ------------------------------\
39225 \ init RC5_Int                  \
39226 \ ------------------------------\
39227     BIS.B #RC5,&IR_IE           \ enable RC5_Int
39228     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
39229 \ ------------------------------\
39230 \ init interrupt vectors
39231 \ ------------------------------\
39232     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
39233     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
39234 \ ------------------------------\
39235 \ define LPM mode for ACCEPT    \
39236 \ ------------------------------\
39237 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
39238 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
39239 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
39240
39241 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
39242
39243 \ ------------------------------\
39244 \ Init LCD 2x20                 \
39245 \ ------------------------------\
39246     $03E8 20_US                \ 1-  wait 20 ms
39247     $03 TOP_LCD                \ 2- send DB5=DB4=1
39248     $CD 20_US                  \ 3- wait 4,1 ms
39249     $03 TOP_LCD                \ 4- send again DB5=DB4=1
39250     $5 20_US                   \ 5- wait 0,1 ms
39251     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
39252     $2 20_US                   \    wait 40 us = LCD cycle
39253     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
39254     $2 20_US                   \    wait 40 us = LCD cycle
39255     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
39256     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
39257     LCD_Clear                   \ 10- "LCD_Clear"
39258     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
39259     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
39260     LCD_Clear                   \ 10- "LCD_Clear"
39261     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
39262     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
39263     CR ." I love you"   
39264     ['] (CR) IS CR              \ ' (CR) is CR
39265     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
39266     CR
39267     ."    RC5toLCD is running. Type STOP to quit"
39268 \    NOECHO                      \ uncomment to run this app without terminal connexion
39269     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
39270     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
39271 ;
39272     \
39273
39274 : STOP                  \ stops multitasking, must to be used before downloading app
39275     ['] (WARM) IS WARM  \ remove START app from FORTH init process
39276     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
39277 ;
39278     \
39279
39280
39281 RST_STATE   ;
39282
39283
39284 CODE MAX    \    n1 n2 -- n3       signed maximum
39285             CMP     @PSP,TOS    \ n2-n1
39286             S<      ?GOTO FW1   \ n2<n1
39287 BW1         ADD     #2,PSP
39288             MOV     @IP+,PC
39289 ENDCODE
39290     \
39291
39292 CODE MIN    \    n1 n2 -- n3       signed minimum
39293             CMP     @PSP,TOS     \ n2-n1
39294             S<      ?GOTO BW1    \ n2<n1
39295 FW1         MOV     @PSP+,TOS
39296             MOV     @IP+,PC
39297 ENDCODE
39298     \
39299
39300 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
39301   >R  <# 0 # #S #>  
39302   R> OVER - 0 MAX SPACES TYPE
39303 ;
39304     \
39305
39306 CODE 20_US                      \ n --      n * 20 us
39307 BEGIN                           \ 3 cycles loop + 6~  
39308 \    MOV     #5,W                \ 3 MCLK = 1 MHz
39309 \    MOV     #23,W               \ 3 MCLK = 4 MHz
39310     MOV     #51,W               \ 3 MCLK = 8 MHz
39311 \    MOV     #104,W              \ 3 MCLK = 16 MHz
39312 \    MOV     #158,W              \ 3 MCLK = 24 MHz
39313     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
39314         SUB #1,W                \ 1
39315     0= UNTIL                    \ 2
39316     SUB     #1,TOS              \ 1
39317 0= UNTIL                        \ 2
39318     MOV     @PSP+,TOS           \ 2
39319     MOV     @IP+,PC             \ 4
39320 ENDCODE
39321     \
39322
39323 CODE TOP_LCD                    \ LCD Sample
39324 \                               \ if write : %xxxxWWWW --
39325 \                               \ if read  : -- %0000RRRR
39326     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
39327     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
39328 0= IF                           \ write LCD bits pattern
39329     AND.B #LCD_DB,TOS           \ 
39330     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
39331     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
39332     MOV @PSP+,TOS               \
39333     MOV @IP+,PC
39334 THEN                            \ read LCD bits pattern
39335     SUB #2,PSP
39336     MOV TOS,0(PSP)
39337     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
39338     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
39339     AND.B #LCD_DB,TOS           \
39340     MOV @IP+,PC
39341 ENDCODE
39342     \
39343
39344 CODE LCD_W                      \ byte --       write byte to LCD 
39345     SUB #2,PSP                  \
39346     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
39347     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
39348     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
39349     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
39350 COLON                           \ high level word starts here 
39351     TOP_LCD 2 20_US             \ write high nibble first
39352     TOP_LCD 2 20_US 
39353 ;
39354     \
39355
39356 CODE LCD_WrC                    \ char --         Write Char
39357     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
39358     JMP LCD_W 
39359 ENDCODE
39360     \
39361
39362 CODE LCD_WrF                    \ func --         Write Fonction
39363     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
39364     JMP LCD_W 
39365 ENDCODE
39366     \
39367
39368 : LCD_Clear 
39369     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
39370 ;
39371     \
39372
39373 : LCD_Home 
39374     $02 LCD_WrF 100 20_us 
39375 ;
39376     \
39377
39378 \ : LCD_Entry_set       $04 OR LCD_WrF ;
39379
39380 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
39381
39382 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
39383
39384 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
39385
39386 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
39387
39388 \ : LCD_Goto            $80 OR LCD_WrF ;
39389
39390 \ CODE LCD_R                      \ -- byte       read byte from LCD
39391 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
39392 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
39393 \ COLON                           \ starts a FORTH word
39394 \     TOP_LCD 2 20_us             \ -- %0000HHHH
39395 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
39396 \ HI2LO                           \ switch from FORTH to assembler
39397 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
39398 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
39399 \     MOV @RSP+,IP                \ restore IP saved by COLON
39400 \     MOV @IP+,PC                 \
39401 \ ENDCODE
39402 \     \
39403
39404 \ CODE LCD_RdS                    \ -- status       Read Status
39405 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
39406 \     JMP LCD_R
39407 \ ENDCODE
39408 \     \
39409
39410 \ CODE LCD_RdC                    \ -- char         Read Char
39411 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
39412 \     JMP LCD_R
39413 \ ENDCODE
39414 \     \
39415
39416 \ -------------+------+------+------+------++---+---+---+---+---------+
39417 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
39418 \ -------------+------+------+------+------++---+---+---+---+---------+
39419 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
39420 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
39421 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
39422 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
39423 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
39424 \ -------------+------+------+------+------++---+---+---+---+---------+
39425
39426
39427 \ ******************************\
39428 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
39429 \ ******************************\
39430 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
39431 \ ------------------------------\
39432 \ define LPM mode for ACCEPT    \
39433 \ ------------------------------\
39434 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
39435 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
39436 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
39437 BIT.B #SW2,&SW2_IN              \ test switch S2
39438 0= IF                           \ case of switch S2 pressed
39439     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
39440     U< IF
39441         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
39442     THEN
39443 ELSE
39444     BIT.B #SW1,&SW1_IN          \ test switch S1 input
39445     0= IF                       \ case of Switch S1 pressed
39446         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
39447         U>= IF                  \
39448             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
39449         THEN                    \
39450     THEN                        \
39451 THEN                            \
39452 RETI                            \ CPU is ON, GIE is OFF
39453 ENDASM                          \
39454     \
39455
39456
39457 \ ------------------------------\
39458 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
39459 \ ******************************\
39460 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
39461 \ ******************************\
39462 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
39463 \                               \       SMclock = 8|16|24 MHz
39464 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
39465 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
39466 \                               \       SR(9)=new Toggle bit memory (ADD on)
39467 \ ------------------------------\
39468 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
39469 \ ------------------------------\
39470 \ define LPM mode for ACCEPT    \
39471 \ ------------------------------\
39472 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
39473 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
39474 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
39475 \ ------------------------------\
39476 \ RC5_FirstStartBitHalfCycle:   \
39477 \ ------------------------------\
39478 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
39479 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
39480 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
39481 MOV     #1778,X                 \ RC5_Period in us
39482 MOV     #14,W                   \ count of loop
39483 BEGIN                           \
39484 \ ------------------------------\
39485 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
39486 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
39487     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
39488 \ RC5_Compute_3/4_Period:       \                   |
39489     RRUM    #1,X                \ X=1/2 cycle       |
39490     MOV     X,Y                 \ Y=1/2             ^
39491     RRUM    #1,Y                \ Y=1/4
39492     ADD     X,Y                 \ Y=3/4
39493 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
39494     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
39495     0= UNTIL                    \
39496 \ ------------------------------\
39497 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
39498 \ ------------------------------\
39499     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
39500     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
39501     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
39502     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
39503     SUB     #1,W                \ decrement count loop
39504 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
39505 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
39506 0<> WHILE                       \ ----> out of loop ----+
39507 \ RC5_compute_7/4_Time_out:     \                       |
39508     ADD     X,Y                 \                       |   out of bound = 7/4 period 
39509 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
39510     BEGIN                       \                       |
39511         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
39512         0>= IF                  \                       |   if cycle time out of bound
39513             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
39514             RETI                \                       |   then quit to do nothing
39515         THEN                    \                       |
39516 \ ------------------------------\                       |
39517         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
39518     0<> UNTIL                   \                   |   |
39519     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
39520 REPEAT                          \ ----> loop back --+   |
39521 \ ------------------------------\                       |
39522 \ RC5_SampleEndOf:              \ <---------------------+
39523 \ ------------------------------\
39524 BIC     #$30,&TA0CTL           \ stop timer_A0
39525 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
39526 \ ******************************\
39527 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
39528 \ ******************************\
39529 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
39530 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
39531 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
39532 BIT     #BIT13,X                \ X(13) = New_RC5_command
39533 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
39534 THEN                            \
39535 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
39536 \ ******************************\
39537 \ RC5_ComputeNewRC5word         \
39538 \ ******************************\
39539 SUB     #4,PSP                  \
39540 MOV     &BASE,2(PSP)            \ save variable BASE before use
39541 MOV     TOS,0(PSP)              \ save TOS before use
39542 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
39543 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
39544 \ ******************************\
39545 \ RC5_ComputeC6bit              \
39546 \ ******************************\
39547 BIT     #$4000,IP              \ test /C6 bit in IP
39548 0= IF   BIS #$40,TOS           \ set C6 bit in S
39549 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
39550 \ ******************************\
39551 \ RC5_CommandByteIsDone         \ RC5_code --
39552 \ ******************************\
39553
39554 \ ------------------------------\
39555 \ Display IR_RC5 code           \
39556 \ ------------------------------\
39557 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
39558 \ ------------------------------\
39559 LO2HI                           \ switch from assembler to FORTH
39560     ['] LCD_CLEAR IS CR         \ redirects CR
39561     ['] LCD_WrC  IS EMIT        \ redirects EMIT
39562     $10 BASE !                 \ change BASE to hexadecimal
39563     CR ." $" 2 U.R             \ print IR_RC5 code
39564     ['] (CR) IS CR              \ restore CR
39565     ['] (EMIT) IS EMIT          \ restore EMIT
39566 HI2LO                           \ switch from FORTH to assembler
39567 \ ------------------------------\
39568 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
39569 \ ------------------------------\
39570 MOV @PSP+,&BASE                 \ restore variable BASE
39571 RETI                            \ CPU is ON, GIE is OFF
39572 ENDASM                          \
39573     \ 
39574
39575 CODE START                      \
39576 \ ------------------------------\
39577 \ TB0CTL = %0000 0010 1001 0100\$3C0
39578 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
39579 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
39580 \                      --       \ID input divider \ 10 = /4
39581 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
39582 \                            -  \TBCLR TimerB Clear
39583 \                             - \TBIE
39584 \                              -\TBIFG
39585 \ --------------------------------\\
39586 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
39587 \              --                 \CM Capture Mode
39588 \                --               \CCIS
39589 \                   -             \SCS
39590 \                    --           \CLLD
39591 \                      -          \CAP
39592 \                        ---      \OUTMOD \ 011 = set/reset
39593 \                           -     \CCIE
39594 \                             -   \CCI
39595 \                              -  \OUT
39596 \                               - \COV
39597 \                                -\CCIFG
39598 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
39599 \ TB0EX0                          \$3E0 
39600 \ ------------------------------\
39601 \ set TimerB to make 50kHz PWM  \
39602 \ ------------------------------\
39603 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
39604 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
39605 \ ------------------------------\
39606 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
39607 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
39608 \ ------------------------------\
39609     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
39610     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
39611 \ ------------------------------\
39612 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
39613 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
39614 \ ------------------------------\
39615 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
39616 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
39617 \ ------------------------------\
39618     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
39619 \ ------------------------------\
39620 \ set TimerB to generate PWM for LCD_Vo
39621 \ ------------------------------\
39622     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
39623 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
39624     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
39625 \ ------------------------------\
39626     BIS.B #LCDVo,&LCDVo_DIR     \
39627     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
39628 \ ------------------------------\
39629     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
39630     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
39631 \ ------------------------------\
39632     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
39633     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
39634 \ ------------------------------\
39635 \ WDT interval init part        \
39636 \ ------------------------------\
39637     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
39638 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
39639 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
39640     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
39641 \ ------------------------------\
39642 \ init RC5_Int                  \
39643 \ ------------------------------\
39644     BIS.B #RC5,&IR_IE           \ enable RC5_Int
39645     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
39646 \ ------------------------------\
39647 \ init interrupt vectors
39648 \ ------------------------------\
39649     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
39650     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
39651 \ ------------------------------\
39652 \ define LPM mode for ACCEPT    \
39653 \ ------------------------------\
39654 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
39655 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
39656 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
39657
39658 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
39659
39660 \ ------------------------------\
39661 \ Init LCD 2x20                 \
39662 \ ------------------------------\
39663     $03E8 20_US                \ 1-  wait 20 ms
39664     $03 TOP_LCD                \ 2- send DB5=DB4=1
39665     $CD 20_US                  \ 3- wait 4,1 ms
39666     $03 TOP_LCD                \ 4- send again DB5=DB4=1
39667     $5 20_US                   \ 5- wait 0,1 ms
39668     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
39669     $2 20_US                   \    wait 40 us = LCD cycle
39670     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
39671     $2 20_US                   \    wait 40 us = LCD cycle
39672     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
39673     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
39674     LCD_Clear                   \ 10- "LCD_Clear"
39675     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
39676     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
39677     LCD_Clear                   \ 10- "LCD_Clear"
39678     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
39679     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
39680     CR ." I love you"   
39681     ['] (CR) IS CR              \ ' (CR) is CR
39682     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
39683     CR
39684     ."    RC5toLCD is running. Type STOP to quit"
39685 \    NOECHO                      \ uncomment to run this app without terminal connexion
39686     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
39687     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
39688 ;
39689     \
39690
39691 : STOP                  \ stops multitasking, must to be used before downloading app
39692     ['] (WARM) IS WARM  \ remove START app from FORTH init process
39693     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
39694 ;
39695     \
39696
39697
39698 RST_STATE   ;
39699
39700
39701 CODE MAX    \    n1 n2 -- n3       signed maximum
39702             CMP     @PSP,TOS    \ n2-n1
39703             S<      ?GOTO FW1   \ n2<n1
39704 BW1         ADD     #2,PSP
39705             MOV     @IP+,PC
39706 ENDCODE
39707     \
39708
39709 CODE MIN    \    n1 n2 -- n3       signed minimum
39710             CMP     @PSP,TOS     \ n2-n1
39711             S<      ?GOTO BW1    \ n2<n1
39712 FW1         MOV     @PSP+,TOS
39713             MOV     @IP+,PC
39714 ENDCODE
39715     \
39716
39717 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
39718   >R  <# 0 # #S #>  
39719   R> OVER - 0 MAX SPACES TYPE
39720 ;
39721     \
39722
39723 CODE 20_US                      \ n --      n * 20 us
39724 BEGIN                           \ 3 cycles loop + 6~  
39725 \    MOV     #5,W                \ 3 MCLK = 1 MHz
39726 \    MOV     #23,W               \ 3 MCLK = 4 MHz
39727     MOV     #51,W               \ 3 MCLK = 8 MHz
39728 \    MOV     #104,W              \ 3 MCLK = 16 MHz
39729 \    MOV     #158,W              \ 3 MCLK = 24 MHz
39730     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
39731         SUB #1,W                \ 1
39732     0= UNTIL                    \ 2
39733     SUB     #1,TOS              \ 1
39734 0= UNTIL                        \ 2
39735     MOV     @PSP+,TOS           \ 2
39736     MOV     @IP+,PC             \ 4
39737 ENDCODE
39738     \
39739
39740 CODE TOP_LCD                    \ LCD Sample
39741 \                               \ if write : %xxxxWWWW --
39742 \                               \ if read  : -- %0000RRRR
39743     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
39744     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
39745 0= IF                           \ write LCD bits pattern
39746     AND.B #LCD_DB,TOS           \ 
39747     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
39748     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
39749     MOV @PSP+,TOS               \
39750     MOV @IP+,PC
39751 THEN                            \ read LCD bits pattern
39752     SUB #2,PSP
39753     MOV TOS,0(PSP)
39754     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
39755     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
39756     AND.B #LCD_DB,TOS           \
39757     MOV @IP+,PC
39758 ENDCODE
39759     \
39760
39761 CODE LCD_W                      \ byte --       write byte to LCD 
39762     SUB #2,PSP                  \
39763     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
39764     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
39765     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
39766     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
39767 COLON                           \ high level word starts here 
39768     TOP_LCD 2 20_US             \ write high nibble first
39769     TOP_LCD 2 20_US 
39770 ;
39771     \
39772
39773 CODE LCD_WrC                    \ char --         Write Char
39774     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
39775     JMP LCD_W 
39776 ENDCODE
39777     \
39778
39779 CODE LCD_WrF                    \ func --         Write Fonction
39780     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
39781     JMP LCD_W 
39782 ENDCODE
39783     \
39784
39785 : LCD_Clear 
39786     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
39787 ;
39788     \
39789
39790 : LCD_Home 
39791     $02 LCD_WrF 100 20_us 
39792 ;
39793     \
39794
39795 \ : LCD_Entry_set       $04 OR LCD_WrF ;
39796
39797 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
39798
39799 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
39800
39801 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
39802
39803 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
39804
39805 \ : LCD_Goto            $80 OR LCD_WrF ;
39806
39807 \ CODE LCD_R                      \ -- byte       read byte from LCD
39808 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
39809 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
39810 \ COLON                           \ starts a FORTH word
39811 \     TOP_LCD 2 20_us             \ -- %0000HHHH
39812 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
39813 \ HI2LO                           \ switch from FORTH to assembler
39814 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
39815 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
39816 \     MOV @RSP+,IP                \ restore IP saved by COLON
39817 \     MOV @IP+,PC                 \
39818 \ ENDCODE
39819 \     \
39820
39821 \ CODE LCD_RdS                    \ -- status       Read Status
39822 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
39823 \     JMP LCD_R
39824 \ ENDCODE
39825 \     \
39826
39827 \ CODE LCD_RdC                    \ -- char         Read Char
39828 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
39829 \     JMP LCD_R
39830 \ ENDCODE
39831 \     \
39832
39833 \ -------------+------+------+------+------++---+---+---+---+---------+
39834 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
39835 \ -------------+------+------+------+------++---+---+---+---+---------+
39836 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
39837 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
39838 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
39839 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
39840 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
39841 \ -------------+------+------+------+------++---+---+---+---+---------+
39842
39843
39844 \ ******************************\
39845 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
39846 \ ******************************\
39847 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
39848 \ ------------------------------\
39849 \ define LPM mode for ACCEPT    \
39850 \ ------------------------------\
39851 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
39852 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
39853 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
39854 BIT.B #SW2,&SW2_IN              \ test switch S2
39855 0= IF                           \ case of switch S2 pressed
39856     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
39857     U< IF
39858         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
39859     THEN
39860 ELSE
39861     BIT.B #SW1,&SW1_IN          \ test switch S1 input
39862     0= IF                       \ case of Switch S1 pressed
39863         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
39864         U>= IF                  \
39865             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
39866         THEN                    \
39867     THEN                        \
39868 THEN                            \
39869 RETI                            \ CPU is ON, GIE is OFF
39870 ENDASM                          \
39871     \
39872
39873
39874 \ ------------------------------\
39875 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
39876 \ ******************************\
39877 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
39878 \ ******************************\
39879 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
39880 \                               \       SMclock = 8|16|24 MHz
39881 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
39882 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
39883 \                               \       SR(9)=new Toggle bit memory (ADD on)
39884 \ ------------------------------\
39885 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
39886 \ ------------------------------\
39887 \ define LPM mode for ACCEPT    \
39888 \ ------------------------------\
39889 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
39890 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
39891 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
39892 \ ------------------------------\
39893 \ RC5_FirstStartBitHalfCycle:   \
39894 \ ------------------------------\
39895 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
39896 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
39897 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
39898 MOV     #1778,X                 \ RC5_Period in us
39899 MOV     #14,W                   \ count of loop
39900 BEGIN                           \
39901 \ ------------------------------\
39902 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
39903 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
39904     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
39905 \ RC5_Compute_3/4_Period:       \                   |
39906     RRUM    #1,X                \ X=1/2 cycle       |
39907     MOV     X,Y                 \ Y=1/2             ^
39908     RRUM    #1,Y                \ Y=1/4
39909     ADD     X,Y                 \ Y=3/4
39910 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
39911     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
39912     0= UNTIL                    \
39913 \ ------------------------------\
39914 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
39915 \ ------------------------------\
39916     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
39917     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
39918     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
39919     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
39920     SUB     #1,W                \ decrement count loop
39921 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
39922 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
39923 0<> WHILE                       \ ----> out of loop ----+
39924 \ RC5_compute_7/4_Time_out:     \                       |
39925     ADD     X,Y                 \                       |   out of bound = 7/4 period 
39926 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
39927     BEGIN                       \                       |
39928         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
39929         0>= IF                  \                       |   if cycle time out of bound
39930             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
39931             RETI                \                       |   then quit to do nothing
39932         THEN                    \                       |
39933 \ ------------------------------\                       |
39934         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
39935     0<> UNTIL                   \                   |   |
39936     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
39937 REPEAT                          \ ----> loop back --+   |
39938 \ ------------------------------\                       |
39939 \ RC5_SampleEndOf:              \ <---------------------+
39940 \ ------------------------------\
39941 BIC     #$30,&TA0CTL           \ stop timer_A0
39942 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
39943 \ ******************************\
39944 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
39945 \ ******************************\
39946 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
39947 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
39948 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
39949 BIT     #BIT13,X                \ X(13) = New_RC5_command
39950 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
39951 THEN                            \
39952 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
39953 \ ******************************\
39954 \ RC5_ComputeNewRC5word         \
39955 \ ******************************\
39956 SUB     #4,PSP                  \
39957 MOV     &BASE,2(PSP)            \ save variable BASE before use
39958 MOV     TOS,0(PSP)              \ save TOS before use
39959 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
39960 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
39961 \ ******************************\
39962 \ RC5_ComputeC6bit              \
39963 \ ******************************\
39964 BIT     #$4000,IP              \ test /C6 bit in IP
39965 0= IF   BIS #$40,TOS           \ set C6 bit in S
39966 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
39967 \ ******************************\
39968 \ RC5_CommandByteIsDone         \ RC5_code --
39969 \ ******************************\
39970
39971 \ ------------------------------\
39972 \ Display IR_RC5 code           \
39973 \ ------------------------------\
39974 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
39975 \ ------------------------------\
39976 LO2HI                           \ switch from assembler to FORTH
39977     ['] LCD_CLEAR IS CR         \ redirects CR
39978     ['] LCD_WrC  IS EMIT        \ redirects EMIT
39979     $10 BASE !                 \ change BASE to hexadecimal
39980     CR ." $" 2 U.R             \ print IR_RC5 code
39981     ['] (CR) IS CR              \ restore CR
39982     ['] (EMIT) IS EMIT          \ restore EMIT
39983 HI2LO                           \ switch from FORTH to assembler
39984 \ ------------------------------\
39985 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
39986 \ ------------------------------\
39987 MOV @PSP+,&BASE                 \ restore variable BASE
39988 RETI                            \ CPU is ON, GIE is OFF
39989 ENDASM                          \
39990     \ 
39991
39992 CODE START                      \
39993 \ ------------------------------\
39994 \ TB0CTL = %0000 0010 1001 0100\$3C0
39995 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
39996 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
39997 \                      --       \ID input divider \ 10 = /4
39998 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
39999 \                            -  \TBCLR TimerB Clear
40000 \                             - \TBIE
40001 \                              -\TBIFG
40002 \ --------------------------------\\
40003 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
40004 \              --                 \CM Capture Mode
40005 \                --               \CCIS
40006 \                   -             \SCS
40007 \                    --           \CLLD
40008 \                      -          \CAP
40009 \                        ---      \OUTMOD \ 011 = set/reset
40010 \                           -     \CCIE
40011 \                             -   \CCI
40012 \                              -  \OUT
40013 \                               - \COV
40014 \                                -\CCIFG
40015 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
40016 \ TB0EX0                          \$3E0 
40017 \ ------------------------------\
40018 \ set TimerB to make 50kHz PWM  \
40019 \ ------------------------------\
40020 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
40021 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
40022 \ ------------------------------\
40023 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
40024 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
40025 \ ------------------------------\
40026     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
40027     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
40028 \ ------------------------------\
40029 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
40030 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
40031 \ ------------------------------\
40032 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
40033 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
40034 \ ------------------------------\
40035     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
40036 \ ------------------------------\
40037 \ set TimerB to generate PWM for LCD_Vo
40038 \ ------------------------------\
40039     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
40040 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
40041     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
40042 \ ------------------------------\
40043     BIS.B #LCDVo,&LCDVo_DIR     \
40044     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
40045 \ ------------------------------\
40046     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
40047     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
40048 \ ------------------------------\
40049     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
40050     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
40051 \ ------------------------------\
40052 \ WDT interval init part        \
40053 \ ------------------------------\
40054     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
40055 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
40056 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
40057     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
40058 \ ------------------------------\
40059 \ init RC5_Int                  \
40060 \ ------------------------------\
40061     BIS.B #RC5,&IR_IE           \ enable RC5_Int
40062     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
40063 \ ------------------------------\
40064 \ init interrupt vectors
40065 \ ------------------------------\
40066     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
40067     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
40068 \ ------------------------------\
40069 \ define LPM mode for ACCEPT    \
40070 \ ------------------------------\
40071 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
40072 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
40073 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
40074
40075 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
40076
40077 \ ------------------------------\
40078 \ Init LCD 2x20                 \
40079 \ ------------------------------\
40080     $03E8 20_US                \ 1-  wait 20 ms
40081     $03 TOP_LCD                \ 2- send DB5=DB4=1
40082     $CD 20_US                  \ 3- wait 4,1 ms
40083     $03 TOP_LCD                \ 4- send again DB5=DB4=1
40084     $5 20_US                   \ 5- wait 0,1 ms
40085     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
40086     $2 20_US                   \    wait 40 us = LCD cycle
40087     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
40088     $2 20_US                   \    wait 40 us = LCD cycle
40089     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
40090     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
40091     LCD_Clear                   \ 10- "LCD_Clear"
40092     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
40093     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
40094     LCD_Clear                   \ 10- "LCD_Clear"
40095     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
40096     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
40097     CR ." I love you"   
40098     ['] (CR) IS CR              \ ' (CR) is CR
40099     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
40100     CR
40101     ."    RC5toLCD is running. Type STOP to quit"
40102 \    NOECHO                      \ uncomment to run this app without terminal connexion
40103     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
40104     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
40105 ;
40106     \
40107
40108 : STOP                  \ stops multitasking, must to be used before downloading app
40109     ['] (WARM) IS WARM  \ remove START app from FORTH init process
40110     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
40111 ;
40112     \
40113
40114
40115 RST_STATE   ;
40116
40117
40118 CODE MAX    \    n1 n2 -- n3       signed maximum
40119             CMP     @PSP,TOS    \ n2-n1
40120             S<      ?GOTO FW1   \ n2<n1
40121 BW1         ADD     #2,PSP
40122             MOV     @IP+,PC
40123 ENDCODE
40124     \
40125
40126 CODE MIN    \    n1 n2 -- n3       signed minimum
40127             CMP     @PSP,TOS     \ n2-n1
40128             S<      ?GOTO BW1    \ n2<n1
40129 FW1         MOV     @PSP+,TOS
40130             MOV     @IP+,PC
40131 ENDCODE
40132     \
40133
40134 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
40135   >R  <# 0 # #S #>  
40136   R> OVER - 0 MAX SPACES TYPE
40137 ;
40138     \
40139
40140 CODE 20_US                      \ n --      n * 20 us
40141 BEGIN                           \ 3 cycles loop + 6~  
40142 \    MOV     #5,W                \ 3 MCLK = 1 MHz
40143 \    MOV     #23,W               \ 3 MCLK = 4 MHz
40144     MOV     #51,W               \ 3 MCLK = 8 MHz
40145 \    MOV     #104,W              \ 3 MCLK = 16 MHz
40146 \    MOV     #158,W              \ 3 MCLK = 24 MHz
40147     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
40148         SUB #1,W                \ 1
40149     0= UNTIL                    \ 2
40150     SUB     #1,TOS              \ 1
40151 0= UNTIL                        \ 2
40152     MOV     @PSP+,TOS           \ 2
40153     MOV     @IP+,PC             \ 4
40154 ENDCODE
40155     \
40156
40157 CODE TOP_LCD                    \ LCD Sample
40158 \                               \ if write : %xxxxWWWW --
40159 \                               \ if read  : -- %0000RRRR
40160     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
40161     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
40162 0= IF                           \ write LCD bits pattern
40163     AND.B #LCD_DB,TOS           \ 
40164     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
40165     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
40166     MOV @PSP+,TOS               \
40167     MOV @IP+,PC
40168 THEN                            \ read LCD bits pattern
40169     SUB #2,PSP
40170     MOV TOS,0(PSP)
40171     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
40172     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
40173     AND.B #LCD_DB,TOS           \
40174     MOV @IP+,PC
40175 ENDCODE
40176     \
40177
40178 CODE LCD_W                      \ byte --       write byte to LCD 
40179     SUB #2,PSP                  \
40180     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
40181     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
40182     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
40183     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
40184 COLON                           \ high level word starts here 
40185     TOP_LCD 2 20_US             \ write high nibble first
40186     TOP_LCD 2 20_US 
40187 ;
40188     \
40189
40190 CODE LCD_WrC                    \ char --         Write Char
40191     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
40192     JMP LCD_W 
40193 ENDCODE
40194     \
40195
40196 CODE LCD_WrF                    \ func --         Write Fonction
40197     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
40198     JMP LCD_W 
40199 ENDCODE
40200     \
40201
40202 : LCD_Clear 
40203     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
40204 ;
40205     \
40206
40207 : LCD_Home 
40208     $02 LCD_WrF 100 20_us 
40209 ;
40210     \
40211
40212 \ : LCD_Entry_set       $04 OR LCD_WrF ;
40213
40214 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
40215
40216 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
40217
40218 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
40219
40220 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
40221
40222 \ : LCD_Goto            $80 OR LCD_WrF ;
40223
40224 \ CODE LCD_R                      \ -- byte       read byte from LCD
40225 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
40226 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
40227 \ COLON                           \ starts a FORTH word
40228 \     TOP_LCD 2 20_us             \ -- %0000HHHH
40229 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
40230 \ HI2LO                           \ switch from FORTH to assembler
40231 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
40232 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
40233 \     MOV @RSP+,IP                \ restore IP saved by COLON
40234 \     MOV @IP+,PC                 \
40235 \ ENDCODE
40236 \     \
40237
40238 \ CODE LCD_RdS                    \ -- status       Read Status
40239 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
40240 \     JMP LCD_R
40241 \ ENDCODE
40242 \     \
40243
40244 \ CODE LCD_RdC                    \ -- char         Read Char
40245 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
40246 \     JMP LCD_R
40247 \ ENDCODE
40248 \     \
40249
40250 \ -------------+------+------+------+------++---+---+---+---+---------+
40251 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
40252 \ -------------+------+------+------+------++---+---+---+---+---------+
40253 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
40254 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
40255 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
40256 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
40257 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
40258 \ -------------+------+------+------+------++---+---+---+---+---------+
40259
40260
40261 \ ******************************\
40262 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
40263 \ ******************************\
40264 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
40265 \ ------------------------------\
40266 \ define LPM mode for ACCEPT    \
40267 \ ------------------------------\
40268 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
40269 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
40270 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
40271 BIT.B #SW2,&SW2_IN              \ test switch S2
40272 0= IF                           \ case of switch S2 pressed
40273     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
40274     U< IF
40275         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
40276     THEN
40277 ELSE
40278     BIT.B #SW1,&SW1_IN          \ test switch S1 input
40279     0= IF                       \ case of Switch S1 pressed
40280         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
40281         U>= IF                  \
40282             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
40283         THEN                    \
40284     THEN                        \
40285 THEN                            \
40286 RETI                            \ CPU is ON, GIE is OFF
40287 ENDASM                          \
40288     \
40289
40290
40291 \ ------------------------------\
40292 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
40293 \ ******************************\
40294 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
40295 \ ******************************\
40296 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
40297 \                               \       SMclock = 8|16|24 MHz
40298 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
40299 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
40300 \                               \       SR(9)=new Toggle bit memory (ADD on)
40301 \ ------------------------------\
40302 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
40303 \ ------------------------------\
40304 \ define LPM mode for ACCEPT    \
40305 \ ------------------------------\
40306 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
40307 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
40308 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
40309 \ ------------------------------\
40310 \ RC5_FirstStartBitHalfCycle:   \
40311 \ ------------------------------\
40312 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
40313 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
40314 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
40315 MOV     #1778,X                 \ RC5_Period in us
40316 MOV     #14,W                   \ count of loop
40317 BEGIN                           \
40318 \ ------------------------------\
40319 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
40320 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
40321     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
40322 \ RC5_Compute_3/4_Period:       \                   |
40323     RRUM    #1,X                \ X=1/2 cycle       |
40324     MOV     X,Y                 \ Y=1/2             ^
40325     RRUM    #1,Y                \ Y=1/4
40326     ADD     X,Y                 \ Y=3/4
40327 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
40328     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
40329     0= UNTIL                    \
40330 \ ------------------------------\
40331 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
40332 \ ------------------------------\
40333     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
40334     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
40335     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
40336     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
40337     SUB     #1,W                \ decrement count loop
40338 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
40339 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
40340 0<> WHILE                       \ ----> out of loop ----+
40341 \ RC5_compute_7/4_Time_out:     \                       |
40342     ADD     X,Y                 \                       |   out of bound = 7/4 period 
40343 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
40344     BEGIN                       \                       |
40345         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
40346         0>= IF                  \                       |   if cycle time out of bound
40347             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
40348             RETI                \                       |   then quit to do nothing
40349         THEN                    \                       |
40350 \ ------------------------------\                       |
40351         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
40352     0<> UNTIL                   \                   |   |
40353     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
40354 REPEAT                          \ ----> loop back --+   |
40355 \ ------------------------------\                       |
40356 \ RC5_SampleEndOf:              \ <---------------------+
40357 \ ------------------------------\
40358 BIC     #$30,&TA0CTL           \ stop timer_A0
40359 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
40360 \ ******************************\
40361 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
40362 \ ******************************\
40363 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
40364 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
40365 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
40366 BIT     #BIT13,X                \ X(13) = New_RC5_command
40367 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
40368 THEN                            \
40369 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
40370 \ ******************************\
40371 \ RC5_ComputeNewRC5word         \
40372 \ ******************************\
40373 SUB     #4,PSP                  \
40374 MOV     &BASE,2(PSP)            \ save variable BASE before use
40375 MOV     TOS,0(PSP)              \ save TOS before use
40376 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
40377 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
40378 \ ******************************\
40379 \ RC5_ComputeC6bit              \
40380 \ ******************************\
40381 BIT     #$4000,IP              \ test /C6 bit in IP
40382 0= IF   BIS #$40,TOS           \ set C6 bit in S
40383 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
40384 \ ******************************\
40385 \ RC5_CommandByteIsDone         \ RC5_code --
40386 \ ******************************\
40387
40388 \ ------------------------------\
40389 \ Display IR_RC5 code           \
40390 \ ------------------------------\
40391 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
40392 \ ------------------------------\
40393 LO2HI                           \ switch from assembler to FORTH
40394     ['] LCD_CLEAR IS CR         \ redirects CR
40395     ['] LCD_WrC  IS EMIT        \ redirects EMIT
40396     $10 BASE !                 \ change BASE to hexadecimal
40397     CR ." $" 2 U.R             \ print IR_RC5 code
40398     ['] (CR) IS CR              \ restore CR
40399     ['] (EMIT) IS EMIT          \ restore EMIT
40400 HI2LO                           \ switch from FORTH to assembler
40401 \ ------------------------------\
40402 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
40403 \ ------------------------------\
40404 MOV @PSP+,&BASE                 \ restore variable BASE
40405 RETI                            \ CPU is ON, GIE is OFF
40406 ENDASM                          \
40407     \ 
40408
40409 CODE START                      \
40410 \ ------------------------------\
40411 \ TB0CTL = %0000 0010 1001 0100\$3C0
40412 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
40413 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
40414 \                      --       \ID input divider \ 10 = /4
40415 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
40416 \                            -  \TBCLR TimerB Clear
40417 \                             - \TBIE
40418 \                              -\TBIFG
40419 \ --------------------------------\\
40420 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
40421 \              --                 \CM Capture Mode
40422 \                --               \CCIS
40423 \                   -             \SCS
40424 \                    --           \CLLD
40425 \                      -          \CAP
40426 \                        ---      \OUTMOD \ 011 = set/reset
40427 \                           -     \CCIE
40428 \                             -   \CCI
40429 \                              -  \OUT
40430 \                               - \COV
40431 \                                -\CCIFG
40432 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
40433 \ TB0EX0                          \$3E0 
40434 \ ------------------------------\
40435 \ set TimerB to make 50kHz PWM  \
40436 \ ------------------------------\
40437 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
40438 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
40439 \ ------------------------------\
40440 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
40441 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
40442 \ ------------------------------\
40443     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
40444     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
40445 \ ------------------------------\
40446 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
40447 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
40448 \ ------------------------------\
40449 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
40450 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
40451 \ ------------------------------\
40452     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
40453 \ ------------------------------\
40454 \ set TimerB to generate PWM for LCD_Vo
40455 \ ------------------------------\
40456     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
40457 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
40458     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
40459 \ ------------------------------\
40460     BIS.B #LCDVo,&LCDVo_DIR     \
40461     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
40462 \ ------------------------------\
40463     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
40464     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
40465 \ ------------------------------\
40466     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
40467     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
40468 \ ------------------------------\
40469 \ WDT interval init part        \
40470 \ ------------------------------\
40471     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
40472 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
40473 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
40474     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
40475 \ ------------------------------\
40476 \ init RC5_Int                  \
40477 \ ------------------------------\
40478     BIS.B #RC5,&IR_IE           \ enable RC5_Int
40479     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
40480 \ ------------------------------\
40481 \ init interrupt vectors
40482 \ ------------------------------\
40483     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
40484     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
40485 \ ------------------------------\
40486 \ define LPM mode for ACCEPT    \
40487 \ ------------------------------\
40488 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
40489 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
40490 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
40491
40492 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
40493
40494 \ ------------------------------\
40495 \ Init LCD 2x20                 \
40496 \ ------------------------------\
40497     $03E8 20_US                \ 1-  wait 20 ms
40498     $03 TOP_LCD                \ 2- send DB5=DB4=1
40499     $CD 20_US                  \ 3- wait 4,1 ms
40500     $03 TOP_LCD                \ 4- send again DB5=DB4=1
40501     $5 20_US                   \ 5- wait 0,1 ms
40502     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
40503     $2 20_US                   \    wait 40 us = LCD cycle
40504     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
40505     $2 20_US                   \    wait 40 us = LCD cycle
40506     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
40507     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
40508     LCD_Clear                   \ 10- "LCD_Clear"
40509     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
40510     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
40511     LCD_Clear                   \ 10- "LCD_Clear"
40512     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
40513     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
40514     CR ." I love you"   
40515     ['] (CR) IS CR              \ ' (CR) is CR
40516     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
40517     CR
40518     ."    RC5toLCD is running. Type STOP to quit"
40519 \    NOECHO                      \ uncomment to run this app without terminal connexion
40520     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
40521     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
40522 ;
40523     \
40524
40525 : STOP                  \ stops multitasking, must to be used before downloading app
40526     ['] (WARM) IS WARM  \ remove START app from FORTH init process
40527     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
40528 ;
40529     \
40530
40531
40532 RST_STATE   ;
40533
40534
40535 CODE MAX    \    n1 n2 -- n3       signed maximum
40536             CMP     @PSP,TOS    \ n2-n1
40537             S<      ?GOTO FW1   \ n2<n1
40538 BW1         ADD     #2,PSP
40539             MOV     @IP+,PC
40540 ENDCODE
40541     \
40542
40543 CODE MIN    \    n1 n2 -- n3       signed minimum
40544             CMP     @PSP,TOS     \ n2-n1
40545             S<      ?GOTO BW1    \ n2<n1
40546 FW1         MOV     @PSP+,TOS
40547             MOV     @IP+,PC
40548 ENDCODE
40549     \
40550
40551 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
40552   >R  <# 0 # #S #>  
40553   R> OVER - 0 MAX SPACES TYPE
40554 ;
40555     \
40556
40557 CODE 20_US                      \ n --      n * 20 us
40558 BEGIN                           \ 3 cycles loop + 6~  
40559 \    MOV     #5,W                \ 3 MCLK = 1 MHz
40560 \    MOV     #23,W               \ 3 MCLK = 4 MHz
40561     MOV     #51,W               \ 3 MCLK = 8 MHz
40562 \    MOV     #104,W              \ 3 MCLK = 16 MHz
40563 \    MOV     #158,W              \ 3 MCLK = 24 MHz
40564     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
40565         SUB #1,W                \ 1
40566     0= UNTIL                    \ 2
40567     SUB     #1,TOS              \ 1
40568 0= UNTIL                        \ 2
40569     MOV     @PSP+,TOS           \ 2
40570     MOV     @IP+,PC             \ 4
40571 ENDCODE
40572     \
40573
40574 CODE TOP_LCD                    \ LCD Sample
40575 \                               \ if write : %xxxxWWWW --
40576 \                               \ if read  : -- %0000RRRR
40577     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
40578     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
40579 0= IF                           \ write LCD bits pattern
40580     AND.B #LCD_DB,TOS           \ 
40581     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
40582     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
40583     MOV @PSP+,TOS               \
40584     MOV @IP+,PC
40585 THEN                            \ read LCD bits pattern
40586     SUB #2,PSP
40587     MOV TOS,0(PSP)
40588     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
40589     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
40590     AND.B #LCD_DB,TOS           \
40591     MOV @IP+,PC
40592 ENDCODE
40593     \
40594
40595 CODE LCD_W                      \ byte --       write byte to LCD 
40596     SUB #2,PSP                  \
40597     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
40598     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
40599     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
40600     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
40601 COLON                           \ high level word starts here 
40602     TOP_LCD 2 20_US             \ write high nibble first
40603     TOP_LCD 2 20_US 
40604 ;
40605     \
40606
40607 CODE LCD_WrC                    \ char --         Write Char
40608     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
40609     JMP LCD_W 
40610 ENDCODE
40611     \
40612
40613 CODE LCD_WrF                    \ func --         Write Fonction
40614     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
40615     JMP LCD_W 
40616 ENDCODE
40617     \
40618
40619 : LCD_Clear 
40620     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
40621 ;
40622     \
40623
40624 : LCD_Home 
40625     $02 LCD_WrF 100 20_us 
40626 ;
40627     \
40628
40629 \ : LCD_Entry_set       $04 OR LCD_WrF ;
40630
40631 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
40632
40633 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
40634
40635 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
40636
40637 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
40638
40639 \ : LCD_Goto            $80 OR LCD_WrF ;
40640
40641 \ CODE LCD_R                      \ -- byte       read byte from LCD
40642 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
40643 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
40644 \ COLON                           \ starts a FORTH word
40645 \     TOP_LCD 2 20_us             \ -- %0000HHHH
40646 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
40647 \ HI2LO                           \ switch from FORTH to assembler
40648 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
40649 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
40650 \     MOV @RSP+,IP                \ restore IP saved by COLON
40651 \     MOV @IP+,PC                 \
40652 \ ENDCODE
40653 \     \
40654
40655 \ CODE LCD_RdS                    \ -- status       Read Status
40656 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
40657 \     JMP LCD_R
40658 \ ENDCODE
40659 \     \
40660
40661 \ CODE LCD_RdC                    \ -- char         Read Char
40662 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
40663 \     JMP LCD_R
40664 \ ENDCODE
40665 \     \
40666
40667 \ -------------+------+------+------+------++---+---+---+---+---------+
40668 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
40669 \ -------------+------+------+------+------++---+---+---+---+---------+
40670 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
40671 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
40672 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
40673 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
40674 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
40675 \ -------------+------+------+------+------++---+---+---+---+---------+
40676
40677
40678 \ ******************************\
40679 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
40680 \ ******************************\
40681 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
40682 \ ------------------------------\
40683 \ define LPM mode for ACCEPT    \
40684 \ ------------------------------\
40685 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
40686 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
40687 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
40688 BIT.B #SW2,&SW2_IN              \ test switch S2
40689 0= IF                           \ case of switch S2 pressed
40690     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
40691     U< IF
40692         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
40693     THEN
40694 ELSE
40695     BIT.B #SW1,&SW1_IN          \ test switch S1 input
40696     0= IF                       \ case of Switch S1 pressed
40697         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
40698         U>= IF                  \
40699             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
40700         THEN                    \
40701     THEN                        \
40702 THEN                            \
40703 RETI                            \ CPU is ON, GIE is OFF
40704 ENDASM                          \
40705     \
40706
40707
40708 \ ------------------------------\
40709 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
40710 \ ******************************\
40711 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
40712 \ ******************************\
40713 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
40714 \                               \       SMclock = 8|16|24 MHz
40715 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
40716 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
40717 \                               \       SR(9)=new Toggle bit memory (ADD on)
40718 \ ------------------------------\
40719 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
40720 \ ------------------------------\
40721 \ define LPM mode for ACCEPT    \
40722 \ ------------------------------\
40723 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
40724 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
40725 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
40726 \ ------------------------------\
40727 \ RC5_FirstStartBitHalfCycle:   \
40728 \ ------------------------------\
40729 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
40730 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
40731 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
40732 MOV     #1778,X                 \ RC5_Period in us
40733 MOV     #14,W                   \ count of loop
40734 BEGIN                           \
40735 \ ------------------------------\
40736 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
40737 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
40738     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
40739 \ RC5_Compute_3/4_Period:       \                   |
40740     RRUM    #1,X                \ X=1/2 cycle       |
40741     MOV     X,Y                 \ Y=1/2             ^
40742     RRUM    #1,Y                \ Y=1/4
40743     ADD     X,Y                 \ Y=3/4
40744 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
40745     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
40746     0= UNTIL                    \
40747 \ ------------------------------\
40748 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
40749 \ ------------------------------\
40750     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
40751     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
40752     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
40753     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
40754     SUB     #1,W                \ decrement count loop
40755 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
40756 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
40757 0<> WHILE                       \ ----> out of loop ----+
40758 \ RC5_compute_7/4_Time_out:     \                       |
40759     ADD     X,Y                 \                       |   out of bound = 7/4 period 
40760 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
40761     BEGIN                       \                       |
40762         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
40763         0>= IF                  \                       |   if cycle time out of bound
40764             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
40765             RETI                \                       |   then quit to do nothing
40766         THEN                    \                       |
40767 \ ------------------------------\                       |
40768         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
40769     0<> UNTIL                   \                   |   |
40770     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
40771 REPEAT                          \ ----> loop back --+   |
40772 \ ------------------------------\                       |
40773 \ RC5_SampleEndOf:              \ <---------------------+
40774 \ ------------------------------\
40775 BIC     #$30,&TA0CTL           \ stop timer_A0
40776 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
40777 \ ******************************\
40778 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
40779 \ ******************************\
40780 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
40781 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
40782 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
40783 BIT     #BIT13,X                \ X(13) = New_RC5_command
40784 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
40785 THEN                            \
40786 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
40787 \ ******************************\
40788 \ RC5_ComputeNewRC5word         \
40789 \ ******************************\
40790 SUB     #4,PSP                  \
40791 MOV     &BASE,2(PSP)            \ save variable BASE before use
40792 MOV     TOS,0(PSP)              \ save TOS before use
40793 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
40794 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
40795 \ ******************************\
40796 \ RC5_ComputeC6bit              \
40797 \ ******************************\
40798 BIT     #$4000,IP              \ test /C6 bit in IP
40799 0= IF   BIS #$40,TOS           \ set C6 bit in S
40800 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
40801 \ ******************************\
40802 \ RC5_CommandByteIsDone         \ RC5_code --
40803 \ ******************************\
40804
40805 \ ------------------------------\
40806 \ Display IR_RC5 code           \
40807 \ ------------------------------\
40808 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
40809 \ ------------------------------\
40810 LO2HI                           \ switch from assembler to FORTH
40811     ['] LCD_CLEAR IS CR         \ redirects CR
40812     ['] LCD_WrC  IS EMIT        \ redirects EMIT
40813     $10 BASE !                 \ change BASE to hexadecimal
40814     CR ." $" 2 U.R             \ print IR_RC5 code
40815     ['] (CR) IS CR              \ restore CR
40816     ['] (EMIT) IS EMIT          \ restore EMIT
40817 HI2LO                           \ switch from FORTH to assembler
40818 \ ------------------------------\
40819 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
40820 \ ------------------------------\
40821 MOV @PSP+,&BASE                 \ restore variable BASE
40822 RETI                            \ CPU is ON, GIE is OFF
40823 ENDASM                          \
40824     \ 
40825
40826 CODE START                      \
40827 \ ------------------------------\
40828 \ TB0CTL = %0000 0010 1001 0100\$3C0
40829 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
40830 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
40831 \                      --       \ID input divider \ 10 = /4
40832 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
40833 \                            -  \TBCLR TimerB Clear
40834 \                             - \TBIE
40835 \                              -\TBIFG
40836 \ --------------------------------\\
40837 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
40838 \              --                 \CM Capture Mode
40839 \                --               \CCIS
40840 \                   -             \SCS
40841 \                    --           \CLLD
40842 \                      -          \CAP
40843 \                        ---      \OUTMOD \ 011 = set/reset
40844 \                           -     \CCIE
40845 \                             -   \CCI
40846 \                              -  \OUT
40847 \                               - \COV
40848 \                                -\CCIFG
40849 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
40850 \ TB0EX0                          \$3E0 
40851 \ ------------------------------\
40852 \ set TimerB to make 50kHz PWM  \
40853 \ ------------------------------\
40854 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
40855 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
40856 \ ------------------------------\
40857 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
40858 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
40859 \ ------------------------------\
40860     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
40861     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
40862 \ ------------------------------\
40863 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
40864 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
40865 \ ------------------------------\
40866 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
40867 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
40868 \ ------------------------------\
40869     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
40870 \ ------------------------------\
40871 \ set TimerB to generate PWM for LCD_Vo
40872 \ ------------------------------\
40873     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
40874 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
40875     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
40876 \ ------------------------------\
40877     BIS.B #LCDVo,&LCDVo_DIR     \
40878     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
40879 \ ------------------------------\
40880     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
40881     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
40882 \ ------------------------------\
40883     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
40884     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
40885 \ ------------------------------\
40886 \ WDT interval init part        \
40887 \ ------------------------------\
40888     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
40889 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
40890 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
40891     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
40892 \ ------------------------------\
40893 \ init RC5_Int                  \
40894 \ ------------------------------\
40895     BIS.B #RC5,&IR_IE           \ enable RC5_Int
40896     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
40897 \ ------------------------------\
40898 \ init interrupt vectors
40899 \ ------------------------------\
40900     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
40901     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
40902 \ ------------------------------\
40903 \ define LPM mode for ACCEPT    \
40904 \ ------------------------------\
40905 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
40906 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
40907 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
40908
40909 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
40910
40911 \ ------------------------------\
40912 \ Init LCD 2x20                 \
40913 \ ------------------------------\
40914     $03E8 20_US                \ 1-  wait 20 ms
40915     $03 TOP_LCD                \ 2- send DB5=DB4=1
40916     $CD 20_US                  \ 3- wait 4,1 ms
40917     $03 TOP_LCD                \ 4- send again DB5=DB4=1
40918     $5 20_US                   \ 5- wait 0,1 ms
40919     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
40920     $2 20_US                   \    wait 40 us = LCD cycle
40921     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
40922     $2 20_US                   \    wait 40 us = LCD cycle
40923     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
40924     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
40925     LCD_Clear                   \ 10- "LCD_Clear"
40926     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
40927     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
40928     LCD_Clear                   \ 10- "LCD_Clear"
40929     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
40930     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
40931     CR ." I love you"   
40932     ['] (CR) IS CR              \ ' (CR) is CR
40933     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
40934     CR
40935     ."    RC5toLCD is running. Type STOP to quit"
40936 \    NOECHO                      \ uncomment to run this app without terminal connexion
40937     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
40938     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
40939 ;
40940     \
40941
40942 : STOP                  \ stops multitasking, must to be used before downloading app
40943     ['] (WARM) IS WARM  \ remove START app from FORTH init process
40944     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
40945 ;
40946     \
40947
40948
40949 RST_STATE   ;
40950
40951
40952 CODE MAX    \    n1 n2 -- n3       signed maximum
40953             CMP     @PSP,TOS    \ n2-n1
40954             S<      ?GOTO FW1   \ n2<n1
40955 BW1         ADD     #2,PSP
40956             MOV     @IP+,PC
40957 ENDCODE
40958     \
40959
40960 CODE MIN    \    n1 n2 -- n3       signed minimum
40961             CMP     @PSP,TOS     \ n2-n1
40962             S<      ?GOTO BW1    \ n2<n1
40963 FW1         MOV     @PSP+,TOS
40964             MOV     @IP+,PC
40965 ENDCODE
40966     \
40967
40968 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
40969   >R  <# 0 # #S #>  
40970   R> OVER - 0 MAX SPACES TYPE
40971 ;
40972     \
40973
40974 CODE 20_US                      \ n --      n * 20 us
40975 BEGIN                           \ 3 cycles loop + 6~  
40976 \    MOV     #5,W                \ 3 MCLK = 1 MHz
40977 \    MOV     #23,W               \ 3 MCLK = 4 MHz
40978     MOV     #51,W               \ 3 MCLK = 8 MHz
40979 \    MOV     #104,W              \ 3 MCLK = 16 MHz
40980 \    MOV     #158,W              \ 3 MCLK = 24 MHz
40981     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
40982         SUB #1,W                \ 1
40983     0= UNTIL                    \ 2
40984     SUB     #1,TOS              \ 1
40985 0= UNTIL                        \ 2
40986     MOV     @PSP+,TOS           \ 2
40987     MOV     @IP+,PC             \ 4
40988 ENDCODE
40989     \
40990
40991 CODE TOP_LCD                    \ LCD Sample
40992 \                               \ if write : %xxxxWWWW --
40993 \                               \ if read  : -- %0000RRRR
40994     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
40995     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
40996 0= IF                           \ write LCD bits pattern
40997     AND.B #LCD_DB,TOS           \ 
40998     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
40999     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
41000     MOV @PSP+,TOS               \
41001     MOV @IP+,PC
41002 THEN                            \ read LCD bits pattern
41003     SUB #2,PSP
41004     MOV TOS,0(PSP)
41005     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
41006     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
41007     AND.B #LCD_DB,TOS           \
41008     MOV @IP+,PC
41009 ENDCODE
41010     \
41011
41012 CODE LCD_W                      \ byte --       write byte to LCD 
41013     SUB #2,PSP                  \
41014     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
41015     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
41016     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
41017     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
41018 COLON                           \ high level word starts here 
41019     TOP_LCD 2 20_US             \ write high nibble first
41020     TOP_LCD 2 20_US 
41021 ;
41022     \
41023
41024 CODE LCD_WrC                    \ char --         Write Char
41025     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
41026     JMP LCD_W 
41027 ENDCODE
41028     \
41029
41030 CODE LCD_WrF                    \ func --         Write Fonction
41031     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
41032     JMP LCD_W 
41033 ENDCODE
41034     \
41035
41036 : LCD_Clear 
41037     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
41038 ;
41039     \
41040
41041 : LCD_Home 
41042     $02 LCD_WrF 100 20_us 
41043 ;
41044     \
41045
41046 \ : LCD_Entry_set       $04 OR LCD_WrF ;
41047
41048 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
41049
41050 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
41051
41052 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
41053
41054 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
41055
41056 \ : LCD_Goto            $80 OR LCD_WrF ;
41057
41058 \ CODE LCD_R                      \ -- byte       read byte from LCD
41059 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
41060 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
41061 \ COLON                           \ starts a FORTH word
41062 \     TOP_LCD 2 20_us             \ -- %0000HHHH
41063 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
41064 \ HI2LO                           \ switch from FORTH to assembler
41065 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
41066 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
41067 \     MOV @RSP+,IP                \ restore IP saved by COLON
41068 \     MOV @IP+,PC                 \
41069 \ ENDCODE
41070 \     \
41071
41072 \ CODE LCD_RdS                    \ -- status       Read Status
41073 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
41074 \     JMP LCD_R
41075 \ ENDCODE
41076 \     \
41077
41078 \ CODE LCD_RdC                    \ -- char         Read Char
41079 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
41080 \     JMP LCD_R
41081 \ ENDCODE
41082 \     \
41083
41084 \ -------------+------+------+------+------++---+---+---+---+---------+
41085 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
41086 \ -------------+------+------+------+------++---+---+---+---+---------+
41087 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
41088 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
41089 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
41090 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
41091 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
41092 \ -------------+------+------+------+------++---+---+---+---+---------+
41093
41094
41095 \ ******************************\
41096 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
41097 \ ******************************\
41098 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
41099 \ ------------------------------\
41100 \ define LPM mode for ACCEPT    \
41101 \ ------------------------------\
41102 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
41103 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
41104 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
41105 BIT.B #SW2,&SW2_IN              \ test switch S2
41106 0= IF                           \ case of switch S2 pressed
41107     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
41108     U< IF
41109         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
41110     THEN
41111 ELSE
41112     BIT.B #SW1,&SW1_IN          \ test switch S1 input
41113     0= IF                       \ case of Switch S1 pressed
41114         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
41115         U>= IF                  \
41116             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
41117         THEN                    \
41118     THEN                        \
41119 THEN                            \
41120 RETI                            \ CPU is ON, GIE is OFF
41121 ENDASM                          \
41122     \
41123
41124
41125 \ ------------------------------\
41126 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
41127 \ ******************************\
41128 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
41129 \ ******************************\
41130 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
41131 \                               \       SMclock = 8|16|24 MHz
41132 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
41133 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
41134 \                               \       SR(9)=new Toggle bit memory (ADD on)
41135 \ ------------------------------\
41136 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
41137 \ ------------------------------\
41138 \ define LPM mode for ACCEPT    \
41139 \ ------------------------------\
41140 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
41141 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
41142 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
41143 \ ------------------------------\
41144 \ RC5_FirstStartBitHalfCycle:   \
41145 \ ------------------------------\
41146 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
41147 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
41148 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
41149 MOV     #1778,X                 \ RC5_Period in us
41150 MOV     #14,W                   \ count of loop
41151 BEGIN                           \
41152 \ ------------------------------\
41153 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
41154 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
41155     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
41156 \ RC5_Compute_3/4_Period:       \                   |
41157     RRUM    #1,X                \ X=1/2 cycle       |
41158     MOV     X,Y                 \ Y=1/2             ^
41159     RRUM    #1,Y                \ Y=1/4
41160     ADD     X,Y                 \ Y=3/4
41161 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
41162     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
41163     0= UNTIL                    \
41164 \ ------------------------------\
41165 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
41166 \ ------------------------------\
41167     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
41168     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
41169     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
41170     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
41171     SUB     #1,W                \ decrement count loop
41172 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
41173 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
41174 0<> WHILE                       \ ----> out of loop ----+
41175 \ RC5_compute_7/4_Time_out:     \                       |
41176     ADD     X,Y                 \                       |   out of bound = 7/4 period 
41177 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
41178     BEGIN                       \                       |
41179         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
41180         0>= IF                  \                       |   if cycle time out of bound
41181             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
41182             RETI                \                       |   then quit to do nothing
41183         THEN                    \                       |
41184 \ ------------------------------\                       |
41185         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
41186     0<> UNTIL                   \                   |   |
41187     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
41188 REPEAT                          \ ----> loop back --+   |
41189 \ ------------------------------\                       |
41190 \ RC5_SampleEndOf:              \ <---------------------+
41191 \ ------------------------------\
41192 BIC     #$30,&TA0CTL           \ stop timer_A0
41193 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
41194 \ ******************************\
41195 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
41196 \ ******************************\
41197 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
41198 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
41199 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
41200 BIT     #BIT13,X                \ X(13) = New_RC5_command
41201 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
41202 THEN                            \
41203 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
41204 \ ******************************\
41205 \ RC5_ComputeNewRC5word         \
41206 \ ******************************\
41207 SUB     #4,PSP                  \
41208 MOV     &BASE,2(PSP)            \ save variable BASE before use
41209 MOV     TOS,0(PSP)              \ save TOS before use
41210 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
41211 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
41212 \ ******************************\
41213 \ RC5_ComputeC6bit              \
41214 \ ******************************\
41215 BIT     #$4000,IP              \ test /C6 bit in IP
41216 0= IF   BIS #$40,TOS           \ set C6 bit in S
41217 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
41218 \ ******************************\
41219 \ RC5_CommandByteIsDone         \ RC5_code --
41220 \ ******************************\
41221
41222 \ ------------------------------\
41223 \ Display IR_RC5 code           \
41224 \ ------------------------------\
41225 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
41226 \ ------------------------------\
41227 LO2HI                           \ switch from assembler to FORTH
41228     ['] LCD_CLEAR IS CR         \ redirects CR
41229     ['] LCD_WrC  IS EMIT        \ redirects EMIT
41230     $10 BASE !                 \ change BASE to hexadecimal
41231     CR ." $" 2 U.R             \ print IR_RC5 code
41232     ['] (CR) IS CR              \ restore CR
41233     ['] (EMIT) IS EMIT          \ restore EMIT
41234 HI2LO                           \ switch from FORTH to assembler
41235 \ ------------------------------\
41236 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
41237 \ ------------------------------\
41238 MOV @PSP+,&BASE                 \ restore variable BASE
41239 RETI                            \ CPU is ON, GIE is OFF
41240 ENDASM                          \
41241     \ 
41242
41243 CODE START                      \
41244 \ ------------------------------\
41245 \ TB0CTL = %0000 0010 1001 0100\$3C0
41246 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
41247 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
41248 \                      --       \ID input divider \ 10 = /4
41249 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
41250 \                            -  \TBCLR TimerB Clear
41251 \                             - \TBIE
41252 \                              -\TBIFG
41253 \ --------------------------------\\
41254 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
41255 \              --                 \CM Capture Mode
41256 \                --               \CCIS
41257 \                   -             \SCS
41258 \                    --           \CLLD
41259 \                      -          \CAP
41260 \                        ---      \OUTMOD \ 011 = set/reset
41261 \                           -     \CCIE
41262 \                             -   \CCI
41263 \                              -  \OUT
41264 \                               - \COV
41265 \                                -\CCIFG
41266 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
41267 \ TB0EX0                          \$3E0 
41268 \ ------------------------------\
41269 \ set TimerB to make 50kHz PWM  \
41270 \ ------------------------------\
41271 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
41272 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
41273 \ ------------------------------\
41274 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
41275 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
41276 \ ------------------------------\
41277     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
41278     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
41279 \ ------------------------------\
41280 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
41281 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
41282 \ ------------------------------\
41283 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
41284 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
41285 \ ------------------------------\
41286     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
41287 \ ------------------------------\
41288 \ set TimerB to generate PWM for LCD_Vo
41289 \ ------------------------------\
41290     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
41291 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
41292     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
41293 \ ------------------------------\
41294     BIS.B #LCDVo,&LCDVo_DIR     \
41295     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
41296 \ ------------------------------\
41297     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
41298     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
41299 \ ------------------------------\
41300     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
41301     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
41302 \ ------------------------------\
41303 \ WDT interval init part        \
41304 \ ------------------------------\
41305     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
41306 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
41307 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
41308     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
41309 \ ------------------------------\
41310 \ init RC5_Int                  \
41311 \ ------------------------------\
41312     BIS.B #RC5,&IR_IE           \ enable RC5_Int
41313     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
41314 \ ------------------------------\
41315 \ init interrupt vectors
41316 \ ------------------------------\
41317     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
41318     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
41319 \ ------------------------------\
41320 \ define LPM mode for ACCEPT    \
41321 \ ------------------------------\
41322 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
41323 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
41324 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
41325
41326 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
41327
41328 \ ------------------------------\
41329 \ Init LCD 2x20                 \
41330 \ ------------------------------\
41331     $03E8 20_US                \ 1-  wait 20 ms
41332     $03 TOP_LCD                \ 2- send DB5=DB4=1
41333     $CD 20_US                  \ 3- wait 4,1 ms
41334     $03 TOP_LCD                \ 4- send again DB5=DB4=1
41335     $5 20_US                   \ 5- wait 0,1 ms
41336     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
41337     $2 20_US                   \    wait 40 us = LCD cycle
41338     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
41339     $2 20_US                   \    wait 40 us = LCD cycle
41340     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
41341     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
41342     LCD_Clear                   \ 10- "LCD_Clear"
41343     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
41344     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
41345     LCD_Clear                   \ 10- "LCD_Clear"
41346     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
41347     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
41348     CR ." I love you"   
41349     ['] (CR) IS CR              \ ' (CR) is CR
41350     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
41351     CR
41352     ."    RC5toLCD is running. Type STOP to quit"
41353 \    NOECHO                      \ uncomment to run this app without terminal connexion
41354     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
41355     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
41356 ;
41357     \
41358
41359 : STOP                  \ stops multitasking, must to be used before downloading app
41360     ['] (WARM) IS WARM  \ remove START app from FORTH init process
41361     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
41362 ;
41363     \
41364
41365
41366 RST_STATE   ;
41367
41368
41369 CODE MAX    \    n1 n2 -- n3       signed maximum
41370             CMP     @PSP,TOS    \ n2-n1
41371             S<      ?GOTO FW1   \ n2<n1
41372 BW1         ADD     #2,PSP
41373             MOV     @IP+,PC
41374 ENDCODE
41375     \
41376
41377 CODE MIN    \    n1 n2 -- n3       signed minimum
41378             CMP     @PSP,TOS     \ n2-n1
41379             S<      ?GOTO BW1    \ n2<n1
41380 FW1         MOV     @PSP+,TOS
41381             MOV     @IP+,PC
41382 ENDCODE
41383     \
41384
41385 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
41386   >R  <# 0 # #S #>  
41387   R> OVER - 0 MAX SPACES TYPE
41388 ;
41389     \
41390
41391 CODE 20_US                      \ n --      n * 20 us
41392 BEGIN                           \ 3 cycles loop + 6~  
41393 \    MOV     #5,W                \ 3 MCLK = 1 MHz
41394 \    MOV     #23,W               \ 3 MCLK = 4 MHz
41395     MOV     #51,W               \ 3 MCLK = 8 MHz
41396 \    MOV     #104,W              \ 3 MCLK = 16 MHz
41397 \    MOV     #158,W              \ 3 MCLK = 24 MHz
41398     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
41399         SUB #1,W                \ 1
41400     0= UNTIL                    \ 2
41401     SUB     #1,TOS              \ 1
41402 0= UNTIL                        \ 2
41403     MOV     @PSP+,TOS           \ 2
41404     MOV     @IP+,PC             \ 4
41405 ENDCODE
41406     \
41407
41408 CODE TOP_LCD                    \ LCD Sample
41409 \                               \ if write : %xxxxWWWW --
41410 \                               \ if read  : -- %0000RRRR
41411     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
41412     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
41413 0= IF                           \ write LCD bits pattern
41414     AND.B #LCD_DB,TOS           \ 
41415     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
41416     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
41417     MOV @PSP+,TOS               \
41418     MOV @IP+,PC
41419 THEN                            \ read LCD bits pattern
41420     SUB #2,PSP
41421     MOV TOS,0(PSP)
41422     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
41423     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
41424     AND.B #LCD_DB,TOS           \
41425     MOV @IP+,PC
41426 ENDCODE
41427     \
41428
41429 CODE LCD_W                      \ byte --       write byte to LCD 
41430     SUB #2,PSP                  \
41431     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
41432     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
41433     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
41434     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
41435 COLON                           \ high level word starts here 
41436     TOP_LCD 2 20_US             \ write high nibble first
41437     TOP_LCD 2 20_US 
41438 ;
41439     \
41440
41441 CODE LCD_WrC                    \ char --         Write Char
41442     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
41443     JMP LCD_W 
41444 ENDCODE
41445     \
41446
41447 CODE LCD_WrF                    \ func --         Write Fonction
41448     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
41449     JMP LCD_W 
41450 ENDCODE
41451     \
41452
41453 : LCD_Clear 
41454     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
41455 ;
41456     \
41457
41458 : LCD_Home 
41459     $02 LCD_WrF 100 20_us 
41460 ;
41461     \
41462
41463 \ : LCD_Entry_set       $04 OR LCD_WrF ;
41464
41465 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
41466
41467 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
41468
41469 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
41470
41471 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
41472
41473 \ : LCD_Goto            $80 OR LCD_WrF ;
41474
41475 \ CODE LCD_R                      \ -- byte       read byte from LCD
41476 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
41477 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
41478 \ COLON                           \ starts a FORTH word
41479 \     TOP_LCD 2 20_us             \ -- %0000HHHH
41480 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
41481 \ HI2LO                           \ switch from FORTH to assembler
41482 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
41483 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
41484 \     MOV @RSP+,IP                \ restore IP saved by COLON
41485 \     MOV @IP+,PC                 \
41486 \ ENDCODE
41487 \     \
41488
41489 \ CODE LCD_RdS                    \ -- status       Read Status
41490 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
41491 \     JMP LCD_R
41492 \ ENDCODE
41493 \     \
41494
41495 \ CODE LCD_RdC                    \ -- char         Read Char
41496 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
41497 \     JMP LCD_R
41498 \ ENDCODE
41499 \     \
41500
41501 \ -------------+------+------+------+------++---+---+---+---+---------+
41502 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
41503 \ -------------+------+------+------+------++---+---+---+---+---------+
41504 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
41505 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
41506 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
41507 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
41508 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
41509 \ -------------+------+------+------+------++---+---+---+---+---------+
41510
41511
41512 \ ******************************\
41513 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
41514 \ ******************************\
41515 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
41516 \ ------------------------------\
41517 \ define LPM mode for ACCEPT    \
41518 \ ------------------------------\
41519 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
41520 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
41521 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
41522 BIT.B #SW2,&SW2_IN              \ test switch S2
41523 0= IF                           \ case of switch S2 pressed
41524     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
41525     U< IF
41526         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
41527     THEN
41528 ELSE
41529     BIT.B #SW1,&SW1_IN          \ test switch S1 input
41530     0= IF                       \ case of Switch S1 pressed
41531         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
41532         U>= IF                  \
41533             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
41534         THEN                    \
41535     THEN                        \
41536 THEN                            \
41537 RETI                            \ CPU is ON, GIE is OFF
41538 ENDASM                          \
41539     \
41540
41541
41542 \ ------------------------------\
41543 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
41544 \ ******************************\
41545 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
41546 \ ******************************\
41547 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
41548 \                               \       SMclock = 8|16|24 MHz
41549 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
41550 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
41551 \                               \       SR(9)=new Toggle bit memory (ADD on)
41552 \ ------------------------------\
41553 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
41554 \ ------------------------------\
41555 \ define LPM mode for ACCEPT    \
41556 \ ------------------------------\
41557 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
41558 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
41559 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
41560 \ ------------------------------\
41561 \ RC5_FirstStartBitHalfCycle:   \
41562 \ ------------------------------\
41563 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
41564 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
41565 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
41566 MOV     #1778,X                 \ RC5_Period in us
41567 MOV     #14,W                   \ count of loop
41568 BEGIN                           \
41569 \ ------------------------------\
41570 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
41571 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
41572     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
41573 \ RC5_Compute_3/4_Period:       \                   |
41574     RRUM    #1,X                \ X=1/2 cycle       |
41575     MOV     X,Y                 \ Y=1/2             ^
41576     RRUM    #1,Y                \ Y=1/4
41577     ADD     X,Y                 \ Y=3/4
41578 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
41579     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
41580     0= UNTIL                    \
41581 \ ------------------------------\
41582 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
41583 \ ------------------------------\
41584     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
41585     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
41586     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
41587     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
41588     SUB     #1,W                \ decrement count loop
41589 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
41590 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
41591 0<> WHILE                       \ ----> out of loop ----+
41592 \ RC5_compute_7/4_Time_out:     \                       |
41593     ADD     X,Y                 \                       |   out of bound = 7/4 period 
41594 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
41595     BEGIN                       \                       |
41596         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
41597         0>= IF                  \                       |   if cycle time out of bound
41598             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
41599             RETI                \                       |   then quit to do nothing
41600         THEN                    \                       |
41601 \ ------------------------------\                       |
41602         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
41603     0<> UNTIL                   \                   |   |
41604     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
41605 REPEAT                          \ ----> loop back --+   |
41606 \ ------------------------------\                       |
41607 \ RC5_SampleEndOf:              \ <---------------------+
41608 \ ------------------------------\
41609 BIC     #$30,&TA0CTL           \ stop timer_A0
41610 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
41611 \ ******************************\
41612 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
41613 \ ******************************\
41614 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
41615 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
41616 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
41617 BIT     #BIT13,X                \ X(13) = New_RC5_command
41618 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
41619 THEN                            \
41620 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
41621 \ ******************************\
41622 \ RC5_ComputeNewRC5word         \
41623 \ ******************************\
41624 SUB     #4,PSP                  \
41625 MOV     &BASE,2(PSP)            \ save variable BASE before use
41626 MOV     TOS,0(PSP)              \ save TOS before use
41627 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
41628 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
41629 \ ******************************\
41630 \ RC5_ComputeC6bit              \
41631 \ ******************************\
41632 BIT     #$4000,IP              \ test /C6 bit in IP
41633 0= IF   BIS #$40,TOS           \ set C6 bit in S
41634 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
41635 \ ******************************\
41636 \ RC5_CommandByteIsDone         \ RC5_code --
41637 \ ******************************\
41638
41639 \ ------------------------------\
41640 \ Display IR_RC5 code           \
41641 \ ------------------------------\
41642 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
41643 \ ------------------------------\
41644 LO2HI                           \ switch from assembler to FORTH
41645     ['] LCD_CLEAR IS CR         \ redirects CR
41646     ['] LCD_WrC  IS EMIT        \ redirects EMIT
41647     $10 BASE !                 \ change BASE to hexadecimal
41648     CR ." $" 2 U.R             \ print IR_RC5 code
41649     ['] (CR) IS CR              \ restore CR
41650     ['] (EMIT) IS EMIT          \ restore EMIT
41651 HI2LO                           \ switch from FORTH to assembler
41652 \ ------------------------------\
41653 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
41654 \ ------------------------------\
41655 MOV @PSP+,&BASE                 \ restore variable BASE
41656 RETI                            \ CPU is ON, GIE is OFF
41657 ENDASM                          \
41658     \ 
41659
41660 CODE START                      \
41661 \ ------------------------------\
41662 \ TB0CTL = %0000 0010 1001 0100\$3C0
41663 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
41664 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
41665 \                      --       \ID input divider \ 10 = /4
41666 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
41667 \                            -  \TBCLR TimerB Clear
41668 \                             - \TBIE
41669 \                              -\TBIFG
41670 \ --------------------------------\\
41671 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
41672 \              --                 \CM Capture Mode
41673 \                --               \CCIS
41674 \                   -             \SCS
41675 \                    --           \CLLD
41676 \                      -          \CAP
41677 \                        ---      \OUTMOD \ 011 = set/reset
41678 \                           -     \CCIE
41679 \                             -   \CCI
41680 \                              -  \OUT
41681 \                               - \COV
41682 \                                -\CCIFG
41683 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
41684 \ TB0EX0                          \$3E0 
41685 \ ------------------------------\
41686 \ set TimerB to make 50kHz PWM  \
41687 \ ------------------------------\
41688 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
41689 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
41690 \ ------------------------------\
41691 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
41692 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
41693 \ ------------------------------\
41694     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
41695     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
41696 \ ------------------------------\
41697 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
41698 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
41699 \ ------------------------------\
41700 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
41701 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
41702 \ ------------------------------\
41703     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
41704 \ ------------------------------\
41705 \ set TimerB to generate PWM for LCD_Vo
41706 \ ------------------------------\
41707     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
41708 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
41709     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
41710 \ ------------------------------\
41711     BIS.B #LCDVo,&LCDVo_DIR     \
41712     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
41713 \ ------------------------------\
41714     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
41715     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
41716 \ ------------------------------\
41717     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
41718     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
41719 \ ------------------------------\
41720 \ WDT interval init part        \
41721 \ ------------------------------\
41722     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
41723 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
41724 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
41725     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
41726 \ ------------------------------\
41727 \ init RC5_Int                  \
41728 \ ------------------------------\
41729     BIS.B #RC5,&IR_IE           \ enable RC5_Int
41730     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
41731 \ ------------------------------\
41732 \ init interrupt vectors
41733 \ ------------------------------\
41734     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
41735     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
41736 \ ------------------------------\
41737 \ define LPM mode for ACCEPT    \
41738 \ ------------------------------\
41739 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
41740 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
41741 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
41742
41743 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
41744
41745 \ ------------------------------\
41746 \ Init LCD 2x20                 \
41747 \ ------------------------------\
41748     $03E8 20_US                \ 1-  wait 20 ms
41749     $03 TOP_LCD                \ 2- send DB5=DB4=1
41750     $CD 20_US                  \ 3- wait 4,1 ms
41751     $03 TOP_LCD                \ 4- send again DB5=DB4=1
41752     $5 20_US                   \ 5- wait 0,1 ms
41753     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
41754     $2 20_US                   \    wait 40 us = LCD cycle
41755     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
41756     $2 20_US                   \    wait 40 us = LCD cycle
41757     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
41758     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
41759     LCD_Clear                   \ 10- "LCD_Clear"
41760     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
41761     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
41762     LCD_Clear                   \ 10- "LCD_Clear"
41763     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
41764     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
41765     CR ." I love you"   
41766     ['] (CR) IS CR              \ ' (CR) is CR
41767     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
41768     CR
41769     ."    RC5toLCD is running. Type STOP to quit"
41770 \    NOECHO                      \ uncomment to run this app without terminal connexion
41771     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
41772     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
41773 ;
41774     \
41775
41776 : STOP                  \ stops multitasking, must to be used before downloading app
41777     ['] (WARM) IS WARM  \ remove START app from FORTH init process
41778     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
41779 ;
41780     \
41781
41782
41783 RST_STATE   ;
41784
41785
41786 CODE MAX    \    n1 n2 -- n3       signed maximum
41787             CMP     @PSP,TOS    \ n2-n1
41788             S<      ?GOTO FW1   \ n2<n1
41789 BW1         ADD     #2,PSP
41790             MOV     @IP+,PC
41791 ENDCODE
41792     \
41793
41794 CODE MIN    \    n1 n2 -- n3       signed minimum
41795             CMP     @PSP,TOS     \ n2-n1
41796             S<      ?GOTO BW1    \ n2<n1
41797 FW1         MOV     @PSP+,TOS
41798             MOV     @IP+,PC
41799 ENDCODE
41800     \
41801
41802 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
41803   >R  <# 0 # #S #>  
41804   R> OVER - 0 MAX SPACES TYPE
41805 ;
41806     \
41807
41808 CODE 20_US                      \ n --      n * 20 us
41809 BEGIN                           \ 3 cycles loop + 6~  
41810 \    MOV     #5,W                \ 3 MCLK = 1 MHz
41811 \    MOV     #23,W               \ 3 MCLK = 4 MHz
41812     MOV     #51,W               \ 3 MCLK = 8 MHz
41813 \    MOV     #104,W              \ 3 MCLK = 16 MHz
41814 \    MOV     #158,W              \ 3 MCLK = 24 MHz
41815     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
41816         SUB #1,W                \ 1
41817     0= UNTIL                    \ 2
41818     SUB     #1,TOS              \ 1
41819 0= UNTIL                        \ 2
41820     MOV     @PSP+,TOS           \ 2
41821     MOV     @IP+,PC             \ 4
41822 ENDCODE
41823     \
41824
41825 CODE TOP_LCD                    \ LCD Sample
41826 \                               \ if write : %xxxxWWWW --
41827 \                               \ if read  : -- %0000RRRR
41828     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
41829     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
41830 0= IF                           \ write LCD bits pattern
41831     AND.B #LCD_DB,TOS           \ 
41832     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
41833     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
41834     MOV @PSP+,TOS               \
41835     MOV @IP+,PC
41836 THEN                            \ read LCD bits pattern
41837     SUB #2,PSP
41838     MOV TOS,0(PSP)
41839     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
41840     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
41841     AND.B #LCD_DB,TOS           \
41842     MOV @IP+,PC
41843 ENDCODE
41844     \
41845
41846 CODE LCD_W                      \ byte --       write byte to LCD 
41847     SUB #2,PSP                  \
41848     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
41849     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
41850     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
41851     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
41852 COLON                           \ high level word starts here 
41853     TOP_LCD 2 20_US             \ write high nibble first
41854     TOP_LCD 2 20_US 
41855 ;
41856     \
41857
41858 CODE LCD_WrC                    \ char --         Write Char
41859     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
41860     JMP LCD_W 
41861 ENDCODE
41862     \
41863
41864 CODE LCD_WrF                    \ func --         Write Fonction
41865     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
41866     JMP LCD_W 
41867 ENDCODE
41868     \
41869
41870 : LCD_Clear 
41871     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
41872 ;
41873     \
41874
41875 : LCD_Home 
41876     $02 LCD_WrF 100 20_us 
41877 ;
41878     \
41879
41880 \ : LCD_Entry_set       $04 OR LCD_WrF ;
41881
41882 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
41883
41884 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
41885
41886 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
41887
41888 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
41889
41890 \ : LCD_Goto            $80 OR LCD_WrF ;
41891
41892 \ CODE LCD_R                      \ -- byte       read byte from LCD
41893 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
41894 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
41895 \ COLON                           \ starts a FORTH word
41896 \     TOP_LCD 2 20_us             \ -- %0000HHHH
41897 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
41898 \ HI2LO                           \ switch from FORTH to assembler
41899 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
41900 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
41901 \     MOV @RSP+,IP                \ restore IP saved by COLON
41902 \     MOV @IP+,PC                 \
41903 \ ENDCODE
41904 \     \
41905
41906 \ CODE LCD_RdS                    \ -- status       Read Status
41907 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
41908 \     JMP LCD_R
41909 \ ENDCODE
41910 \     \
41911
41912 \ CODE LCD_RdC                    \ -- char         Read Char
41913 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
41914 \     JMP LCD_R
41915 \ ENDCODE
41916 \     \
41917
41918 \ -------------+------+------+------+------++---+---+---+---+---------+
41919 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
41920 \ -------------+------+------+------+------++---+---+---+---+---------+
41921 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
41922 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
41923 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
41924 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
41925 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
41926 \ -------------+------+------+------+------++---+---+---+---+---------+
41927
41928
41929 \ ******************************\
41930 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
41931 \ ******************************\
41932 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
41933 \ ------------------------------\
41934 \ define LPM mode for ACCEPT    \
41935 \ ------------------------------\
41936 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
41937 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
41938 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
41939 BIT.B #SW2,&SW2_IN              \ test switch S2
41940 0= IF                           \ case of switch S2 pressed
41941     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
41942     U< IF
41943         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
41944     THEN
41945 ELSE
41946     BIT.B #SW1,&SW1_IN          \ test switch S1 input
41947     0= IF                       \ case of Switch S1 pressed
41948         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
41949         U>= IF                  \
41950             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
41951         THEN                    \
41952     THEN                        \
41953 THEN                            \
41954 RETI                            \ CPU is ON, GIE is OFF
41955 ENDASM                          \
41956     \
41957
41958
41959 \ ------------------------------\
41960 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
41961 \ ******************************\
41962 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
41963 \ ******************************\
41964 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
41965 \                               \       SMclock = 8|16|24 MHz
41966 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
41967 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
41968 \                               \       SR(9)=new Toggle bit memory (ADD on)
41969 \ ------------------------------\
41970 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
41971 \ ------------------------------\
41972 \ define LPM mode for ACCEPT    \
41973 \ ------------------------------\
41974 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
41975 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
41976 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
41977 \ ------------------------------\
41978 \ RC5_FirstStartBitHalfCycle:   \
41979 \ ------------------------------\
41980 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
41981 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
41982 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
41983 MOV     #1778,X                 \ RC5_Period in us
41984 MOV     #14,W                   \ count of loop
41985 BEGIN                           \
41986 \ ------------------------------\
41987 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
41988 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
41989     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
41990 \ RC5_Compute_3/4_Period:       \                   |
41991     RRUM    #1,X                \ X=1/2 cycle       |
41992     MOV     X,Y                 \ Y=1/2             ^
41993     RRUM    #1,Y                \ Y=1/4
41994     ADD     X,Y                 \ Y=3/4
41995 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
41996     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
41997     0= UNTIL                    \
41998 \ ------------------------------\
41999 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
42000 \ ------------------------------\
42001     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
42002     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
42003     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
42004     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
42005     SUB     #1,W                \ decrement count loop
42006 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
42007 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
42008 0<> WHILE                       \ ----> out of loop ----+
42009 \ RC5_compute_7/4_Time_out:     \                       |
42010     ADD     X,Y                 \                       |   out of bound = 7/4 period 
42011 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
42012     BEGIN                       \                       |
42013         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
42014         0>= IF                  \                       |   if cycle time out of bound
42015             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
42016             RETI                \                       |   then quit to do nothing
42017         THEN                    \                       |
42018 \ ------------------------------\                       |
42019         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
42020     0<> UNTIL                   \                   |   |
42021     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
42022 REPEAT                          \ ----> loop back --+   |
42023 \ ------------------------------\                       |
42024 \ RC5_SampleEndOf:              \ <---------------------+
42025 \ ------------------------------\
42026 BIC     #$30,&TA0CTL           \ stop timer_A0
42027 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
42028 \ ******************************\
42029 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
42030 \ ******************************\
42031 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
42032 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
42033 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
42034 BIT     #BIT13,X                \ X(13) = New_RC5_command
42035 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
42036 THEN                            \
42037 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
42038 \ ******************************\
42039 \ RC5_ComputeNewRC5word         \
42040 \ ******************************\
42041 SUB     #4,PSP                  \
42042 MOV     &BASE,2(PSP)            \ save variable BASE before use
42043 MOV     TOS,0(PSP)              \ save TOS before use
42044 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
42045 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
42046 \ ******************************\
42047 \ RC5_ComputeC6bit              \
42048 \ ******************************\
42049 BIT     #$4000,IP              \ test /C6 bit in IP
42050 0= IF   BIS #$40,TOS           \ set C6 bit in S
42051 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
42052 \ ******************************\
42053 \ RC5_CommandByteIsDone         \ RC5_code --
42054 \ ******************************\
42055
42056 \ ------------------------------\
42057 \ Display IR_RC5 code           \
42058 \ ------------------------------\
42059 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
42060 \ ------------------------------\
42061 LO2HI                           \ switch from assembler to FORTH
42062     ['] LCD_CLEAR IS CR         \ redirects CR
42063     ['] LCD_WrC  IS EMIT        \ redirects EMIT
42064     $10 BASE !                 \ change BASE to hexadecimal
42065     CR ." $" 2 U.R             \ print IR_RC5 code
42066     ['] (CR) IS CR              \ restore CR
42067     ['] (EMIT) IS EMIT          \ restore EMIT
42068 HI2LO                           \ switch from FORTH to assembler
42069 \ ------------------------------\
42070 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
42071 \ ------------------------------\
42072 MOV @PSP+,&BASE                 \ restore variable BASE
42073 RETI                            \ CPU is ON, GIE is OFF
42074 ENDASM                          \
42075     \ 
42076
42077 CODE START                      \
42078 \ ------------------------------\
42079 \ TB0CTL = %0000 0010 1001 0100\$3C0
42080 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
42081 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
42082 \                      --       \ID input divider \ 10 = /4
42083 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
42084 \                            -  \TBCLR TimerB Clear
42085 \                             - \TBIE
42086 \                              -\TBIFG
42087 \ --------------------------------\\
42088 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
42089 \              --                 \CM Capture Mode
42090 \                --               \CCIS
42091 \                   -             \SCS
42092 \                    --           \CLLD
42093 \                      -          \CAP
42094 \                        ---      \OUTMOD \ 011 = set/reset
42095 \                           -     \CCIE
42096 \                             -   \CCI
42097 \                              -  \OUT
42098 \                               - \COV
42099 \                                -\CCIFG
42100 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
42101 \ TB0EX0                          \$3E0 
42102 \ ------------------------------\
42103 \ set TimerB to make 50kHz PWM  \
42104 \ ------------------------------\
42105 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
42106 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
42107 \ ------------------------------\
42108 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
42109 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
42110 \ ------------------------------\
42111     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
42112     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
42113 \ ------------------------------\
42114 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
42115 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
42116 \ ------------------------------\
42117 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
42118 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
42119 \ ------------------------------\
42120     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
42121 \ ------------------------------\
42122 \ set TimerB to generate PWM for LCD_Vo
42123 \ ------------------------------\
42124     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
42125 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
42126     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
42127 \ ------------------------------\
42128     BIS.B #LCDVo,&LCDVo_DIR     \
42129     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
42130 \ ------------------------------\
42131     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
42132     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
42133 \ ------------------------------\
42134     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
42135     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
42136 \ ------------------------------\
42137 \ WDT interval init part        \
42138 \ ------------------------------\
42139     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
42140 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
42141 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
42142     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
42143 \ ------------------------------\
42144 \ init RC5_Int                  \
42145 \ ------------------------------\
42146     BIS.B #RC5,&IR_IE           \ enable RC5_Int
42147     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
42148 \ ------------------------------\
42149 \ init interrupt vectors
42150 \ ------------------------------\
42151     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
42152     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
42153 \ ------------------------------\
42154 \ define LPM mode for ACCEPT    \
42155 \ ------------------------------\
42156 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
42157 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
42158 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
42159
42160 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
42161
42162 \ ------------------------------\
42163 \ Init LCD 2x20                 \
42164 \ ------------------------------\
42165     $03E8 20_US                \ 1-  wait 20 ms
42166     $03 TOP_LCD                \ 2- send DB5=DB4=1
42167     $CD 20_US                  \ 3- wait 4,1 ms
42168     $03 TOP_LCD                \ 4- send again DB5=DB4=1
42169     $5 20_US                   \ 5- wait 0,1 ms
42170     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
42171     $2 20_US                   \    wait 40 us = LCD cycle
42172     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
42173     $2 20_US                   \    wait 40 us = LCD cycle
42174     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
42175     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
42176     LCD_Clear                   \ 10- "LCD_Clear"
42177     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
42178     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
42179     LCD_Clear                   \ 10- "LCD_Clear"
42180     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
42181     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
42182     CR ." I love you"   
42183     ['] (CR) IS CR              \ ' (CR) is CR
42184     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
42185     CR
42186     ."    RC5toLCD is running. Type STOP to quit"
42187 \    NOECHO                      \ uncomment to run this app without terminal connexion
42188     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
42189     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
42190 ;
42191     \
42192
42193 : STOP                  \ stops multitasking, must to be used before downloading app
42194     ['] (WARM) IS WARM  \ remove START app from FORTH init process
42195     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
42196 ;
42197     \
42198
42199
42200 RST_STATE   ;
42201
42202
42203 CODE MAX    \    n1 n2 -- n3       signed maximum
42204             CMP     @PSP,TOS    \ n2-n1
42205             S<      ?GOTO FW1   \ n2<n1
42206 BW1         ADD     #2,PSP
42207             MOV     @IP+,PC
42208 ENDCODE
42209     \
42210
42211 CODE MIN    \    n1 n2 -- n3       signed minimum
42212             CMP     @PSP,TOS     \ n2-n1
42213             S<      ?GOTO BW1    \ n2<n1
42214 FW1         MOV     @PSP+,TOS
42215             MOV     @IP+,PC
42216 ENDCODE
42217     \
42218
42219 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
42220   >R  <# 0 # #S #>  
42221   R> OVER - 0 MAX SPACES TYPE
42222 ;
42223     \
42224
42225 CODE 20_US                      \ n --      n * 20 us
42226 BEGIN                           \ 3 cycles loop + 6~  
42227 \    MOV     #5,W                \ 3 MCLK = 1 MHz
42228 \    MOV     #23,W               \ 3 MCLK = 4 MHz
42229     MOV     #51,W               \ 3 MCLK = 8 MHz
42230 \    MOV     #104,W              \ 3 MCLK = 16 MHz
42231 \    MOV     #158,W              \ 3 MCLK = 24 MHz
42232     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
42233         SUB #1,W                \ 1
42234     0= UNTIL                    \ 2
42235     SUB     #1,TOS              \ 1
42236 0= UNTIL                        \ 2
42237     MOV     @PSP+,TOS           \ 2
42238     MOV     @IP+,PC             \ 4
42239 ENDCODE
42240     \
42241
42242 CODE TOP_LCD                    \ LCD Sample
42243 \                               \ if write : %xxxxWWWW --
42244 \                               \ if read  : -- %0000RRRR
42245     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
42246     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
42247 0= IF                           \ write LCD bits pattern
42248     AND.B #LCD_DB,TOS           \ 
42249     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
42250     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
42251     MOV @PSP+,TOS               \
42252     MOV @IP+,PC
42253 THEN                            \ read LCD bits pattern
42254     SUB #2,PSP
42255     MOV TOS,0(PSP)
42256     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
42257     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
42258     AND.B #LCD_DB,TOS           \
42259     MOV @IP+,PC
42260 ENDCODE
42261     \
42262
42263 CODE LCD_W                      \ byte --       write byte to LCD 
42264     SUB #2,PSP                  \
42265     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
42266     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
42267     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
42268     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
42269 COLON                           \ high level word starts here 
42270     TOP_LCD 2 20_US             \ write high nibble first
42271     TOP_LCD 2 20_US 
42272 ;
42273     \
42274
42275 CODE LCD_WrC                    \ char --         Write Char
42276     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
42277     JMP LCD_W 
42278 ENDCODE
42279     \
42280
42281 CODE LCD_WrF                    \ func --         Write Fonction
42282     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
42283     JMP LCD_W 
42284 ENDCODE
42285     \
42286
42287 : LCD_Clear 
42288     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
42289 ;
42290     \
42291
42292 : LCD_Home 
42293     $02 LCD_WrF 100 20_us 
42294 ;
42295     \
42296
42297 \ : LCD_Entry_set       $04 OR LCD_WrF ;
42298
42299 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
42300
42301 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
42302
42303 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
42304
42305 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
42306
42307 \ : LCD_Goto            $80 OR LCD_WrF ;
42308
42309 \ CODE LCD_R                      \ -- byte       read byte from LCD
42310 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
42311 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
42312 \ COLON                           \ starts a FORTH word
42313 \     TOP_LCD 2 20_us             \ -- %0000HHHH
42314 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
42315 \ HI2LO                           \ switch from FORTH to assembler
42316 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
42317 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
42318 \     MOV @RSP+,IP                \ restore IP saved by COLON
42319 \     MOV @IP+,PC                 \
42320 \ ENDCODE
42321 \     \
42322
42323 \ CODE LCD_RdS                    \ -- status       Read Status
42324 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
42325 \     JMP LCD_R
42326 \ ENDCODE
42327 \     \
42328
42329 \ CODE LCD_RdC                    \ -- char         Read Char
42330 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
42331 \     JMP LCD_R
42332 \ ENDCODE
42333 \     \
42334
42335 \ -------------+------+------+------+------++---+---+---+---+---------+
42336 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
42337 \ -------------+------+------+------+------++---+---+---+---+---------+
42338 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
42339 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
42340 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
42341 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
42342 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
42343 \ -------------+------+------+------+------++---+---+---+---+---------+
42344
42345
42346 \ ******************************\
42347 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
42348 \ ******************************\
42349 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
42350 \ ------------------------------\
42351 \ define LPM mode for ACCEPT    \
42352 \ ------------------------------\
42353 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
42354 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
42355 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
42356 BIT.B #SW2,&SW2_IN              \ test switch S2
42357 0= IF                           \ case of switch S2 pressed
42358     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
42359     U< IF
42360         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
42361     THEN
42362 ELSE
42363     BIT.B #SW1,&SW1_IN          \ test switch S1 input
42364     0= IF                       \ case of Switch S1 pressed
42365         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
42366         U>= IF                  \
42367             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
42368         THEN                    \
42369     THEN                        \
42370 THEN                            \
42371 RETI                            \ CPU is ON, GIE is OFF
42372 ENDASM                          \
42373     \
42374
42375
42376 \ ------------------------------\
42377 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
42378 \ ******************************\
42379 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
42380 \ ******************************\
42381 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
42382 \                               \       SMclock = 8|16|24 MHz
42383 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
42384 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
42385 \                               \       SR(9)=new Toggle bit memory (ADD on)
42386 \ ------------------------------\
42387 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
42388 \ ------------------------------\
42389 \ define LPM mode for ACCEPT    \
42390 \ ------------------------------\
42391 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
42392 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
42393 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
42394 \ ------------------------------\
42395 \ RC5_FirstStartBitHalfCycle:   \
42396 \ ------------------------------\
42397 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
42398 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
42399 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
42400 MOV     #1778,X                 \ RC5_Period in us
42401 MOV     #14,W                   \ count of loop
42402 BEGIN                           \
42403 \ ------------------------------\
42404 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
42405 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
42406     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
42407 \ RC5_Compute_3/4_Period:       \                   |
42408     RRUM    #1,X                \ X=1/2 cycle       |
42409     MOV     X,Y                 \ Y=1/2             ^
42410     RRUM    #1,Y                \ Y=1/4
42411     ADD     X,Y                 \ Y=3/4
42412 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
42413     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
42414     0= UNTIL                    \
42415 \ ------------------------------\
42416 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
42417 \ ------------------------------\
42418     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
42419     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
42420     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
42421     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
42422     SUB     #1,W                \ decrement count loop
42423 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
42424 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
42425 0<> WHILE                       \ ----> out of loop ----+
42426 \ RC5_compute_7/4_Time_out:     \                       |
42427     ADD     X,Y                 \                       |   out of bound = 7/4 period 
42428 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
42429     BEGIN                       \                       |
42430         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
42431         0>= IF                  \                       |   if cycle time out of bound
42432             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
42433             RETI                \                       |   then quit to do nothing
42434         THEN                    \                       |
42435 \ ------------------------------\                       |
42436         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
42437     0<> UNTIL                   \                   |   |
42438     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
42439 REPEAT                          \ ----> loop back --+   |
42440 \ ------------------------------\                       |
42441 \ RC5_SampleEndOf:              \ <---------------------+
42442 \ ------------------------------\
42443 BIC     #$30,&TA0CTL           \ stop timer_A0
42444 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
42445 \ ******************************\
42446 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
42447 \ ******************************\
42448 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
42449 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
42450 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
42451 BIT     #BIT13,X                \ X(13) = New_RC5_command
42452 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
42453 THEN                            \
42454 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
42455 \ ******************************\
42456 \ RC5_ComputeNewRC5word         \
42457 \ ******************************\
42458 SUB     #4,PSP                  \
42459 MOV     &BASE,2(PSP)            \ save variable BASE before use
42460 MOV     TOS,0(PSP)              \ save TOS before use
42461 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
42462 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
42463 \ ******************************\
42464 \ RC5_ComputeC6bit              \
42465 \ ******************************\
42466 BIT     #$4000,IP              \ test /C6 bit in IP
42467 0= IF   BIS #$40,TOS           \ set C6 bit in S
42468 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
42469 \ ******************************\
42470 \ RC5_CommandByteIsDone         \ RC5_code --
42471 \ ******************************\
42472
42473 \ ------------------------------\
42474 \ Display IR_RC5 code           \
42475 \ ------------------------------\
42476 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
42477 \ ------------------------------\
42478 LO2HI                           \ switch from assembler to FORTH
42479     ['] LCD_CLEAR IS CR         \ redirects CR
42480     ['] LCD_WrC  IS EMIT        \ redirects EMIT
42481     $10 BASE !                 \ change BASE to hexadecimal
42482     CR ." $" 2 U.R             \ print IR_RC5 code
42483     ['] (CR) IS CR              \ restore CR
42484     ['] (EMIT) IS EMIT          \ restore EMIT
42485 HI2LO                           \ switch from FORTH to assembler
42486 \ ------------------------------\
42487 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
42488 \ ------------------------------\
42489 MOV @PSP+,&BASE                 \ restore variable BASE
42490 RETI                            \ CPU is ON, GIE is OFF
42491 ENDASM                          \
42492     \ 
42493
42494 CODE START                      \
42495 \ ------------------------------\
42496 \ TB0CTL = %0000 0010 1001 0100\$3C0
42497 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
42498 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
42499 \                      --       \ID input divider \ 10 = /4
42500 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
42501 \                            -  \TBCLR TimerB Clear
42502 \                             - \TBIE
42503 \                              -\TBIFG
42504 \ --------------------------------\\
42505 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
42506 \              --                 \CM Capture Mode
42507 \                --               \CCIS
42508 \                   -             \SCS
42509 \                    --           \CLLD
42510 \                      -          \CAP
42511 \                        ---      \OUTMOD \ 011 = set/reset
42512 \                           -     \CCIE
42513 \                             -   \CCI
42514 \                              -  \OUT
42515 \                               - \COV
42516 \                                -\CCIFG
42517 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
42518 \ TB0EX0                          \$3E0 
42519 \ ------------------------------\
42520 \ set TimerB to make 50kHz PWM  \
42521 \ ------------------------------\
42522 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
42523 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
42524 \ ------------------------------\
42525 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
42526 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
42527 \ ------------------------------\
42528     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
42529     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
42530 \ ------------------------------\
42531 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
42532 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
42533 \ ------------------------------\
42534 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
42535 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
42536 \ ------------------------------\
42537     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
42538 \ ------------------------------\
42539 \ set TimerB to generate PWM for LCD_Vo
42540 \ ------------------------------\
42541     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
42542 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
42543     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
42544 \ ------------------------------\
42545     BIS.B #LCDVo,&LCDVo_DIR     \
42546     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
42547 \ ------------------------------\
42548     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
42549     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
42550 \ ------------------------------\
42551     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
42552     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
42553 \ ------------------------------\
42554 \ WDT interval init part        \
42555 \ ------------------------------\
42556     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
42557 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
42558 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
42559     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
42560 \ ------------------------------\
42561 \ init RC5_Int                  \
42562 \ ------------------------------\
42563     BIS.B #RC5,&IR_IE           \ enable RC5_Int
42564     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
42565 \ ------------------------------\
42566 \ init interrupt vectors
42567 \ ------------------------------\
42568     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
42569     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
42570 \ ------------------------------\
42571 \ define LPM mode for ACCEPT    \
42572 \ ------------------------------\
42573 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
42574 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
42575 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
42576
42577 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
42578
42579 \ ------------------------------\
42580 \ Init LCD 2x20                 \
42581 \ ------------------------------\
42582     $03E8 20_US                \ 1-  wait 20 ms
42583     $03 TOP_LCD                \ 2- send DB5=DB4=1
42584     $CD 20_US                  \ 3- wait 4,1 ms
42585     $03 TOP_LCD                \ 4- send again DB5=DB4=1
42586     $5 20_US                   \ 5- wait 0,1 ms
42587     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
42588     $2 20_US                   \    wait 40 us = LCD cycle
42589     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
42590     $2 20_US                   \    wait 40 us = LCD cycle
42591     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
42592     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
42593     LCD_Clear                   \ 10- "LCD_Clear"
42594     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
42595     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
42596     LCD_Clear                   \ 10- "LCD_Clear"
42597     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
42598     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
42599     CR ." I love you"   
42600     ['] (CR) IS CR              \ ' (CR) is CR
42601     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
42602     CR
42603     ."    RC5toLCD is running. Type STOP to quit"
42604 \    NOECHO                      \ uncomment to run this app without terminal connexion
42605     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
42606     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
42607 ;
42608     \
42609
42610 : STOP                  \ stops multitasking, must to be used before downloading app
42611     ['] (WARM) IS WARM  \ remove START app from FORTH init process
42612     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
42613 ;
42614     \
42615
42616
42617 RST_STATE   ;
42618
42619
42620 CODE MAX    \    n1 n2 -- n3       signed maximum
42621             CMP     @PSP,TOS    \ n2-n1
42622             S<      ?GOTO FW1   \ n2<n1
42623 BW1         ADD     #2,PSP
42624             MOV     @IP+,PC
42625 ENDCODE
42626     \
42627
42628 CODE MIN    \    n1 n2 -- n3       signed minimum
42629             CMP     @PSP,TOS     \ n2-n1
42630             S<      ?GOTO BW1    \ n2<n1
42631 FW1         MOV     @PSP+,TOS
42632             MOV     @IP+,PC
42633 ENDCODE
42634     \
42635
42636 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
42637   >R  <# 0 # #S #>  
42638   R> OVER - 0 MAX SPACES TYPE
42639 ;
42640     \
42641
42642 CODE 20_US                      \ n --      n * 20 us
42643 BEGIN                           \ 3 cycles loop + 6~  
42644 \    MOV     #5,W                \ 3 MCLK = 1 MHz
42645 \    MOV     #23,W               \ 3 MCLK = 4 MHz
42646     MOV     #51,W               \ 3 MCLK = 8 MHz
42647 \    MOV     #104,W              \ 3 MCLK = 16 MHz
42648 \    MOV     #158,W              \ 3 MCLK = 24 MHz
42649     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
42650         SUB #1,W                \ 1
42651     0= UNTIL                    \ 2
42652     SUB     #1,TOS              \ 1
42653 0= UNTIL                        \ 2
42654     MOV     @PSP+,TOS           \ 2
42655     MOV     @IP+,PC             \ 4
42656 ENDCODE
42657     \
42658
42659 CODE TOP_LCD                    \ LCD Sample
42660 \                               \ if write : %xxxxWWWW --
42661 \                               \ if read  : -- %0000RRRR
42662     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
42663     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
42664 0= IF                           \ write LCD bits pattern
42665     AND.B #LCD_DB,TOS           \ 
42666     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
42667     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
42668     MOV @PSP+,TOS               \
42669     MOV @IP+,PC
42670 THEN                            \ read LCD bits pattern
42671     SUB #2,PSP
42672     MOV TOS,0(PSP)
42673     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
42674     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
42675     AND.B #LCD_DB,TOS           \
42676     MOV @IP+,PC
42677 ENDCODE
42678     \
42679
42680 CODE LCD_W                      \ byte --       write byte to LCD 
42681     SUB #2,PSP                  \
42682     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
42683     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
42684     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
42685     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
42686 COLON                           \ high level word starts here 
42687     TOP_LCD 2 20_US             \ write high nibble first
42688     TOP_LCD 2 20_US 
42689 ;
42690     \
42691
42692 CODE LCD_WrC                    \ char --         Write Char
42693     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
42694     JMP LCD_W 
42695 ENDCODE
42696     \
42697
42698 CODE LCD_WrF                    \ func --         Write Fonction
42699     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
42700     JMP LCD_W 
42701 ENDCODE
42702     \
42703
42704 : LCD_Clear 
42705     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
42706 ;
42707     \
42708
42709 : LCD_Home 
42710     $02 LCD_WrF 100 20_us 
42711 ;
42712     \
42713
42714 \ : LCD_Entry_set       $04 OR LCD_WrF ;
42715
42716 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
42717
42718 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
42719
42720 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
42721
42722 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
42723
42724 \ : LCD_Goto            $80 OR LCD_WrF ;
42725
42726 \ CODE LCD_R                      \ -- byte       read byte from LCD
42727 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
42728 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
42729 \ COLON                           \ starts a FORTH word
42730 \     TOP_LCD 2 20_us             \ -- %0000HHHH
42731 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
42732 \ HI2LO                           \ switch from FORTH to assembler
42733 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
42734 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
42735 \     MOV @RSP+,IP                \ restore IP saved by COLON
42736 \     MOV @IP+,PC                 \
42737 \ ENDCODE
42738 \     \
42739
42740 \ CODE LCD_RdS                    \ -- status       Read Status
42741 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
42742 \     JMP LCD_R
42743 \ ENDCODE
42744 \     \
42745
42746 \ CODE LCD_RdC                    \ -- char         Read Char
42747 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
42748 \     JMP LCD_R
42749 \ ENDCODE
42750 \     \
42751
42752 \ -------------+------+------+------+------++---+---+---+---+---------+
42753 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
42754 \ -------------+------+------+------+------++---+---+---+---+---------+
42755 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
42756 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
42757 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
42758 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
42759 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
42760 \ -------------+------+------+------+------++---+---+---+---+---------+
42761
42762
42763 \ ******************************\
42764 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
42765 \ ******************************\
42766 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
42767 \ ------------------------------\
42768 \ define LPM mode for ACCEPT    \
42769 \ ------------------------------\
42770 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
42771 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
42772 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
42773 BIT.B #SW2,&SW2_IN              \ test switch S2
42774 0= IF                           \ case of switch S2 pressed
42775     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
42776     U< IF
42777         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
42778     THEN
42779 ELSE
42780     BIT.B #SW1,&SW1_IN          \ test switch S1 input
42781     0= IF                       \ case of Switch S1 pressed
42782         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
42783         U>= IF                  \
42784             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
42785         THEN                    \
42786     THEN                        \
42787 THEN                            \
42788 RETI                            \ CPU is ON, GIE is OFF
42789 ENDASM                          \
42790     \
42791
42792
42793 \ ------------------------------\
42794 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
42795 \ ******************************\
42796 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
42797 \ ******************************\
42798 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
42799 \                               \       SMclock = 8|16|24 MHz
42800 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
42801 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
42802 \                               \       SR(9)=new Toggle bit memory (ADD on)
42803 \ ------------------------------\
42804 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
42805 \ ------------------------------\
42806 \ define LPM mode for ACCEPT    \
42807 \ ------------------------------\
42808 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
42809 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
42810 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
42811 \ ------------------------------\
42812 \ RC5_FirstStartBitHalfCycle:   \
42813 \ ------------------------------\
42814 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
42815 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
42816 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
42817 MOV     #1778,X                 \ RC5_Period in us
42818 MOV     #14,W                   \ count of loop
42819 BEGIN                           \
42820 \ ------------------------------\
42821 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
42822 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
42823     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
42824 \ RC5_Compute_3/4_Period:       \                   |
42825     RRUM    #1,X                \ X=1/2 cycle       |
42826     MOV     X,Y                 \ Y=1/2             ^
42827     RRUM    #1,Y                \ Y=1/4
42828     ADD     X,Y                 \ Y=3/4
42829 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
42830     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
42831     0= UNTIL                    \
42832 \ ------------------------------\
42833 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
42834 \ ------------------------------\
42835     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
42836     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
42837     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
42838     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
42839     SUB     #1,W                \ decrement count loop
42840 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
42841 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
42842 0<> WHILE                       \ ----> out of loop ----+
42843 \ RC5_compute_7/4_Time_out:     \                       |
42844     ADD     X,Y                 \                       |   out of bound = 7/4 period 
42845 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
42846     BEGIN                       \                       |
42847         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
42848         0>= IF                  \                       |   if cycle time out of bound
42849             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
42850             RETI                \                       |   then quit to do nothing
42851         THEN                    \                       |
42852 \ ------------------------------\                       |
42853         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
42854     0<> UNTIL                   \                   |   |
42855     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
42856 REPEAT                          \ ----> loop back --+   |
42857 \ ------------------------------\                       |
42858 \ RC5_SampleEndOf:              \ <---------------------+
42859 \ ------------------------------\
42860 BIC     #$30,&TA0CTL           \ stop timer_A0
42861 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
42862 \ ******************************\
42863 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
42864 \ ******************************\
42865 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
42866 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
42867 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
42868 BIT     #BIT13,X                \ X(13) = New_RC5_command
42869 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
42870 THEN                            \
42871 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
42872 \ ******************************\
42873 \ RC5_ComputeNewRC5word         \
42874 \ ******************************\
42875 SUB     #4,PSP                  \
42876 MOV     &BASE,2(PSP)            \ save variable BASE before use
42877 MOV     TOS,0(PSP)              \ save TOS before use
42878 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
42879 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
42880 \ ******************************\
42881 \ RC5_ComputeC6bit              \
42882 \ ******************************\
42883 BIT     #$4000,IP              \ test /C6 bit in IP
42884 0= IF   BIS #$40,TOS           \ set C6 bit in S
42885 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
42886 \ ******************************\
42887 \ RC5_CommandByteIsDone         \ RC5_code --
42888 \ ******************************\
42889
42890 \ ------------------------------\
42891 \ Display IR_RC5 code           \
42892 \ ------------------------------\
42893 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
42894 \ ------------------------------\
42895 LO2HI                           \ switch from assembler to FORTH
42896     ['] LCD_CLEAR IS CR         \ redirects CR
42897     ['] LCD_WrC  IS EMIT        \ redirects EMIT
42898     $10 BASE !                 \ change BASE to hexadecimal
42899     CR ." $" 2 U.R             \ print IR_RC5 code
42900     ['] (CR) IS CR              \ restore CR
42901     ['] (EMIT) IS EMIT          \ restore EMIT
42902 HI2LO                           \ switch from FORTH to assembler
42903 \ ------------------------------\
42904 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
42905 \ ------------------------------\
42906 MOV @PSP+,&BASE                 \ restore variable BASE
42907 RETI                            \ CPU is ON, GIE is OFF
42908 ENDASM                          \
42909     \ 
42910
42911 CODE START                      \
42912 \ ------------------------------\
42913 \ TB0CTL = %0000 0010 1001 0100\$3C0
42914 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
42915 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
42916 \                      --       \ID input divider \ 10 = /4
42917 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
42918 \                            -  \TBCLR TimerB Clear
42919 \                             - \TBIE
42920 \                              -\TBIFG
42921 \ --------------------------------\\
42922 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
42923 \              --                 \CM Capture Mode
42924 \                --               \CCIS
42925 \                   -             \SCS
42926 \                    --           \CLLD
42927 \                      -          \CAP
42928 \                        ---      \OUTMOD \ 011 = set/reset
42929 \                           -     \CCIE
42930 \                             -   \CCI
42931 \                              -  \OUT
42932 \                               - \COV
42933 \                                -\CCIFG
42934 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
42935 \ TB0EX0                          \$3E0 
42936 \ ------------------------------\
42937 \ set TimerB to make 50kHz PWM  \
42938 \ ------------------------------\
42939 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
42940 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
42941 \ ------------------------------\
42942 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
42943 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
42944 \ ------------------------------\
42945     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
42946     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
42947 \ ------------------------------\
42948 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
42949 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
42950 \ ------------------------------\
42951 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
42952 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
42953 \ ------------------------------\
42954     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
42955 \ ------------------------------\
42956 \ set TimerB to generate PWM for LCD_Vo
42957 \ ------------------------------\
42958     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
42959 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
42960     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
42961 \ ------------------------------\
42962     BIS.B #LCDVo,&LCDVo_DIR     \
42963     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
42964 \ ------------------------------\
42965     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
42966     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
42967 \ ------------------------------\
42968     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
42969     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
42970 \ ------------------------------\
42971 \ WDT interval init part        \
42972 \ ------------------------------\
42973     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
42974 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
42975 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
42976     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
42977 \ ------------------------------\
42978 \ init RC5_Int                  \
42979 \ ------------------------------\
42980     BIS.B #RC5,&IR_IE           \ enable RC5_Int
42981     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
42982 \ ------------------------------\
42983 \ init interrupt vectors
42984 \ ------------------------------\
42985     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
42986     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
42987 \ ------------------------------\
42988 \ define LPM mode for ACCEPT    \
42989 \ ------------------------------\
42990 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
42991 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
42992 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
42993
42994 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
42995
42996 \ ------------------------------\
42997 \ Init LCD 2x20                 \
42998 \ ------------------------------\
42999     $03E8 20_US                \ 1-  wait 20 ms
43000     $03 TOP_LCD                \ 2- send DB5=DB4=1
43001     $CD 20_US                  \ 3- wait 4,1 ms
43002     $03 TOP_LCD                \ 4- send again DB5=DB4=1
43003     $5 20_US                   \ 5- wait 0,1 ms
43004     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
43005     $2 20_US                   \    wait 40 us = LCD cycle
43006     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
43007     $2 20_US                   \    wait 40 us = LCD cycle
43008     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
43009     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
43010     LCD_Clear                   \ 10- "LCD_Clear"
43011     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
43012     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
43013     LCD_Clear                   \ 10- "LCD_Clear"
43014     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
43015     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
43016     CR ." I love you"   
43017     ['] (CR) IS CR              \ ' (CR) is CR
43018     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
43019     CR
43020     ."    RC5toLCD is running. Type STOP to quit"
43021 \    NOECHO                      \ uncomment to run this app without terminal connexion
43022     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
43023     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
43024 ;
43025     \
43026
43027 : STOP                  \ stops multitasking, must to be used before downloading app
43028     ['] (WARM) IS WARM  \ remove START app from FORTH init process
43029     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
43030 ;
43031     \
43032
43033
43034 RST_STATE   ;
43035
43036
43037 CODE MAX    \    n1 n2 -- n3       signed maximum
43038             CMP     @PSP,TOS    \ n2-n1
43039             S<      ?GOTO FW1   \ n2<n1
43040 BW1         ADD     #2,PSP
43041             MOV     @IP+,PC
43042 ENDCODE
43043     \
43044
43045 CODE MIN    \    n1 n2 -- n3       signed minimum
43046             CMP     @PSP,TOS     \ n2-n1
43047             S<      ?GOTO BW1    \ n2<n1
43048 FW1         MOV     @PSP+,TOS
43049             MOV     @IP+,PC
43050 ENDCODE
43051     \
43052
43053 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
43054   >R  <# 0 # #S #>  
43055   R> OVER - 0 MAX SPACES TYPE
43056 ;
43057     \
43058
43059 CODE 20_US                      \ n --      n * 20 us
43060 BEGIN                           \ 3 cycles loop + 6~  
43061 \    MOV     #5,W                \ 3 MCLK = 1 MHz
43062 \    MOV     #23,W               \ 3 MCLK = 4 MHz
43063     MOV     #51,W               \ 3 MCLK = 8 MHz
43064 \    MOV     #104,W              \ 3 MCLK = 16 MHz
43065 \    MOV     #158,W              \ 3 MCLK = 24 MHz
43066     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
43067         SUB #1,W                \ 1
43068     0= UNTIL                    \ 2
43069     SUB     #1,TOS              \ 1
43070 0= UNTIL                        \ 2
43071     MOV     @PSP+,TOS           \ 2
43072     MOV     @IP+,PC             \ 4
43073 ENDCODE
43074     \
43075
43076 CODE TOP_LCD                    \ LCD Sample
43077 \                               \ if write : %xxxxWWWW --
43078 \                               \ if read  : -- %0000RRRR
43079     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
43080     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
43081 0= IF                           \ write LCD bits pattern
43082     AND.B #LCD_DB,TOS           \ 
43083     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
43084     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
43085     MOV @PSP+,TOS               \
43086     MOV @IP+,PC
43087 THEN                            \ read LCD bits pattern
43088     SUB #2,PSP
43089     MOV TOS,0(PSP)
43090     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
43091     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
43092     AND.B #LCD_DB,TOS           \
43093     MOV @IP+,PC
43094 ENDCODE
43095     \
43096
43097 CODE LCD_W                      \ byte --       write byte to LCD 
43098     SUB #2,PSP                  \
43099     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
43100     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
43101     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
43102     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
43103 COLON                           \ high level word starts here 
43104     TOP_LCD 2 20_US             \ write high nibble first
43105     TOP_LCD 2 20_US 
43106 ;
43107     \
43108
43109 CODE LCD_WrC                    \ char --         Write Char
43110     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
43111     JMP LCD_W 
43112 ENDCODE
43113     \
43114
43115 CODE LCD_WrF                    \ func --         Write Fonction
43116     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
43117     JMP LCD_W 
43118 ENDCODE
43119     \
43120
43121 : LCD_Clear 
43122     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
43123 ;
43124     \
43125
43126 : LCD_Home 
43127     $02 LCD_WrF 100 20_us 
43128 ;
43129     \
43130
43131 \ : LCD_Entry_set       $04 OR LCD_WrF ;
43132
43133 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
43134
43135 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
43136
43137 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
43138
43139 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
43140
43141 \ : LCD_Goto            $80 OR LCD_WrF ;
43142
43143 \ CODE LCD_R                      \ -- byte       read byte from LCD
43144 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
43145 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
43146 \ COLON                           \ starts a FORTH word
43147 \     TOP_LCD 2 20_us             \ -- %0000HHHH
43148 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
43149 \ HI2LO                           \ switch from FORTH to assembler
43150 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
43151 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
43152 \     MOV @RSP+,IP                \ restore IP saved by COLON
43153 \     MOV @IP+,PC                 \
43154 \ ENDCODE
43155 \     \
43156
43157 \ CODE LCD_RdS                    \ -- status       Read Status
43158 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
43159 \     JMP LCD_R
43160 \ ENDCODE
43161 \     \
43162
43163 \ CODE LCD_RdC                    \ -- char         Read Char
43164 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
43165 \     JMP LCD_R
43166 \ ENDCODE
43167 \     \
43168
43169 \ -------------+------+------+------+------++---+---+---+---+---------+
43170 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
43171 \ -------------+------+------+------+------++---+---+---+---+---------+
43172 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
43173 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
43174 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
43175 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
43176 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
43177 \ -------------+------+------+------+------++---+---+---+---+---------+
43178
43179
43180 \ ******************************\
43181 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
43182 \ ******************************\
43183 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
43184 \ ------------------------------\
43185 \ define LPM mode for ACCEPT    \
43186 \ ------------------------------\
43187 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
43188 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
43189 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
43190 BIT.B #SW2,&SW2_IN              \ test switch S2
43191 0= IF                           \ case of switch S2 pressed
43192     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
43193     U< IF
43194         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
43195     THEN
43196 ELSE
43197     BIT.B #SW1,&SW1_IN          \ test switch S1 input
43198     0= IF                       \ case of Switch S1 pressed
43199         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
43200         U>= IF                  \
43201             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
43202         THEN                    \
43203     THEN                        \
43204 THEN                            \
43205 RETI                            \ CPU is ON, GIE is OFF
43206 ENDASM                          \
43207     \
43208
43209
43210 \ ------------------------------\
43211 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
43212 \ ******************************\
43213 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
43214 \ ******************************\
43215 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
43216 \                               \       SMclock = 8|16|24 MHz
43217 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
43218 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
43219 \                               \       SR(9)=new Toggle bit memory (ADD on)
43220 \ ------------------------------\
43221 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
43222 \ ------------------------------\
43223 \ define LPM mode for ACCEPT    \
43224 \ ------------------------------\
43225 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
43226 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
43227 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
43228 \ ------------------------------\
43229 \ RC5_FirstStartBitHalfCycle:   \
43230 \ ------------------------------\
43231 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
43232 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
43233 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
43234 MOV     #1778,X                 \ RC5_Period in us
43235 MOV     #14,W                   \ count of loop
43236 BEGIN                           \
43237 \ ------------------------------\
43238 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
43239 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
43240     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
43241 \ RC5_Compute_3/4_Period:       \                   |
43242     RRUM    #1,X                \ X=1/2 cycle       |
43243     MOV     X,Y                 \ Y=1/2             ^
43244     RRUM    #1,Y                \ Y=1/4
43245     ADD     X,Y                 \ Y=3/4
43246 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
43247     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
43248     0= UNTIL                    \
43249 \ ------------------------------\
43250 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
43251 \ ------------------------------\
43252     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
43253     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
43254     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
43255     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
43256     SUB     #1,W                \ decrement count loop
43257 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
43258 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
43259 0<> WHILE                       \ ----> out of loop ----+
43260 \ RC5_compute_7/4_Time_out:     \                       |
43261     ADD     X,Y                 \                       |   out of bound = 7/4 period 
43262 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
43263     BEGIN                       \                       |
43264         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
43265         0>= IF                  \                       |   if cycle time out of bound
43266             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
43267             RETI                \                       |   then quit to do nothing
43268         THEN                    \                       |
43269 \ ------------------------------\                       |
43270         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
43271     0<> UNTIL                   \                   |   |
43272     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
43273 REPEAT                          \ ----> loop back --+   |
43274 \ ------------------------------\                       |
43275 \ RC5_SampleEndOf:              \ <---------------------+
43276 \ ------------------------------\
43277 BIC     #$30,&TA0CTL           \ stop timer_A0
43278 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
43279 \ ******************************\
43280 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
43281 \ ******************************\
43282 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
43283 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
43284 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
43285 BIT     #BIT13,X                \ X(13) = New_RC5_command
43286 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
43287 THEN                            \
43288 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
43289 \ ******************************\
43290 \ RC5_ComputeNewRC5word         \
43291 \ ******************************\
43292 SUB     #4,PSP                  \
43293 MOV     &BASE,2(PSP)            \ save variable BASE before use
43294 MOV     TOS,0(PSP)              \ save TOS before use
43295 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
43296 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
43297 \ ******************************\
43298 \ RC5_ComputeC6bit              \
43299 \ ******************************\
43300 BIT     #$4000,IP              \ test /C6 bit in IP
43301 0= IF   BIS #$40,TOS           \ set C6 bit in S
43302 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
43303 \ ******************************\
43304 \ RC5_CommandByteIsDone         \ RC5_code --
43305 \ ******************************\
43306
43307 \ ------------------------------\
43308 \ Display IR_RC5 code           \
43309 \ ------------------------------\
43310 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
43311 \ ------------------------------\
43312 LO2HI                           \ switch from assembler to FORTH
43313     ['] LCD_CLEAR IS CR         \ redirects CR
43314     ['] LCD_WrC  IS EMIT        \ redirects EMIT
43315     $10 BASE !                 \ change BASE to hexadecimal
43316     CR ." $" 2 U.R             \ print IR_RC5 code
43317     ['] (CR) IS CR              \ restore CR
43318     ['] (EMIT) IS EMIT          \ restore EMIT
43319 HI2LO                           \ switch from FORTH to assembler
43320 \ ------------------------------\
43321 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
43322 \ ------------------------------\
43323 MOV @PSP+,&BASE                 \ restore variable BASE
43324 RETI                            \ CPU is ON, GIE is OFF
43325 ENDASM                          \
43326     \ 
43327
43328 CODE START                      \
43329 \ ------------------------------\
43330 \ TB0CTL = %0000 0010 1001 0100\$3C0
43331 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
43332 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
43333 \                      --       \ID input divider \ 10 = /4
43334 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
43335 \                            -  \TBCLR TimerB Clear
43336 \                             - \TBIE
43337 \                              -\TBIFG
43338 \ --------------------------------\\
43339 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
43340 \              --                 \CM Capture Mode
43341 \                --               \CCIS
43342 \                   -             \SCS
43343 \                    --           \CLLD
43344 \                      -          \CAP
43345 \                        ---      \OUTMOD \ 011 = set/reset
43346 \                           -     \CCIE
43347 \                             -   \CCI
43348 \                              -  \OUT
43349 \                               - \COV
43350 \                                -\CCIFG
43351 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
43352 \ TB0EX0                          \$3E0 
43353 \ ------------------------------\
43354 \ set TimerB to make 50kHz PWM  \
43355 \ ------------------------------\
43356 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
43357 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
43358 \ ------------------------------\
43359 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
43360 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
43361 \ ------------------------------\
43362     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
43363     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
43364 \ ------------------------------\
43365 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
43366 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
43367 \ ------------------------------\
43368 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
43369 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
43370 \ ------------------------------\
43371     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
43372 \ ------------------------------\
43373 \ set TimerB to generate PWM for LCD_Vo
43374 \ ------------------------------\
43375     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
43376 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
43377     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
43378 \ ------------------------------\
43379     BIS.B #LCDVo,&LCDVo_DIR     \
43380     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
43381 \ ------------------------------\
43382     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
43383     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
43384 \ ------------------------------\
43385     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
43386     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
43387 \ ------------------------------\
43388 \ WDT interval init part        \
43389 \ ------------------------------\
43390     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
43391 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
43392 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
43393     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
43394 \ ------------------------------\
43395 \ init RC5_Int                  \
43396 \ ------------------------------\
43397     BIS.B #RC5,&IR_IE           \ enable RC5_Int
43398     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
43399 \ ------------------------------\
43400 \ init interrupt vectors
43401 \ ------------------------------\
43402     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
43403     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
43404 \ ------------------------------\
43405 \ define LPM mode for ACCEPT    \
43406 \ ------------------------------\
43407 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
43408 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
43409 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
43410
43411 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
43412
43413 \ ------------------------------\
43414 \ Init LCD 2x20                 \
43415 \ ------------------------------\
43416     $03E8 20_US                \ 1-  wait 20 ms
43417     $03 TOP_LCD                \ 2- send DB5=DB4=1
43418     $CD 20_US                  \ 3- wait 4,1 ms
43419     $03 TOP_LCD                \ 4- send again DB5=DB4=1
43420     $5 20_US                   \ 5- wait 0,1 ms
43421     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
43422     $2 20_US                   \    wait 40 us = LCD cycle
43423     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
43424     $2 20_US                   \    wait 40 us = LCD cycle
43425     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
43426     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
43427     LCD_Clear                   \ 10- "LCD_Clear"
43428     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
43429     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
43430     LCD_Clear                   \ 10- "LCD_Clear"
43431     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
43432     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
43433     CR ." I love you"   
43434     ['] (CR) IS CR              \ ' (CR) is CR
43435     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
43436     CR
43437     ."    RC5toLCD is running. Type STOP to quit"
43438 \    NOECHO                      \ uncomment to run this app without terminal connexion
43439     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
43440     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
43441 ;
43442     \
43443
43444 : STOP                  \ stops multitasking, must to be used before downloading app
43445     ['] (WARM) IS WARM  \ remove START app from FORTH init process
43446     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
43447 ;
43448     \
43449
43450
43451 RST_STATE   ;
43452
43453
43454 CODE MAX    \    n1 n2 -- n3       signed maximum
43455             CMP     @PSP,TOS    \ n2-n1
43456             S<      ?GOTO FW1   \ n2<n1
43457 BW1         ADD     #2,PSP
43458             MOV     @IP+,PC
43459 ENDCODE
43460     \
43461
43462 CODE MIN    \    n1 n2 -- n3       signed minimum
43463             CMP     @PSP,TOS     \ n2-n1
43464             S<      ?GOTO BW1    \ n2<n1
43465 FW1         MOV     @PSP+,TOS
43466             MOV     @IP+,PC
43467 ENDCODE
43468     \
43469
43470 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
43471   >R  <# 0 # #S #>  
43472   R> OVER - 0 MAX SPACES TYPE
43473 ;
43474     \
43475
43476 CODE 20_US                      \ n --      n * 20 us
43477 BEGIN                           \ 3 cycles loop + 6~  
43478 \    MOV     #5,W                \ 3 MCLK = 1 MHz
43479 \    MOV     #23,W               \ 3 MCLK = 4 MHz
43480     MOV     #51,W               \ 3 MCLK = 8 MHz
43481 \    MOV     #104,W              \ 3 MCLK = 16 MHz
43482 \    MOV     #158,W              \ 3 MCLK = 24 MHz
43483     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
43484         SUB #1,W                \ 1
43485     0= UNTIL                    \ 2
43486     SUB     #1,TOS              \ 1
43487 0= UNTIL                        \ 2
43488     MOV     @PSP+,TOS           \ 2
43489     MOV     @IP+,PC             \ 4
43490 ENDCODE
43491     \
43492
43493 CODE TOP_LCD                    \ LCD Sample
43494 \                               \ if write : %xxxxWWWW --
43495 \                               \ if read  : -- %0000RRRR
43496     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
43497     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
43498 0= IF                           \ write LCD bits pattern
43499     AND.B #LCD_DB,TOS           \ 
43500     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
43501     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
43502     MOV @PSP+,TOS               \
43503     MOV @IP+,PC
43504 THEN                            \ read LCD bits pattern
43505     SUB #2,PSP
43506     MOV TOS,0(PSP)
43507     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
43508     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
43509     AND.B #LCD_DB,TOS           \
43510     MOV @IP+,PC
43511 ENDCODE
43512     \
43513
43514 CODE LCD_W                      \ byte --       write byte to LCD 
43515     SUB #2,PSP                  \
43516     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
43517     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
43518     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
43519     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
43520 COLON                           \ high level word starts here 
43521     TOP_LCD 2 20_US             \ write high nibble first
43522     TOP_LCD 2 20_US 
43523 ;
43524     \
43525
43526 CODE LCD_WrC                    \ char --         Write Char
43527     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
43528     JMP LCD_W 
43529 ENDCODE
43530     \
43531
43532 CODE LCD_WrF                    \ func --         Write Fonction
43533     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
43534     JMP LCD_W 
43535 ENDCODE
43536     \
43537
43538 : LCD_Clear 
43539     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
43540 ;
43541     \
43542
43543 : LCD_Home 
43544     $02 LCD_WrF 100 20_us 
43545 ;
43546     \
43547
43548 \ : LCD_Entry_set       $04 OR LCD_WrF ;
43549
43550 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
43551
43552 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
43553
43554 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
43555
43556 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
43557
43558 \ : LCD_Goto            $80 OR LCD_WrF ;
43559
43560 \ CODE LCD_R                      \ -- byte       read byte from LCD
43561 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
43562 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
43563 \ COLON                           \ starts a FORTH word
43564 \     TOP_LCD 2 20_us             \ -- %0000HHHH
43565 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
43566 \ HI2LO                           \ switch from FORTH to assembler
43567 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
43568 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
43569 \     MOV @RSP+,IP                \ restore IP saved by COLON
43570 \     MOV @IP+,PC                 \
43571 \ ENDCODE
43572 \     \
43573
43574 \ CODE LCD_RdS                    \ -- status       Read Status
43575 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
43576 \     JMP LCD_R
43577 \ ENDCODE
43578 \     \
43579
43580 \ CODE LCD_RdC                    \ -- char         Read Char
43581 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
43582 \     JMP LCD_R
43583 \ ENDCODE
43584 \     \
43585
43586 \ -------------+------+------+------+------++---+---+---+---+---------+
43587 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
43588 \ -------------+------+------+------+------++---+---+---+---+---------+
43589 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
43590 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
43591 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
43592 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
43593 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
43594 \ -------------+------+------+------+------++---+---+---+---+---------+
43595
43596
43597 \ ******************************\
43598 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
43599 \ ******************************\
43600 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
43601 \ ------------------------------\
43602 \ define LPM mode for ACCEPT    \
43603 \ ------------------------------\
43604 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
43605 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
43606 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
43607 BIT.B #SW2,&SW2_IN              \ test switch S2
43608 0= IF                           \ case of switch S2 pressed
43609     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
43610     U< IF
43611         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
43612     THEN
43613 ELSE
43614     BIT.B #SW1,&SW1_IN          \ test switch S1 input
43615     0= IF                       \ case of Switch S1 pressed
43616         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
43617         U>= IF                  \
43618             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
43619         THEN                    \
43620     THEN                        \
43621 THEN                            \
43622 RETI                            \ CPU is ON, GIE is OFF
43623 ENDASM                          \
43624     \
43625
43626
43627 \ ------------------------------\
43628 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
43629 \ ******************************\
43630 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
43631 \ ******************************\
43632 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
43633 \                               \       SMclock = 8|16|24 MHz
43634 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
43635 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
43636 \                               \       SR(9)=new Toggle bit memory (ADD on)
43637 \ ------------------------------\
43638 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
43639 \ ------------------------------\
43640 \ define LPM mode for ACCEPT    \
43641 \ ------------------------------\
43642 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
43643 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
43644 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
43645 \ ------------------------------\
43646 \ RC5_FirstStartBitHalfCycle:   \
43647 \ ------------------------------\
43648 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
43649 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
43650 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
43651 MOV     #1778,X                 \ RC5_Period in us
43652 MOV     #14,W                   \ count of loop
43653 BEGIN                           \
43654 \ ------------------------------\
43655 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
43656 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
43657     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
43658 \ RC5_Compute_3/4_Period:       \                   |
43659     RRUM    #1,X                \ X=1/2 cycle       |
43660     MOV     X,Y                 \ Y=1/2             ^
43661     RRUM    #1,Y                \ Y=1/4
43662     ADD     X,Y                 \ Y=3/4
43663 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
43664     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
43665     0= UNTIL                    \
43666 \ ------------------------------\
43667 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
43668 \ ------------------------------\
43669     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
43670     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
43671     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
43672     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
43673     SUB     #1,W                \ decrement count loop
43674 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
43675 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
43676 0<> WHILE                       \ ----> out of loop ----+
43677 \ RC5_compute_7/4_Time_out:     \                       |
43678     ADD     X,Y                 \                       |   out of bound = 7/4 period 
43679 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
43680     BEGIN                       \                       |
43681         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
43682         0>= IF                  \                       |   if cycle time out of bound
43683             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
43684             RETI                \                       |   then quit to do nothing
43685         THEN                    \                       |
43686 \ ------------------------------\                       |
43687         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
43688     0<> UNTIL                   \                   |   |
43689     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
43690 REPEAT                          \ ----> loop back --+   |
43691 \ ------------------------------\                       |
43692 \ RC5_SampleEndOf:              \ <---------------------+
43693 \ ------------------------------\
43694 BIC     #$30,&TA0CTL           \ stop timer_A0
43695 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
43696 \ ******************************\
43697 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
43698 \ ******************************\
43699 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
43700 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
43701 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
43702 BIT     #BIT13,X                \ X(13) = New_RC5_command
43703 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
43704 THEN                            \
43705 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
43706 \ ******************************\
43707 \ RC5_ComputeNewRC5word         \
43708 \ ******************************\
43709 SUB     #4,PSP                  \
43710 MOV     &BASE,2(PSP)            \ save variable BASE before use
43711 MOV     TOS,0(PSP)              \ save TOS before use
43712 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
43713 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
43714 \ ******************************\
43715 \ RC5_ComputeC6bit              \
43716 \ ******************************\
43717 BIT     #$4000,IP              \ test /C6 bit in IP
43718 0= IF   BIS #$40,TOS           \ set C6 bit in S
43719 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
43720 \ ******************************\
43721 \ RC5_CommandByteIsDone         \ RC5_code --
43722 \ ******************************\
43723
43724 \ ------------------------------\
43725 \ Display IR_RC5 code           \
43726 \ ------------------------------\
43727 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
43728 \ ------------------------------\
43729 LO2HI                           \ switch from assembler to FORTH
43730     ['] LCD_CLEAR IS CR         \ redirects CR
43731     ['] LCD_WrC  IS EMIT        \ redirects EMIT
43732     $10 BASE !                 \ change BASE to hexadecimal
43733     CR ." $" 2 U.R             \ print IR_RC5 code
43734     ['] (CR) IS CR              \ restore CR
43735     ['] (EMIT) IS EMIT          \ restore EMIT
43736 HI2LO                           \ switch from FORTH to assembler
43737 \ ------------------------------\
43738 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
43739 \ ------------------------------\
43740 MOV @PSP+,&BASE                 \ restore variable BASE
43741 RETI                            \ CPU is ON, GIE is OFF
43742 ENDASM                          \
43743     \ 
43744
43745 CODE START                      \
43746 \ ------------------------------\
43747 \ TB0CTL = %0000 0010 1001 0100\$3C0
43748 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
43749 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
43750 \                      --       \ID input divider \ 10 = /4
43751 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
43752 \                            -  \TBCLR TimerB Clear
43753 \                             - \TBIE
43754 \                              -\TBIFG
43755 \ --------------------------------\\
43756 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
43757 \              --                 \CM Capture Mode
43758 \                --               \CCIS
43759 \                   -             \SCS
43760 \                    --           \CLLD
43761 \                      -          \CAP
43762 \                        ---      \OUTMOD \ 011 = set/reset
43763 \                           -     \CCIE
43764 \                             -   \CCI
43765 \                              -  \OUT
43766 \                               - \COV
43767 \                                -\CCIFG
43768 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
43769 \ TB0EX0                          \$3E0 
43770 \ ------------------------------\
43771 \ set TimerB to make 50kHz PWM  \
43772 \ ------------------------------\
43773 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
43774 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
43775 \ ------------------------------\
43776 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
43777 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
43778 \ ------------------------------\
43779     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
43780     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
43781 \ ------------------------------\
43782 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
43783 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
43784 \ ------------------------------\
43785 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
43786 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
43787 \ ------------------------------\
43788     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
43789 \ ------------------------------\
43790 \ set TimerB to generate PWM for LCD_Vo
43791 \ ------------------------------\
43792     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
43793 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
43794     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
43795 \ ------------------------------\
43796     BIS.B #LCDVo,&LCDVo_DIR     \
43797     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
43798 \ ------------------------------\
43799     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
43800     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
43801 \ ------------------------------\
43802     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
43803     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
43804 \ ------------------------------\
43805 \ WDT interval init part        \
43806 \ ------------------------------\
43807     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
43808 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
43809 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
43810     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
43811 \ ------------------------------\
43812 \ init RC5_Int                  \
43813 \ ------------------------------\
43814     BIS.B #RC5,&IR_IE           \ enable RC5_Int
43815     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
43816 \ ------------------------------\
43817 \ init interrupt vectors
43818 \ ------------------------------\
43819     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
43820     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
43821 \ ------------------------------\
43822 \ define LPM mode for ACCEPT    \
43823 \ ------------------------------\
43824 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
43825 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
43826 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
43827
43828 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
43829
43830 \ ------------------------------\
43831 \ Init LCD 2x20                 \
43832 \ ------------------------------\
43833     $03E8 20_US                \ 1-  wait 20 ms
43834     $03 TOP_LCD                \ 2- send DB5=DB4=1
43835     $CD 20_US                  \ 3- wait 4,1 ms
43836     $03 TOP_LCD                \ 4- send again DB5=DB4=1
43837     $5 20_US                   \ 5- wait 0,1 ms
43838     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
43839     $2 20_US                   \    wait 40 us = LCD cycle
43840     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
43841     $2 20_US                   \    wait 40 us = LCD cycle
43842     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
43843     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
43844     LCD_Clear                   \ 10- "LCD_Clear"
43845     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
43846     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
43847     LCD_Clear                   \ 10- "LCD_Clear"
43848     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
43849     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
43850     CR ." I love you"   
43851     ['] (CR) IS CR              \ ' (CR) is CR
43852     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
43853     CR
43854     ."    RC5toLCD is running. Type STOP to quit"
43855 \    NOECHO                      \ uncomment to run this app without terminal connexion
43856     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
43857     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
43858 ;
43859     \
43860
43861 : STOP                  \ stops multitasking, must to be used before downloading app
43862     ['] (WARM) IS WARM  \ remove START app from FORTH init process
43863     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
43864 ;
43865     \
43866
43867
43868 RST_STATE   ;
43869
43870
43871 CODE MAX    \    n1 n2 -- n3       signed maximum
43872             CMP     @PSP,TOS    \ n2-n1
43873             S<      ?GOTO FW1   \ n2<n1
43874 BW1         ADD     #2,PSP
43875             MOV     @IP+,PC
43876 ENDCODE
43877     \
43878
43879 CODE MIN    \    n1 n2 -- n3       signed minimum
43880             CMP     @PSP,TOS     \ n2-n1
43881             S<      ?GOTO BW1    \ n2<n1
43882 FW1         MOV     @PSP+,TOS
43883             MOV     @IP+,PC
43884 ENDCODE
43885     \
43886
43887 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
43888   >R  <# 0 # #S #>  
43889   R> OVER - 0 MAX SPACES TYPE
43890 ;
43891     \
43892
43893 CODE 20_US                      \ n --      n * 20 us
43894 BEGIN                           \ 3 cycles loop + 6~  
43895 \    MOV     #5,W                \ 3 MCLK = 1 MHz
43896 \    MOV     #23,W               \ 3 MCLK = 4 MHz
43897     MOV     #51,W               \ 3 MCLK = 8 MHz
43898 \    MOV     #104,W              \ 3 MCLK = 16 MHz
43899 \    MOV     #158,W              \ 3 MCLK = 24 MHz
43900     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
43901         SUB #1,W                \ 1
43902     0= UNTIL                    \ 2
43903     SUB     #1,TOS              \ 1
43904 0= UNTIL                        \ 2
43905     MOV     @PSP+,TOS           \ 2
43906     MOV     @IP+,PC             \ 4
43907 ENDCODE
43908     \
43909
43910 CODE TOP_LCD                    \ LCD Sample
43911 \                               \ if write : %xxxxWWWW --
43912 \                               \ if read  : -- %0000RRRR
43913     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
43914     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
43915 0= IF                           \ write LCD bits pattern
43916     AND.B #LCD_DB,TOS           \ 
43917     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
43918     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
43919     MOV @PSP+,TOS               \
43920     MOV @IP+,PC
43921 THEN                            \ read LCD bits pattern
43922     SUB #2,PSP
43923     MOV TOS,0(PSP)
43924     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
43925     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
43926     AND.B #LCD_DB,TOS           \
43927     MOV @IP+,PC
43928 ENDCODE
43929     \
43930
43931 CODE LCD_W                      \ byte --       write byte to LCD 
43932     SUB #2,PSP                  \
43933     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
43934     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
43935     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
43936     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
43937 COLON                           \ high level word starts here 
43938     TOP_LCD 2 20_US             \ write high nibble first
43939     TOP_LCD 2 20_US 
43940 ;
43941     \
43942
43943 CODE LCD_WrC                    \ char --         Write Char
43944     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
43945     JMP LCD_W 
43946 ENDCODE
43947     \
43948
43949 CODE LCD_WrF                    \ func --         Write Fonction
43950     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
43951     JMP LCD_W 
43952 ENDCODE
43953     \
43954
43955 : LCD_Clear 
43956     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
43957 ;
43958     \
43959
43960 : LCD_Home 
43961     $02 LCD_WrF 100 20_us 
43962 ;
43963     \
43964
43965 \ : LCD_Entry_set       $04 OR LCD_WrF ;
43966
43967 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
43968
43969 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
43970
43971 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
43972
43973 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
43974
43975 \ : LCD_Goto            $80 OR LCD_WrF ;
43976
43977 \ CODE LCD_R                      \ -- byte       read byte from LCD
43978 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
43979 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
43980 \ COLON                           \ starts a FORTH word
43981 \     TOP_LCD 2 20_us             \ -- %0000HHHH
43982 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
43983 \ HI2LO                           \ switch from FORTH to assembler
43984 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
43985 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
43986 \     MOV @RSP+,IP                \ restore IP saved by COLON
43987 \     MOV @IP+,PC                 \
43988 \ ENDCODE
43989 \     \
43990
43991 \ CODE LCD_RdS                    \ -- status       Read Status
43992 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
43993 \     JMP LCD_R
43994 \ ENDCODE
43995 \     \
43996
43997 \ CODE LCD_RdC                    \ -- char         Read Char
43998 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
43999 \     JMP LCD_R
44000 \ ENDCODE
44001 \     \
44002
44003 \ -------------+------+------+------+------++---+---+---+---+---------+
44004 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
44005 \ -------------+------+------+------+------++---+---+---+---+---------+
44006 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
44007 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
44008 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
44009 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
44010 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
44011 \ -------------+------+------+------+------++---+---+---+---+---------+
44012
44013
44014 \ ******************************\
44015 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
44016 \ ******************************\
44017 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
44018 \ ------------------------------\
44019 \ define LPM mode for ACCEPT    \
44020 \ ------------------------------\
44021 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
44022 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
44023 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
44024 BIT.B #SW2,&SW2_IN              \ test switch S2
44025 0= IF                           \ case of switch S2 pressed
44026     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
44027     U< IF
44028         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
44029     THEN
44030 ELSE
44031     BIT.B #SW1,&SW1_IN          \ test switch S1 input
44032     0= IF                       \ case of Switch S1 pressed
44033         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
44034         U>= IF                  \
44035             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
44036         THEN                    \
44037     THEN                        \
44038 THEN                            \
44039 RETI                            \ CPU is ON, GIE is OFF
44040 ENDASM                          \
44041     \
44042
44043
44044 \ ------------------------------\
44045 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
44046 \ ******************************\
44047 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
44048 \ ******************************\
44049 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
44050 \                               \       SMclock = 8|16|24 MHz
44051 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
44052 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
44053 \                               \       SR(9)=new Toggle bit memory (ADD on)
44054 \ ------------------------------\
44055 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
44056 \ ------------------------------\
44057 \ define LPM mode for ACCEPT    \
44058 \ ------------------------------\
44059 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
44060 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
44061 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
44062 \ ------------------------------\
44063 \ RC5_FirstStartBitHalfCycle:   \
44064 \ ------------------------------\
44065 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
44066 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
44067 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
44068 MOV     #1778,X                 \ RC5_Period in us
44069 MOV     #14,W                   \ count of loop
44070 BEGIN                           \
44071 \ ------------------------------\
44072 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
44073 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
44074     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
44075 \ RC5_Compute_3/4_Period:       \                   |
44076     RRUM    #1,X                \ X=1/2 cycle       |
44077     MOV     X,Y                 \ Y=1/2             ^
44078     RRUM    #1,Y                \ Y=1/4
44079     ADD     X,Y                 \ Y=3/4
44080 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
44081     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
44082     0= UNTIL                    \
44083 \ ------------------------------\
44084 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
44085 \ ------------------------------\
44086     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
44087     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
44088     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
44089     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
44090     SUB     #1,W                \ decrement count loop
44091 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
44092 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
44093 0<> WHILE                       \ ----> out of loop ----+
44094 \ RC5_compute_7/4_Time_out:     \                       |
44095     ADD     X,Y                 \                       |   out of bound = 7/4 period 
44096 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
44097     BEGIN                       \                       |
44098         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
44099         0>= IF                  \                       |   if cycle time out of bound
44100             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
44101             RETI                \                       |   then quit to do nothing
44102         THEN                    \                       |
44103 \ ------------------------------\                       |
44104         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
44105     0<> UNTIL                   \                   |   |
44106     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
44107 REPEAT                          \ ----> loop back --+   |
44108 \ ------------------------------\                       |
44109 \ RC5_SampleEndOf:              \ <---------------------+
44110 \ ------------------------------\
44111 BIC     #$30,&TA0CTL           \ stop timer_A0
44112 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
44113 \ ******************************\
44114 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
44115 \ ******************************\
44116 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
44117 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
44118 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
44119 BIT     #BIT13,X                \ X(13) = New_RC5_command
44120 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
44121 THEN                            \
44122 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
44123 \ ******************************\
44124 \ RC5_ComputeNewRC5word         \
44125 \ ******************************\
44126 SUB     #4,PSP                  \
44127 MOV     &BASE,2(PSP)            \ save variable BASE before use
44128 MOV     TOS,0(PSP)              \ save TOS before use
44129 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
44130 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
44131 \ ******************************\
44132 \ RC5_ComputeC6bit              \
44133 \ ******************************\
44134 BIT     #$4000,IP              \ test /C6 bit in IP
44135 0= IF   BIS #$40,TOS           \ set C6 bit in S
44136 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
44137 \ ******************************\
44138 \ RC5_CommandByteIsDone         \ RC5_code --
44139 \ ******************************\
44140
44141 \ ------------------------------\
44142 \ Display IR_RC5 code           \
44143 \ ------------------------------\
44144 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
44145 \ ------------------------------\
44146 LO2HI                           \ switch from assembler to FORTH
44147     ['] LCD_CLEAR IS CR         \ redirects CR
44148     ['] LCD_WrC  IS EMIT        \ redirects EMIT
44149     $10 BASE !                 \ change BASE to hexadecimal
44150     CR ." $" 2 U.R             \ print IR_RC5 code
44151     ['] (CR) IS CR              \ restore CR
44152     ['] (EMIT) IS EMIT          \ restore EMIT
44153 HI2LO                           \ switch from FORTH to assembler
44154 \ ------------------------------\
44155 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
44156 \ ------------------------------\
44157 MOV @PSP+,&BASE                 \ restore variable BASE
44158 RETI                            \ CPU is ON, GIE is OFF
44159 ENDASM                          \
44160     \ 
44161
44162 CODE START                      \
44163 \ ------------------------------\
44164 \ TB0CTL = %0000 0010 1001 0100\$3C0
44165 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
44166 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
44167 \                      --       \ID input divider \ 10 = /4
44168 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
44169 \                            -  \TBCLR TimerB Clear
44170 \                             - \TBIE
44171 \                              -\TBIFG
44172 \ --------------------------------\\
44173 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
44174 \              --                 \CM Capture Mode
44175 \                --               \CCIS
44176 \                   -             \SCS
44177 \                    --           \CLLD
44178 \                      -          \CAP
44179 \                        ---      \OUTMOD \ 011 = set/reset
44180 \                           -     \CCIE
44181 \                             -   \CCI
44182 \                              -  \OUT
44183 \                               - \COV
44184 \                                -\CCIFG
44185 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
44186 \ TB0EX0                          \$3E0 
44187 \ ------------------------------\
44188 \ set TimerB to make 50kHz PWM  \
44189 \ ------------------------------\
44190 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
44191 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
44192 \ ------------------------------\
44193 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
44194 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
44195 \ ------------------------------\
44196     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
44197     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
44198 \ ------------------------------\
44199 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
44200 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
44201 \ ------------------------------\
44202 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
44203 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
44204 \ ------------------------------\
44205     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
44206 \ ------------------------------\
44207 \ set TimerB to generate PWM for LCD_Vo
44208 \ ------------------------------\
44209     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
44210 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
44211     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
44212 \ ------------------------------\
44213     BIS.B #LCDVo,&LCDVo_DIR     \
44214     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
44215 \ ------------------------------\
44216     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
44217     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
44218 \ ------------------------------\
44219     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
44220     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
44221 \ ------------------------------\
44222 \ WDT interval init part        \
44223 \ ------------------------------\
44224     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
44225 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
44226 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
44227     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
44228 \ ------------------------------\
44229 \ init RC5_Int                  \
44230 \ ------------------------------\
44231     BIS.B #RC5,&IR_IE           \ enable RC5_Int
44232     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
44233 \ ------------------------------\
44234 \ init interrupt vectors
44235 \ ------------------------------\
44236     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
44237     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
44238 \ ------------------------------\
44239 \ define LPM mode for ACCEPT    \
44240 \ ------------------------------\
44241 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
44242 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
44243 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
44244
44245 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
44246
44247 \ ------------------------------\
44248 \ Init LCD 2x20                 \
44249 \ ------------------------------\
44250     $03E8 20_US                \ 1-  wait 20 ms
44251     $03 TOP_LCD                \ 2- send DB5=DB4=1
44252     $CD 20_US                  \ 3- wait 4,1 ms
44253     $03 TOP_LCD                \ 4- send again DB5=DB4=1
44254     $5 20_US                   \ 5- wait 0,1 ms
44255     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
44256     $2 20_US                   \    wait 40 us = LCD cycle
44257     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
44258     $2 20_US                   \    wait 40 us = LCD cycle
44259     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
44260     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
44261     LCD_Clear                   \ 10- "LCD_Clear"
44262     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
44263     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
44264     LCD_Clear                   \ 10- "LCD_Clear"
44265     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
44266     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
44267     CR ." I love you"   
44268     ['] (CR) IS CR              \ ' (CR) is CR
44269     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
44270     CR
44271     ."    RC5toLCD is running. Type STOP to quit"
44272 \    NOECHO                      \ uncomment to run this app without terminal connexion
44273     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
44274     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
44275 ;
44276     \
44277
44278 : STOP                  \ stops multitasking, must to be used before downloading app
44279     ['] (WARM) IS WARM  \ remove START app from FORTH init process
44280     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
44281 ;
44282     \
44283
44284
44285 RST_STATE   ;
44286
44287
44288 CODE MAX    \    n1 n2 -- n3       signed maximum
44289             CMP     @PSP,TOS    \ n2-n1
44290             S<      ?GOTO FW1   \ n2<n1
44291 BW1         ADD     #2,PSP
44292             MOV     @IP+,PC
44293 ENDCODE
44294     \
44295
44296 CODE MIN    \    n1 n2 -- n3       signed minimum
44297             CMP     @PSP,TOS     \ n2-n1
44298             S<      ?GOTO BW1    \ n2<n1
44299 FW1         MOV     @PSP+,TOS
44300             MOV     @IP+,PC
44301 ENDCODE
44302     \
44303
44304 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
44305   >R  <# 0 # #S #>  
44306   R> OVER - 0 MAX SPACES TYPE
44307 ;
44308     \
44309
44310 CODE 20_US                      \ n --      n * 20 us
44311 BEGIN                           \ 3 cycles loop + 6~  
44312 \    MOV     #5,W                \ 3 MCLK = 1 MHz
44313 \    MOV     #23,W               \ 3 MCLK = 4 MHz
44314     MOV     #51,W               \ 3 MCLK = 8 MHz
44315 \    MOV     #104,W              \ 3 MCLK = 16 MHz
44316 \    MOV     #158,W              \ 3 MCLK = 24 MHz
44317     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
44318         SUB #1,W                \ 1
44319     0= UNTIL                    \ 2
44320     SUB     #1,TOS              \ 1
44321 0= UNTIL                        \ 2
44322     MOV     @PSP+,TOS           \ 2
44323     MOV     @IP+,PC             \ 4
44324 ENDCODE
44325     \
44326
44327 CODE TOP_LCD                    \ LCD Sample
44328 \                               \ if write : %xxxxWWWW --
44329 \                               \ if read  : -- %0000RRRR
44330     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
44331     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
44332 0= IF                           \ write LCD bits pattern
44333     AND.B #LCD_DB,TOS           \ 
44334     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
44335     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
44336     MOV @PSP+,TOS               \
44337     MOV @IP+,PC
44338 THEN                            \ read LCD bits pattern
44339     SUB #2,PSP
44340     MOV TOS,0(PSP)
44341     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
44342     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
44343     AND.B #LCD_DB,TOS           \
44344     MOV @IP+,PC
44345 ENDCODE
44346     \
44347
44348 CODE LCD_W                      \ byte --       write byte to LCD 
44349     SUB #2,PSP                  \
44350     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
44351     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
44352     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
44353     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
44354 COLON                           \ high level word starts here 
44355     TOP_LCD 2 20_US             \ write high nibble first
44356     TOP_LCD 2 20_US 
44357 ;
44358     \
44359
44360 CODE LCD_WrC                    \ char --         Write Char
44361     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
44362     JMP LCD_W 
44363 ENDCODE
44364     \
44365
44366 CODE LCD_WrF                    \ func --         Write Fonction
44367     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
44368     JMP LCD_W 
44369 ENDCODE
44370     \
44371
44372 : LCD_Clear 
44373     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
44374 ;
44375     \
44376
44377 : LCD_Home 
44378     $02 LCD_WrF 100 20_us 
44379 ;
44380     \
44381
44382 \ : LCD_Entry_set       $04 OR LCD_WrF ;
44383
44384 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
44385
44386 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
44387
44388 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
44389
44390 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
44391
44392 \ : LCD_Goto            $80 OR LCD_WrF ;
44393
44394 \ CODE LCD_R                      \ -- byte       read byte from LCD
44395 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
44396 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
44397 \ COLON                           \ starts a FORTH word
44398 \     TOP_LCD 2 20_us             \ -- %0000HHHH
44399 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
44400 \ HI2LO                           \ switch from FORTH to assembler
44401 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
44402 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
44403 \     MOV @RSP+,IP                \ restore IP saved by COLON
44404 \     MOV @IP+,PC                 \
44405 \ ENDCODE
44406 \     \
44407
44408 \ CODE LCD_RdS                    \ -- status       Read Status
44409 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
44410 \     JMP LCD_R
44411 \ ENDCODE
44412 \     \
44413
44414 \ CODE LCD_RdC                    \ -- char         Read Char
44415 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
44416 \     JMP LCD_R
44417 \ ENDCODE
44418 \     \
44419
44420 \ -------------+------+------+------+------++---+---+---+---+---------+
44421 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
44422 \ -------------+------+------+------+------++---+---+---+---+---------+
44423 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
44424 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
44425 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
44426 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
44427 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
44428 \ -------------+------+------+------+------++---+---+---+---+---------+
44429
44430
44431 \ ******************************\
44432 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
44433 \ ******************************\
44434 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
44435 \ ------------------------------\
44436 \ define LPM mode for ACCEPT    \
44437 \ ------------------------------\
44438 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
44439 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
44440 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
44441 BIT.B #SW2,&SW2_IN              \ test switch S2
44442 0= IF                           \ case of switch S2 pressed
44443     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
44444     U< IF
44445         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
44446     THEN
44447 ELSE
44448     BIT.B #SW1,&SW1_IN          \ test switch S1 input
44449     0= IF                       \ case of Switch S1 pressed
44450         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
44451         U>= IF                  \
44452             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
44453         THEN                    \
44454     THEN                        \
44455 THEN                            \
44456 RETI                            \ CPU is ON, GIE is OFF
44457 ENDASM                          \
44458     \
44459
44460
44461 \ ------------------------------\
44462 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
44463 \ ******************************\
44464 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
44465 \ ******************************\
44466 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
44467 \                               \       SMclock = 8|16|24 MHz
44468 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
44469 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
44470 \                               \       SR(9)=new Toggle bit memory (ADD on)
44471 \ ------------------------------\
44472 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
44473 \ ------------------------------\
44474 \ define LPM mode for ACCEPT    \
44475 \ ------------------------------\
44476 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
44477 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
44478 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
44479 \ ------------------------------\
44480 \ RC5_FirstStartBitHalfCycle:   \
44481 \ ------------------------------\
44482 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
44483 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
44484 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
44485 MOV     #1778,X                 \ RC5_Period in us
44486 MOV     #14,W                   \ count of loop
44487 BEGIN                           \
44488 \ ------------------------------\
44489 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
44490 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
44491     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
44492 \ RC5_Compute_3/4_Period:       \                   |
44493     RRUM    #1,X                \ X=1/2 cycle       |
44494     MOV     X,Y                 \ Y=1/2             ^
44495     RRUM    #1,Y                \ Y=1/4
44496     ADD     X,Y                 \ Y=3/4
44497 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
44498     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
44499     0= UNTIL                    \
44500 \ ------------------------------\
44501 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
44502 \ ------------------------------\
44503     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
44504     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
44505     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
44506     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
44507     SUB     #1,W                \ decrement count loop
44508 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
44509 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
44510 0<> WHILE                       \ ----> out of loop ----+
44511 \ RC5_compute_7/4_Time_out:     \                       |
44512     ADD     X,Y                 \                       |   out of bound = 7/4 period 
44513 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
44514     BEGIN                       \                       |
44515         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
44516         0>= IF                  \                       |   if cycle time out of bound
44517             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
44518             RETI                \                       |   then quit to do nothing
44519         THEN                    \                       |
44520 \ ------------------------------\                       |
44521         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
44522     0<> UNTIL                   \                   |   |
44523     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
44524 REPEAT                          \ ----> loop back --+   |
44525 \ ------------------------------\                       |
44526 \ RC5_SampleEndOf:              \ <---------------------+
44527 \ ------------------------------\
44528 BIC     #$30,&TA0CTL           \ stop timer_A0
44529 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
44530 \ ******************************\
44531 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
44532 \ ******************************\
44533 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
44534 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
44535 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
44536 BIT     #BIT13,X                \ X(13) = New_RC5_command
44537 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
44538 THEN                            \
44539 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
44540 \ ******************************\
44541 \ RC5_ComputeNewRC5word         \
44542 \ ******************************\
44543 SUB     #4,PSP                  \
44544 MOV     &BASE,2(PSP)            \ save variable BASE before use
44545 MOV     TOS,0(PSP)              \ save TOS before use
44546 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
44547 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
44548 \ ******************************\
44549 \ RC5_ComputeC6bit              \
44550 \ ******************************\
44551 BIT     #$4000,IP              \ test /C6 bit in IP
44552 0= IF   BIS #$40,TOS           \ set C6 bit in S
44553 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
44554 \ ******************************\
44555 \ RC5_CommandByteIsDone         \ RC5_code --
44556 \ ******************************\
44557
44558 \ ------------------------------\
44559 \ Display IR_RC5 code           \
44560 \ ------------------------------\
44561 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
44562 \ ------------------------------\
44563 LO2HI                           \ switch from assembler to FORTH
44564     ['] LCD_CLEAR IS CR         \ redirects CR
44565     ['] LCD_WrC  IS EMIT        \ redirects EMIT
44566     $10 BASE !                 \ change BASE to hexadecimal
44567     CR ." $" 2 U.R             \ print IR_RC5 code
44568     ['] (CR) IS CR              \ restore CR
44569     ['] (EMIT) IS EMIT          \ restore EMIT
44570 HI2LO                           \ switch from FORTH to assembler
44571 \ ------------------------------\
44572 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
44573 \ ------------------------------\
44574 MOV @PSP+,&BASE                 \ restore variable BASE
44575 RETI                            \ CPU is ON, GIE is OFF
44576 ENDASM                          \
44577     \ 
44578
44579 CODE START                      \
44580 \ ------------------------------\
44581 \ TB0CTL = %0000 0010 1001 0100\$3C0
44582 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
44583 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
44584 \                      --       \ID input divider \ 10 = /4
44585 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
44586 \                            -  \TBCLR TimerB Clear
44587 \                             - \TBIE
44588 \                              -\TBIFG
44589 \ --------------------------------\\
44590 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
44591 \              --                 \CM Capture Mode
44592 \                --               \CCIS
44593 \                   -             \SCS
44594 \                    --           \CLLD
44595 \                      -          \CAP
44596 \                        ---      \OUTMOD \ 011 = set/reset
44597 \                           -     \CCIE
44598 \                             -   \CCI
44599 \                              -  \OUT
44600 \                               - \COV
44601 \                                -\CCIFG
44602 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
44603 \ TB0EX0                          \$3E0 
44604 \ ------------------------------\
44605 \ set TimerB to make 50kHz PWM  \
44606 \ ------------------------------\
44607 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
44608 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
44609 \ ------------------------------\
44610 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
44611 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
44612 \ ------------------------------\
44613     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
44614     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
44615 \ ------------------------------\
44616 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
44617 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
44618 \ ------------------------------\
44619 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
44620 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
44621 \ ------------------------------\
44622     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
44623 \ ------------------------------\
44624 \ set TimerB to generate PWM for LCD_Vo
44625 \ ------------------------------\
44626     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
44627 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
44628     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
44629 \ ------------------------------\
44630     BIS.B #LCDVo,&LCDVo_DIR     \
44631     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
44632 \ ------------------------------\
44633     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
44634     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
44635 \ ------------------------------\
44636     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
44637     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
44638 \ ------------------------------\
44639 \ WDT interval init part        \
44640 \ ------------------------------\
44641     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
44642 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
44643 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
44644     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
44645 \ ------------------------------\
44646 \ init RC5_Int                  \
44647 \ ------------------------------\
44648     BIS.B #RC5,&IR_IE           \ enable RC5_Int
44649     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
44650 \ ------------------------------\
44651 \ init interrupt vectors
44652 \ ------------------------------\
44653     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
44654     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
44655 \ ------------------------------\
44656 \ define LPM mode for ACCEPT    \
44657 \ ------------------------------\
44658 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
44659 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
44660 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
44661
44662 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
44663
44664 \ ------------------------------\
44665 \ Init LCD 2x20                 \
44666 \ ------------------------------\
44667     $03E8 20_US                \ 1-  wait 20 ms
44668     $03 TOP_LCD                \ 2- send DB5=DB4=1
44669     $CD 20_US                  \ 3- wait 4,1 ms
44670     $03 TOP_LCD                \ 4- send again DB5=DB4=1
44671     $5 20_US                   \ 5- wait 0,1 ms
44672     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
44673     $2 20_US                   \    wait 40 us = LCD cycle
44674     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
44675     $2 20_US                   \    wait 40 us = LCD cycle
44676     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
44677     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
44678     LCD_Clear                   \ 10- "LCD_Clear"
44679     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
44680     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
44681     LCD_Clear                   \ 10- "LCD_Clear"
44682     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
44683     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
44684     CR ." I love you"   
44685     ['] (CR) IS CR              \ ' (CR) is CR
44686     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
44687     CR
44688     ."    RC5toLCD is running. Type STOP to quit"
44689 \    NOECHO                      \ uncomment to run this app without terminal connexion
44690     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
44691     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
44692 ;
44693     \
44694
44695 : STOP                  \ stops multitasking, must to be used before downloading app
44696     ['] (WARM) IS WARM  \ remove START app from FORTH init process
44697     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
44698 ;
44699     \
44700
44701
44702 RST_STATE   ;
44703
44704
44705 CODE MAX    \    n1 n2 -- n3       signed maximum
44706             CMP     @PSP,TOS    \ n2-n1
44707             S<      ?GOTO FW1   \ n2<n1
44708 BW1         ADD     #2,PSP
44709             MOV     @IP+,PC
44710 ENDCODE
44711     \
44712
44713 CODE MIN    \    n1 n2 -- n3       signed minimum
44714             CMP     @PSP,TOS     \ n2-n1
44715             S<      ?GOTO BW1    \ n2<n1
44716 FW1         MOV     @PSP+,TOS
44717             MOV     @IP+,PC
44718 ENDCODE
44719     \
44720
44721 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
44722   >R  <# 0 # #S #>  
44723   R> OVER - 0 MAX SPACES TYPE
44724 ;
44725     \
44726
44727 CODE 20_US                      \ n --      n * 20 us
44728 BEGIN                           \ 3 cycles loop + 6~  
44729 \    MOV     #5,W                \ 3 MCLK = 1 MHz
44730 \    MOV     #23,W               \ 3 MCLK = 4 MHz
44731     MOV     #51,W               \ 3 MCLK = 8 MHz
44732 \    MOV     #104,W              \ 3 MCLK = 16 MHz
44733 \    MOV     #158,W              \ 3 MCLK = 24 MHz
44734     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
44735         SUB #1,W                \ 1
44736     0= UNTIL                    \ 2
44737     SUB     #1,TOS              \ 1
44738 0= UNTIL                        \ 2
44739     MOV     @PSP+,TOS           \ 2
44740     MOV     @IP+,PC             \ 4
44741 ENDCODE
44742     \
44743
44744 CODE TOP_LCD                    \ LCD Sample
44745 \                               \ if write : %xxxxWWWW --
44746 \                               \ if read  : -- %0000RRRR
44747     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
44748     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
44749 0= IF                           \ write LCD bits pattern
44750     AND.B #LCD_DB,TOS           \ 
44751     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
44752     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
44753     MOV @PSP+,TOS               \
44754     MOV @IP+,PC
44755 THEN                            \ read LCD bits pattern
44756     SUB #2,PSP
44757     MOV TOS,0(PSP)
44758     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
44759     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
44760     AND.B #LCD_DB,TOS           \
44761     MOV @IP+,PC
44762 ENDCODE
44763     \
44764
44765 CODE LCD_W                      \ byte --       write byte to LCD 
44766     SUB #2,PSP                  \
44767     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
44768     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
44769     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
44770     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
44771 COLON                           \ high level word starts here 
44772     TOP_LCD 2 20_US             \ write high nibble first
44773     TOP_LCD 2 20_US 
44774 ;
44775     \
44776
44777 CODE LCD_WrC                    \ char --         Write Char
44778     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
44779     JMP LCD_W 
44780 ENDCODE
44781     \
44782
44783 CODE LCD_WrF                    \ func --         Write Fonction
44784     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
44785     JMP LCD_W 
44786 ENDCODE
44787     \
44788
44789 : LCD_Clear 
44790     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
44791 ;
44792     \
44793
44794 : LCD_Home 
44795     $02 LCD_WrF 100 20_us 
44796 ;
44797     \
44798
44799 \ : LCD_Entry_set       $04 OR LCD_WrF ;
44800
44801 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
44802
44803 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
44804
44805 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
44806
44807 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
44808
44809 \ : LCD_Goto            $80 OR LCD_WrF ;
44810
44811 \ CODE LCD_R                      \ -- byte       read byte from LCD
44812 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
44813 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
44814 \ COLON                           \ starts a FORTH word
44815 \     TOP_LCD 2 20_us             \ -- %0000HHHH
44816 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
44817 \ HI2LO                           \ switch from FORTH to assembler
44818 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
44819 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
44820 \     MOV @RSP+,IP                \ restore IP saved by COLON
44821 \     MOV @IP+,PC                 \
44822 \ ENDCODE
44823 \     \
44824
44825 \ CODE LCD_RdS                    \ -- status       Read Status
44826 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
44827 \     JMP LCD_R
44828 \ ENDCODE
44829 \     \
44830
44831 \ CODE LCD_RdC                    \ -- char         Read Char
44832 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
44833 \     JMP LCD_R
44834 \ ENDCODE
44835 \     \
44836
44837 \ -------------+------+------+------+------++---+---+---+---+---------+
44838 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
44839 \ -------------+------+------+------+------++---+---+---+---+---------+
44840 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
44841 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
44842 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
44843 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
44844 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
44845 \ -------------+------+------+------+------++---+---+---+---+---------+
44846
44847
44848 \ ******************************\
44849 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
44850 \ ******************************\
44851 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
44852 \ ------------------------------\
44853 \ define LPM mode for ACCEPT    \
44854 \ ------------------------------\
44855 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
44856 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
44857 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
44858 BIT.B #SW2,&SW2_IN              \ test switch S2
44859 0= IF                           \ case of switch S2 pressed
44860     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
44861     U< IF
44862         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
44863     THEN
44864 ELSE
44865     BIT.B #SW1,&SW1_IN          \ test switch S1 input
44866     0= IF                       \ case of Switch S1 pressed
44867         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
44868         U>= IF                  \
44869             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
44870         THEN                    \
44871     THEN                        \
44872 THEN                            \
44873 RETI                            \ CPU is ON, GIE is OFF
44874 ENDASM                          \
44875     \
44876
44877
44878 \ ------------------------------\
44879 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
44880 \ ******************************\
44881 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
44882 \ ******************************\
44883 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
44884 \                               \       SMclock = 8|16|24 MHz
44885 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
44886 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
44887 \                               \       SR(9)=new Toggle bit memory (ADD on)
44888 \ ------------------------------\
44889 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
44890 \ ------------------------------\
44891 \ define LPM mode for ACCEPT    \
44892 \ ------------------------------\
44893 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
44894 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
44895 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
44896 \ ------------------------------\
44897 \ RC5_FirstStartBitHalfCycle:   \
44898 \ ------------------------------\
44899 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
44900 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
44901 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
44902 MOV     #1778,X                 \ RC5_Period in us
44903 MOV     #14,W                   \ count of loop
44904 BEGIN                           \
44905 \ ------------------------------\
44906 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
44907 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
44908     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
44909 \ RC5_Compute_3/4_Period:       \                   |
44910     RRUM    #1,X                \ X=1/2 cycle       |
44911     MOV     X,Y                 \ Y=1/2             ^
44912     RRUM    #1,Y                \ Y=1/4
44913     ADD     X,Y                 \ Y=3/4
44914 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
44915     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
44916     0= UNTIL                    \
44917 \ ------------------------------\
44918 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
44919 \ ------------------------------\
44920     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
44921     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
44922     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
44923     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
44924     SUB     #1,W                \ decrement count loop
44925 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
44926 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
44927 0<> WHILE                       \ ----> out of loop ----+
44928 \ RC5_compute_7/4_Time_out:     \                       |
44929     ADD     X,Y                 \                       |   out of bound = 7/4 period 
44930 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
44931     BEGIN                       \                       |
44932         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
44933         0>= IF                  \                       |   if cycle time out of bound
44934             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
44935             RETI                \                       |   then quit to do nothing
44936         THEN                    \                       |
44937 \ ------------------------------\                       |
44938         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
44939     0<> UNTIL                   \                   |   |
44940     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
44941 REPEAT                          \ ----> loop back --+   |
44942 \ ------------------------------\                       |
44943 \ RC5_SampleEndOf:              \ <---------------------+
44944 \ ------------------------------\
44945 BIC     #$30,&TA0CTL           \ stop timer_A0
44946 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
44947 \ ******************************\
44948 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
44949 \ ******************************\
44950 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
44951 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
44952 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
44953 BIT     #BIT13,X                \ X(13) = New_RC5_command
44954 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
44955 THEN                            \
44956 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
44957 \ ******************************\
44958 \ RC5_ComputeNewRC5word         \
44959 \ ******************************\
44960 SUB     #4,PSP                  \
44961 MOV     &BASE,2(PSP)            \ save variable BASE before use
44962 MOV     TOS,0(PSP)              \ save TOS before use
44963 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
44964 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
44965 \ ******************************\
44966 \ RC5_ComputeC6bit              \
44967 \ ******************************\
44968 BIT     #$4000,IP              \ test /C6 bit in IP
44969 0= IF   BIS #$40,TOS           \ set C6 bit in S
44970 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
44971 \ ******************************\
44972 \ RC5_CommandByteIsDone         \ RC5_code --
44973 \ ******************************\
44974
44975 \ ------------------------------\
44976 \ Display IR_RC5 code           \
44977 \ ------------------------------\
44978 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
44979 \ ------------------------------\
44980 LO2HI                           \ switch from assembler to FORTH
44981     ['] LCD_CLEAR IS CR         \ redirects CR
44982     ['] LCD_WrC  IS EMIT        \ redirects EMIT
44983     $10 BASE !                 \ change BASE to hexadecimal
44984     CR ." $" 2 U.R             \ print IR_RC5 code
44985     ['] (CR) IS CR              \ restore CR
44986     ['] (EMIT) IS EMIT          \ restore EMIT
44987 HI2LO                           \ switch from FORTH to assembler
44988 \ ------------------------------\
44989 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
44990 \ ------------------------------\
44991 MOV @PSP+,&BASE                 \ restore variable BASE
44992 RETI                            \ CPU is ON, GIE is OFF
44993 ENDASM                          \
44994     \ 
44995
44996 CODE START                      \
44997 \ ------------------------------\
44998 \ TB0CTL = %0000 0010 1001 0100\$3C0
44999 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
45000 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
45001 \                      --       \ID input divider \ 10 = /4
45002 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
45003 \                            -  \TBCLR TimerB Clear
45004 \                             - \TBIE
45005 \                              -\TBIFG
45006 \ --------------------------------\\
45007 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
45008 \              --                 \CM Capture Mode
45009 \                --               \CCIS
45010 \                   -             \SCS
45011 \                    --           \CLLD
45012 \                      -          \CAP
45013 \                        ---      \OUTMOD \ 011 = set/reset
45014 \                           -     \CCIE
45015 \                             -   \CCI
45016 \                              -  \OUT
45017 \                               - \COV
45018 \                                -\CCIFG
45019 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
45020 \ TB0EX0                          \$3E0 
45021 \ ------------------------------\
45022 \ set TimerB to make 50kHz PWM  \
45023 \ ------------------------------\
45024 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
45025 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
45026 \ ------------------------------\
45027 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
45028 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
45029 \ ------------------------------\
45030     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
45031     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
45032 \ ------------------------------\
45033 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
45034 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
45035 \ ------------------------------\
45036 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
45037 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
45038 \ ------------------------------\
45039     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
45040 \ ------------------------------\
45041 \ set TimerB to generate PWM for LCD_Vo
45042 \ ------------------------------\
45043     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
45044 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
45045     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
45046 \ ------------------------------\
45047     BIS.B #LCDVo,&LCDVo_DIR     \
45048     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
45049 \ ------------------------------\
45050     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
45051     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
45052 \ ------------------------------\
45053     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
45054     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
45055 \ ------------------------------\
45056 \ WDT interval init part        \
45057 \ ------------------------------\
45058     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
45059 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
45060 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
45061     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
45062 \ ------------------------------\
45063 \ init RC5_Int                  \
45064 \ ------------------------------\
45065     BIS.B #RC5,&IR_IE           \ enable RC5_Int
45066     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
45067 \ ------------------------------\
45068 \ init interrupt vectors
45069 \ ------------------------------\
45070     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
45071     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
45072 \ ------------------------------\
45073 \ define LPM mode for ACCEPT    \
45074 \ ------------------------------\
45075 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
45076 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
45077 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
45078
45079 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
45080
45081 \ ------------------------------\
45082 \ Init LCD 2x20                 \
45083 \ ------------------------------\
45084     $03E8 20_US                \ 1-  wait 20 ms
45085     $03 TOP_LCD                \ 2- send DB5=DB4=1
45086     $CD 20_US                  \ 3- wait 4,1 ms
45087     $03 TOP_LCD                \ 4- send again DB5=DB4=1
45088     $5 20_US                   \ 5- wait 0,1 ms
45089     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
45090     $2 20_US                   \    wait 40 us = LCD cycle
45091     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
45092     $2 20_US                   \    wait 40 us = LCD cycle
45093     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
45094     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
45095     LCD_Clear                   \ 10- "LCD_Clear"
45096     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
45097     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
45098     LCD_Clear                   \ 10- "LCD_Clear"
45099     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
45100     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
45101     CR ." I love you"   
45102     ['] (CR) IS CR              \ ' (CR) is CR
45103     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
45104     CR
45105     ."    RC5toLCD is running. Type STOP to quit"
45106 \    NOECHO                      \ uncomment to run this app without terminal connexion
45107     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
45108     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
45109 ;
45110     \
45111
45112 : STOP                  \ stops multitasking, must to be used before downloading app
45113     ['] (WARM) IS WARM  \ remove START app from FORTH init process
45114     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
45115 ;
45116     \
45117
45118
45119 RST_STATE   ;
45120
45121
45122 CODE MAX    \    n1 n2 -- n3       signed maximum
45123             CMP     @PSP,TOS    \ n2-n1
45124             S<      ?GOTO FW1   \ n2<n1
45125 BW1         ADD     #2,PSP
45126             MOV     @IP+,PC
45127 ENDCODE
45128     \
45129
45130 CODE MIN    \    n1 n2 -- n3       signed minimum
45131             CMP     @PSP,TOS     \ n2-n1
45132             S<      ?GOTO BW1    \ n2<n1
45133 FW1         MOV     @PSP+,TOS
45134             MOV     @IP+,PC
45135 ENDCODE
45136     \
45137
45138 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
45139   >R  <# 0 # #S #>  
45140   R> OVER - 0 MAX SPACES TYPE
45141 ;
45142     \
45143
45144 CODE 20_US                      \ n --      n * 20 us
45145 BEGIN                           \ 3 cycles loop + 6~  
45146 \    MOV     #5,W                \ 3 MCLK = 1 MHz
45147 \    MOV     #23,W               \ 3 MCLK = 4 MHz
45148     MOV     #51,W               \ 3 MCLK = 8 MHz
45149 \    MOV     #104,W              \ 3 MCLK = 16 MHz
45150 \    MOV     #158,W              \ 3 MCLK = 24 MHz
45151     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
45152         SUB #1,W                \ 1
45153     0= UNTIL                    \ 2
45154     SUB     #1,TOS              \ 1
45155 0= UNTIL                        \ 2
45156     MOV     @PSP+,TOS           \ 2
45157     MOV     @IP+,PC             \ 4
45158 ENDCODE
45159     \
45160
45161 CODE TOP_LCD                    \ LCD Sample
45162 \                               \ if write : %xxxxWWWW --
45163 \                               \ if read  : -- %0000RRRR
45164     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
45165     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
45166 0= IF                           \ write LCD bits pattern
45167     AND.B #LCD_DB,TOS           \ 
45168     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
45169     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
45170     MOV @PSP+,TOS               \
45171     MOV @IP+,PC
45172 THEN                            \ read LCD bits pattern
45173     SUB #2,PSP
45174     MOV TOS,0(PSP)
45175     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
45176     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
45177     AND.B #LCD_DB,TOS           \
45178     MOV @IP+,PC
45179 ENDCODE
45180     \
45181
45182 CODE LCD_W                      \ byte --       write byte to LCD 
45183     SUB #2,PSP                  \
45184     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
45185     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
45186     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
45187     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
45188 COLON                           \ high level word starts here 
45189     TOP_LCD 2 20_US             \ write high nibble first
45190     TOP_LCD 2 20_US 
45191 ;
45192     \
45193
45194 CODE LCD_WrC                    \ char --         Write Char
45195     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
45196     JMP LCD_W 
45197 ENDCODE
45198     \
45199
45200 CODE LCD_WrF                    \ func --         Write Fonction
45201     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
45202     JMP LCD_W 
45203 ENDCODE
45204     \
45205
45206 : LCD_Clear 
45207     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
45208 ;
45209     \
45210
45211 : LCD_Home 
45212     $02 LCD_WrF 100 20_us 
45213 ;
45214     \
45215
45216 \ : LCD_Entry_set       $04 OR LCD_WrF ;
45217
45218 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
45219
45220 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
45221
45222 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
45223
45224 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
45225
45226 \ : LCD_Goto            $80 OR LCD_WrF ;
45227
45228 \ CODE LCD_R                      \ -- byte       read byte from LCD
45229 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
45230 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
45231 \ COLON                           \ starts a FORTH word
45232 \     TOP_LCD 2 20_us             \ -- %0000HHHH
45233 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
45234 \ HI2LO                           \ switch from FORTH to assembler
45235 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
45236 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
45237 \     MOV @RSP+,IP                \ restore IP saved by COLON
45238 \     MOV @IP+,PC                 \
45239 \ ENDCODE
45240 \     \
45241
45242 \ CODE LCD_RdS                    \ -- status       Read Status
45243 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
45244 \     JMP LCD_R
45245 \ ENDCODE
45246 \     \
45247
45248 \ CODE LCD_RdC                    \ -- char         Read Char
45249 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
45250 \     JMP LCD_R
45251 \ ENDCODE
45252 \     \
45253
45254 \ -------------+------+------+------+------++---+---+---+---+---------+
45255 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
45256 \ -------------+------+------+------+------++---+---+---+---+---------+
45257 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
45258 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
45259 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
45260 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
45261 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
45262 \ -------------+------+------+------+------++---+---+---+---+---------+
45263
45264
45265 \ ******************************\
45266 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
45267 \ ******************************\
45268 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
45269 \ ------------------------------\
45270 \ define LPM mode for ACCEPT    \
45271 \ ------------------------------\
45272 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
45273 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
45274 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
45275 BIT.B #SW2,&SW2_IN              \ test switch S2
45276 0= IF                           \ case of switch S2 pressed
45277     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
45278     U< IF
45279         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
45280     THEN
45281 ELSE
45282     BIT.B #SW1,&SW1_IN          \ test switch S1 input
45283     0= IF                       \ case of Switch S1 pressed
45284         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
45285         U>= IF                  \
45286             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
45287         THEN                    \
45288     THEN                        \
45289 THEN                            \
45290 RETI                            \ CPU is ON, GIE is OFF
45291 ENDASM                          \
45292     \
45293
45294
45295 \ ------------------------------\
45296 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
45297 \ ******************************\
45298 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
45299 \ ******************************\
45300 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
45301 \                               \       SMclock = 8|16|24 MHz
45302 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
45303 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
45304 \                               \       SR(9)=new Toggle bit memory (ADD on)
45305 \ ------------------------------\
45306 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
45307 \ ------------------------------\
45308 \ define LPM mode for ACCEPT    \
45309 \ ------------------------------\
45310 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
45311 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
45312 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
45313 \ ------------------------------\
45314 \ RC5_FirstStartBitHalfCycle:   \
45315 \ ------------------------------\
45316 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
45317 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
45318 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
45319 MOV     #1778,X                 \ RC5_Period in us
45320 MOV     #14,W                   \ count of loop
45321 BEGIN                           \
45322 \ ------------------------------\
45323 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
45324 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
45325     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
45326 \ RC5_Compute_3/4_Period:       \                   |
45327     RRUM    #1,X                \ X=1/2 cycle       |
45328     MOV     X,Y                 \ Y=1/2             ^
45329     RRUM    #1,Y                \ Y=1/4
45330     ADD     X,Y                 \ Y=3/4
45331 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
45332     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
45333     0= UNTIL                    \
45334 \ ------------------------------\
45335 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
45336 \ ------------------------------\
45337     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
45338     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
45339     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
45340     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
45341     SUB     #1,W                \ decrement count loop
45342 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
45343 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
45344 0<> WHILE                       \ ----> out of loop ----+
45345 \ RC5_compute_7/4_Time_out:     \                       |
45346     ADD     X,Y                 \                       |   out of bound = 7/4 period 
45347 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
45348     BEGIN                       \                       |
45349         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
45350         0>= IF                  \                       |   if cycle time out of bound
45351             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
45352             RETI                \                       |   then quit to do nothing
45353         THEN                    \                       |
45354 \ ------------------------------\                       |
45355         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
45356     0<> UNTIL                   \                   |   |
45357     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
45358 REPEAT                          \ ----> loop back --+   |
45359 \ ------------------------------\                       |
45360 \ RC5_SampleEndOf:              \ <---------------------+
45361 \ ------------------------------\
45362 BIC     #$30,&TA0CTL           \ stop timer_A0
45363 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
45364 \ ******************************\
45365 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
45366 \ ******************************\
45367 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
45368 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
45369 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
45370 BIT     #BIT13,X                \ X(13) = New_RC5_command
45371 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
45372 THEN                            \
45373 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
45374 \ ******************************\
45375 \ RC5_ComputeNewRC5word         \
45376 \ ******************************\
45377 SUB     #4,PSP                  \
45378 MOV     &BASE,2(PSP)            \ save variable BASE before use
45379 MOV     TOS,0(PSP)              \ save TOS before use
45380 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
45381 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
45382 \ ******************************\
45383 \ RC5_ComputeC6bit              \
45384 \ ******************************\
45385 BIT     #$4000,IP              \ test /C6 bit in IP
45386 0= IF   BIS #$40,TOS           \ set C6 bit in S
45387 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
45388 \ ******************************\
45389 \ RC5_CommandByteIsDone         \ RC5_code --
45390 \ ******************************\
45391
45392 \ ------------------------------\
45393 \ Display IR_RC5 code           \
45394 \ ------------------------------\
45395 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
45396 \ ------------------------------\
45397 LO2HI                           \ switch from assembler to FORTH
45398     ['] LCD_CLEAR IS CR         \ redirects CR
45399     ['] LCD_WrC  IS EMIT        \ redirects EMIT
45400     $10 BASE !                 \ change BASE to hexadecimal
45401     CR ." $" 2 U.R             \ print IR_RC5 code
45402     ['] (CR) IS CR              \ restore CR
45403     ['] (EMIT) IS EMIT          \ restore EMIT
45404 HI2LO                           \ switch from FORTH to assembler
45405 \ ------------------------------\
45406 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
45407 \ ------------------------------\
45408 MOV @PSP+,&BASE                 \ restore variable BASE
45409 RETI                            \ CPU is ON, GIE is OFF
45410 ENDASM                          \
45411     \ 
45412
45413 CODE START                      \
45414 \ ------------------------------\
45415 \ TB0CTL = %0000 0010 1001 0100\$3C0
45416 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
45417 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
45418 \                      --       \ID input divider \ 10 = /4
45419 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
45420 \                            -  \TBCLR TimerB Clear
45421 \                             - \TBIE
45422 \                              -\TBIFG
45423 \ --------------------------------\\
45424 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
45425 \              --                 \CM Capture Mode
45426 \                --               \CCIS
45427 \                   -             \SCS
45428 \                    --           \CLLD
45429 \                      -          \CAP
45430 \                        ---      \OUTMOD \ 011 = set/reset
45431 \                           -     \CCIE
45432 \                             -   \CCI
45433 \                              -  \OUT
45434 \                               - \COV
45435 \                                -\CCIFG
45436 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
45437 \ TB0EX0                          \$3E0 
45438 \ ------------------------------\
45439 \ set TimerB to make 50kHz PWM  \
45440 \ ------------------------------\
45441 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
45442 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
45443 \ ------------------------------\
45444 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
45445 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
45446 \ ------------------------------\
45447     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
45448     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
45449 \ ------------------------------\
45450 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
45451 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
45452 \ ------------------------------\
45453 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
45454 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
45455 \ ------------------------------\
45456     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
45457 \ ------------------------------\
45458 \ set TimerB to generate PWM for LCD_Vo
45459 \ ------------------------------\
45460     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
45461 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
45462     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
45463 \ ------------------------------\
45464     BIS.B #LCDVo,&LCDVo_DIR     \
45465     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
45466 \ ------------------------------\
45467     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
45468     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
45469 \ ------------------------------\
45470     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
45471     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
45472 \ ------------------------------\
45473 \ WDT interval init part        \
45474 \ ------------------------------\
45475     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
45476 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
45477 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
45478     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
45479 \ ------------------------------\
45480 \ init RC5_Int                  \
45481 \ ------------------------------\
45482     BIS.B #RC5,&IR_IE           \ enable RC5_Int
45483     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
45484 \ ------------------------------\
45485 \ init interrupt vectors
45486 \ ------------------------------\
45487     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
45488     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
45489 \ ------------------------------\
45490 \ define LPM mode for ACCEPT    \
45491 \ ------------------------------\
45492 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
45493 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
45494 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
45495
45496 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
45497
45498 \ ------------------------------\
45499 \ Init LCD 2x20                 \
45500 \ ------------------------------\
45501     $03E8 20_US                \ 1-  wait 20 ms
45502     $03 TOP_LCD                \ 2- send DB5=DB4=1
45503     $CD 20_US                  \ 3- wait 4,1 ms
45504     $03 TOP_LCD                \ 4- send again DB5=DB4=1
45505     $5 20_US                   \ 5- wait 0,1 ms
45506     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
45507     $2 20_US                   \    wait 40 us = LCD cycle
45508     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
45509     $2 20_US                   \    wait 40 us = LCD cycle
45510     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
45511     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
45512     LCD_Clear                   \ 10- "LCD_Clear"
45513     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
45514     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
45515     LCD_Clear                   \ 10- "LCD_Clear"
45516     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
45517     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
45518     CR ." I love you"   
45519     ['] (CR) IS CR              \ ' (CR) is CR
45520     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
45521     CR
45522     ."    RC5toLCD is running. Type STOP to quit"
45523 \    NOECHO                      \ uncomment to run this app without terminal connexion
45524     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
45525     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
45526 ;
45527     \
45528
45529 : STOP                  \ stops multitasking, must to be used before downloading app
45530     ['] (WARM) IS WARM  \ remove START app from FORTH init process
45531     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
45532 ;
45533     \
45534
45535
45536 RST_STATE   ;
45537
45538
45539 CODE MAX    \    n1 n2 -- n3       signed maximum
45540             CMP     @PSP,TOS    \ n2-n1
45541             S<      ?GOTO FW1   \ n2<n1
45542 BW1         ADD     #2,PSP
45543             MOV     @IP+,PC
45544 ENDCODE
45545     \
45546
45547 CODE MIN    \    n1 n2 -- n3       signed minimum
45548             CMP     @PSP,TOS     \ n2-n1
45549             S<      ?GOTO BW1    \ n2<n1
45550 FW1         MOV     @PSP+,TOS
45551             MOV     @IP+,PC
45552 ENDCODE
45553     \
45554
45555 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
45556   >R  <# 0 # #S #>  
45557   R> OVER - 0 MAX SPACES TYPE
45558 ;
45559     \
45560
45561 CODE 20_US                      \ n --      n * 20 us
45562 BEGIN                           \ 3 cycles loop + 6~  
45563 \    MOV     #5,W                \ 3 MCLK = 1 MHz
45564 \    MOV     #23,W               \ 3 MCLK = 4 MHz
45565     MOV     #51,W               \ 3 MCLK = 8 MHz
45566 \    MOV     #104,W              \ 3 MCLK = 16 MHz
45567 \    MOV     #158,W              \ 3 MCLK = 24 MHz
45568     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
45569         SUB #1,W                \ 1
45570     0= UNTIL                    \ 2
45571     SUB     #1,TOS              \ 1
45572 0= UNTIL                        \ 2
45573     MOV     @PSP+,TOS           \ 2
45574     MOV     @IP+,PC             \ 4
45575 ENDCODE
45576     \
45577
45578 CODE TOP_LCD                    \ LCD Sample
45579 \                               \ if write : %xxxxWWWW --
45580 \                               \ if read  : -- %0000RRRR
45581     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
45582     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
45583 0= IF                           \ write LCD bits pattern
45584     AND.B #LCD_DB,TOS           \ 
45585     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
45586     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
45587     MOV @PSP+,TOS               \
45588     MOV @IP+,PC
45589 THEN                            \ read LCD bits pattern
45590     SUB #2,PSP
45591     MOV TOS,0(PSP)
45592     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
45593     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
45594     AND.B #LCD_DB,TOS           \
45595     MOV @IP+,PC
45596 ENDCODE
45597     \
45598
45599 CODE LCD_W                      \ byte --       write byte to LCD 
45600     SUB #2,PSP                  \
45601     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
45602     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
45603     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
45604     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
45605 COLON                           \ high level word starts here 
45606     TOP_LCD 2 20_US             \ write high nibble first
45607     TOP_LCD 2 20_US 
45608 ;
45609     \
45610
45611 CODE LCD_WrC                    \ char --         Write Char
45612     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
45613     JMP LCD_W 
45614 ENDCODE
45615     \
45616
45617 CODE LCD_WrF                    \ func --         Write Fonction
45618     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
45619     JMP LCD_W 
45620 ENDCODE
45621     \
45622
45623 : LCD_Clear 
45624     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
45625 ;
45626     \
45627
45628 : LCD_Home 
45629     $02 LCD_WrF 100 20_us 
45630 ;
45631     \
45632
45633 \ : LCD_Entry_set       $04 OR LCD_WrF ;
45634
45635 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
45636
45637 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
45638
45639 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
45640
45641 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
45642
45643 \ : LCD_Goto            $80 OR LCD_WrF ;
45644
45645 \ CODE LCD_R                      \ -- byte       read byte from LCD
45646 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
45647 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
45648 \ COLON                           \ starts a FORTH word
45649 \     TOP_LCD 2 20_us             \ -- %0000HHHH
45650 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
45651 \ HI2LO                           \ switch from FORTH to assembler
45652 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
45653 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
45654 \     MOV @RSP+,IP                \ restore IP saved by COLON
45655 \     MOV @IP+,PC                 \
45656 \ ENDCODE
45657 \     \
45658
45659 \ CODE LCD_RdS                    \ -- status       Read Status
45660 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
45661 \     JMP LCD_R
45662 \ ENDCODE
45663 \     \
45664
45665 \ CODE LCD_RdC                    \ -- char         Read Char
45666 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
45667 \     JMP LCD_R
45668 \ ENDCODE
45669 \     \
45670
45671 \ -------------+------+------+------+------++---+---+---+---+---------+
45672 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
45673 \ -------------+------+------+------+------++---+---+---+---+---------+
45674 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
45675 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
45676 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
45677 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
45678 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
45679 \ -------------+------+------+------+------++---+---+---+---+---------+
45680
45681
45682 \ ******************************\
45683 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
45684 \ ******************************\
45685 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
45686 \ ------------------------------\
45687 \ define LPM mode for ACCEPT    \
45688 \ ------------------------------\
45689 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
45690 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
45691 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
45692 BIT.B #SW2,&SW2_IN              \ test switch S2
45693 0= IF                           \ case of switch S2 pressed
45694     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
45695     U< IF
45696         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
45697     THEN
45698 ELSE
45699     BIT.B #SW1,&SW1_IN          \ test switch S1 input
45700     0= IF                       \ case of Switch S1 pressed
45701         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
45702         U>= IF                  \
45703             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
45704         THEN                    \
45705     THEN                        \
45706 THEN                            \
45707 RETI                            \ CPU is ON, GIE is OFF
45708 ENDASM                          \
45709     \
45710
45711
45712 \ ------------------------------\
45713 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
45714 \ ******************************\
45715 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
45716 \ ******************************\
45717 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
45718 \                               \       SMclock = 8|16|24 MHz
45719 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
45720 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
45721 \                               \       SR(9)=new Toggle bit memory (ADD on)
45722 \ ------------------------------\
45723 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
45724 \ ------------------------------\
45725 \ define LPM mode for ACCEPT    \
45726 \ ------------------------------\
45727 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
45728 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
45729 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
45730 \ ------------------------------\
45731 \ RC5_FirstStartBitHalfCycle:   \
45732 \ ------------------------------\
45733 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
45734 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
45735 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
45736 MOV     #1778,X                 \ RC5_Period in us
45737 MOV     #14,W                   \ count of loop
45738 BEGIN                           \
45739 \ ------------------------------\
45740 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
45741 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
45742     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
45743 \ RC5_Compute_3/4_Period:       \                   |
45744     RRUM    #1,X                \ X=1/2 cycle       |
45745     MOV     X,Y                 \ Y=1/2             ^
45746     RRUM    #1,Y                \ Y=1/4
45747     ADD     X,Y                 \ Y=3/4
45748 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
45749     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
45750     0= UNTIL                    \
45751 \ ------------------------------\
45752 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
45753 \ ------------------------------\
45754     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
45755     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
45756     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
45757     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
45758     SUB     #1,W                \ decrement count loop
45759 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
45760 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
45761 0<> WHILE                       \ ----> out of loop ----+
45762 \ RC5_compute_7/4_Time_out:     \                       |
45763     ADD     X,Y                 \                       |   out of bound = 7/4 period 
45764 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
45765     BEGIN                       \                       |
45766         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
45767         0>= IF                  \                       |   if cycle time out of bound
45768             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
45769             RETI                \                       |   then quit to do nothing
45770         THEN                    \                       |
45771 \ ------------------------------\                       |
45772         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
45773     0<> UNTIL                   \                   |   |
45774     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
45775 REPEAT                          \ ----> loop back --+   |
45776 \ ------------------------------\                       |
45777 \ RC5_SampleEndOf:              \ <---------------------+
45778 \ ------------------------------\
45779 BIC     #$30,&TA0CTL           \ stop timer_A0
45780 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
45781 \ ******************************\
45782 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
45783 \ ******************************\
45784 MOV     @RSP,X                  \ retiSR(9)  = old UF1 = old RC5 toggle bit
45785 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
45786 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
45787 BIT     #BIT13,X                \ X(13) = New_RC5_command
45788 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
45789 THEN                            \
45790 XOR     #UF1,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
45791 \ ******************************\
45792 \ RC5_ComputeNewRC5word         \
45793 \ ******************************\
45794 SUB     #4,PSP                  \
45795 MOV     &BASE,2(PSP)            \ save variable BASE before use
45796 MOV     TOS,0(PSP)              \ save TOS before use
45797 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
45798 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
45799 \ ******************************\
45800 \ RC5_ComputeC6bit              \
45801 \ ******************************\
45802 BIT     #$4000,IP              \ test /C6 bit in IP
45803 0= IF   BIS #$40,TOS           \ set C6 bit in S
45804 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
45805 \ ******************************\
45806 \ RC5_CommandByteIsDone         \ RC5_code --
45807 \ ******************************\
45808
45809 \ ------------------------------\
45810 \ Display IR_RC5 code           \
45811 \ ------------------------------\
45812 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
45813 \ ------------------------------\
45814 LO2HI                           \ switch from assembler to FORTH
45815     ['] LCD_CLEAR IS CR         \ redirects CR
45816     ['] LCD_WrC  IS EMIT        \ redirects EMIT
45817     $10 BASE !                 \ change BASE to hexadecimal
45818     CR ." $" 2 U.R             \ print IR_RC5 code
45819     ['] (CR) IS CR              \ restore CR
45820     ['] (EMIT) IS EMIT          \ restore EMIT
45821 HI2LO                           \ switch from FORTH to assembler
45822 \ ------------------------------\
45823 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
45824 \ ------------------------------\
45825 MOV @PSP+,&BASE                 \ restore variable BASE
45826 RETI                            \ CPU is ON, GIE is OFF
45827 ENDASM                          \
45828     \ 
45829
45830 CODE START                      \
45831 \ ------------------------------\
45832 \ TB0CTL = %0000 0010 1001 0100\$3C0
45833 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
45834 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
45835 \                      --       \ID input divider \ 10 = /4
45836 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
45837 \                            -  \TBCLR TimerB Clear
45838 \                             - \TBIE
45839 \                              -\TBIFG
45840 \ --------------------------------\\
45841 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
45842 \              --                 \CM Capture Mode
45843 \                --               \CCIS
45844 \                   -             \SCS
45845 \                    --           \CLLD
45846 \                      -          \CAP
45847 \                        ---      \OUTMOD \ 011 = set/reset
45848 \                           -     \CCIE
45849 \                             -   \CCI
45850 \                              -  \OUT
45851 \                               - \COV
45852 \                                -\CCIFG
45853 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
45854 \ TB0EX0                          \$3E0 
45855 \ ------------------------------\
45856 \ set TimerB to make 50kHz PWM  \
45857 \ ------------------------------\
45858 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
45859 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
45860 \ ------------------------------\
45861 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
45862 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
45863 \ ------------------------------\
45864     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
45865     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
45866 \ ------------------------------\
45867 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
45868 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
45869 \ ------------------------------\
45870 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
45871 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
45872 \ ------------------------------\
45873     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
45874 \ ------------------------------\
45875 \ set TimerB to generate PWM for LCD_Vo
45876 \ ------------------------------\
45877     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
45878 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
45879     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
45880 \ ------------------------------\
45881     BIS.B #LCDVo,&LCDVo_DIR     \
45882     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
45883 \ ------------------------------\
45884     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
45885     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
45886 \ ------------------------------\
45887     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
45888     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
45889 \ ------------------------------\
45890 \ WDT interval init part        \
45891 \ ------------------------------\
45892     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
45893 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
45894 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
45895     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
45896 \ ------------------------------\
45897 \ init RC5_Int                  \
45898 \ ------------------------------\
45899     BIS.B #RC5,&IR_IE           \ enable RC5_Int
45900     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
45901 \ ------------------------------\
45902 \ init interrupt vectors
45903 \ ------------------------------\
45904     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
45905     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
45906 \ ------------------------------\
45907 \ define LPM mode for ACCEPT    \
45908 \ ------------------------------\
45909 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
45910 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
45911 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
45912
45913 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
45914
45915 \ ------------------------------\
45916 \ Init LCD 2x20                 \
45917 \ ------------------------------\
45918     $03E8 20_US                \ 1-  wait 20 ms
45919     $03 TOP_LCD                \ 2- send DB5=DB4=1
45920     $CD 20_US                  \ 3- wait 4,1 ms
45921     $03 TOP_LCD                \ 4- send again DB5=DB4=1
45922     $5 20_US                   \ 5- wait 0,1 ms
45923     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
45924     $2 20_US                   \    wait 40 us = LCD cycle
45925     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
45926     $2 20_US                   \    wait 40 us = LCD cycle
45927     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
45928     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
45929     LCD_Clear                   \ 10- "LCD_Clear"
45930     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
45931     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
45932     LCD_Clear                   \ 10- "LCD_Clear"
45933     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
45934     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
45935     CR ." I love you"   
45936     ['] (CR) IS CR              \ ' (CR) is CR
45937     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
45938     CR
45939     ."    RC5toLCD is running. Type STOP to quit"
45940 \    NOECHO                      \ uncomment to run this app without terminal connexion
45941     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
45942     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
45943 ;
45944     \
45945
45946 : STOP                  \ stops multitasking, must to be used before downloading app
45947     ['] (WARM) IS WARM  \ remove START app from FORTH init process
45948     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
45949 ;
45950     \
45951
45952
45953
45954 ECHO
45955             ; download is done
45956 RST_HERE    ; this app is protected against <reset>,
45957 \ START