OSDN Git Service

bug bug bug...
[fast-forth/master.git] / MSP430-FORTH / PROG10k.f
1 ; -----------------------------------
2 ; prog10k.4th
3 ; -----------------------------------
4     \
5 PWR_STATE
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 PWR_STATE
87
88
89 CODE MAX    \    n1 n2 -- n3       signed maximum
90             CMP     @PSP,TOS    \ n2-n1
91             S<      ?GOTO FW1   \ n2<n1
92 BW1         ADD     #2,PSP
93             MOV     @IP+,PC
94 ENDCODE
95     \
96
97 CODE MIN    \    n1 n2 -- n3       signed minimum
98             CMP     @PSP,TOS     \ n2-n1
99             S<      ?GOTO BW1    \ n2<n1
100 FW1         MOV     @PSP+,TOS
101             MOV     @IP+,PC
102 ENDCODE
103     \
104
105 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
106   >R  <# 0 # #S #>  
107   R> OVER - 0 MAX SPACES TYPE
108 ;
109     \
110
111 CODE 20_US                      \ n --      n * 20 us
112 BEGIN                           \ 3 cycles loop + 6~  
113 \    MOV     #5,W                \ 3 MCLK = 1 MHz
114 \    MOV     #23,W               \ 3 MCLK = 4 MHz
115     MOV     #51,W               \ 3 MCLK = 8 MHz
116 \    MOV     #104,W              \ 3 MCLK = 16 MHz
117 \    MOV     #158,W              \ 3 MCLK = 24 MHz
118     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
119         SUB #1,W                \ 1
120     0= UNTIL                    \ 2
121     SUB     #1,TOS              \ 1
122 0= UNTIL                        \ 2
123     MOV     @PSP+,TOS           \ 2
124     MOV     @IP+,PC             \ 4
125 ENDCODE
126     \
127
128 CODE TOP_LCD                    \ LCD Sample
129 \                               \ if write : %xxxxWWWW --
130 \                               \ if read  : -- %0000RRRR
131     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
132     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
133 0= IF                           \ write LCD bits pattern
134     AND.B #LCD_DB,TOS           \ 
135     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
136     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
137     MOV @PSP+,TOS               \
138     MOV @IP+,PC
139 THEN                            \ read LCD bits pattern
140     SUB #2,PSP
141     MOV TOS,0(PSP)
142     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
143     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
144     AND.B #LCD_DB,TOS           \
145     MOV @IP+,PC
146 ENDCODE
147     \
148
149 CODE LCD_W                      \ byte --       write byte to LCD 
150     SUB #2,PSP                  \
151     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
152     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
153     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
154     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
155 COLON                           \ high level word starts here 
156     TOP_LCD 2 20_US             \ write high nibble first
157     TOP_LCD 2 20_US 
158 ;
159     \
160
161 CODE LCD_WrC                    \ char --         Write Char
162     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
163     JMP LCD_W 
164 ENDCODE
165     \
166
167 CODE LCD_WrF                    \ func --         Write Fonction
168     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
169     JMP LCD_W 
170 ENDCODE
171     \
172
173 : LCD_Clear 
174     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
175 ;
176     \
177
178 : LCD_Home 
179     $02 LCD_WrF 100 20_us 
180 ;
181     \
182
183 \ : LCD_Entry_set       $04 OR LCD_WrF ;
184
185 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
186
187 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
188
189 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
190
191 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
192
193 \ : LCD_Goto            $80 OR LCD_WrF ;
194
195 \ CODE LCD_R                      \ -- byte       read byte from LCD
196 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
197 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
198 \ COLON                           \ starts a FORTH word
199 \     TOP_LCD 2 20_us             \ -- %0000HHHH
200 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
201 \ HI2LO                           \ switch from FORTH to assembler
202 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
203 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
204 \     MOV @RSP+,IP                \ restore IP saved by COLON
205 \     MOV @IP+,PC                 \
206 \ ENDCODE
207 \     \
208
209 \ CODE LCD_RdS                    \ -- status       Read Status
210 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
211 \     JMP LCD_R
212 \ ENDCODE
213 \     \
214
215 \ CODE LCD_RdC                    \ -- char         Read Char
216 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
217 \     JMP LCD_R
218 \ ENDCODE
219 \     \
220
221 \ -------------+------+------+------+------++---+---+---+---+---------+
222 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
223 \ -------------+------+------+------+------++---+---+---+---+---------+
224 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
225 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
226 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
227 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
228 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
229 \ -------------+------+------+------+------++---+---+---+---+---------+
230
231
232 \ ******************************\
233 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
234 \ ******************************\
235 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
236 \ ------------------------------\
237 \ define LPM mode for ACCEPT    \
238 \ ------------------------------\
239 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
240 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
241 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
242 BIT.B #SW2,&SW2_IN              \ test switch S2
243 0= IF                           \ case of switch S2 pressed
244     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
245     U< IF
246         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
247     THEN
248 ELSE
249     BIT.B #SW1,&SW1_IN          \ test switch S1 input
250     0= IF                       \ case of Switch S1 pressed
251         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
252         U>= IF                  \
253             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
254         THEN                    \
255     THEN                        \
256 THEN                            \
257 RETI                            \ CPU is ON, GIE is OFF
258 ENDASM                          \
259     \
260
261
262 \ ------------------------------\
263 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
264 \ ******************************\
265 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
266 \ ******************************\
267 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
268 \                               \       SMclock = 8|16|24 MHz
269 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
270 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
271 \                               \       SR(9)=new Toggle bit memory (ADD on)
272 \ ------------------------------\
273 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
274 \ ------------------------------\
275 \ define LPM mode for ACCEPT    \
276 \ ------------------------------\
277 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
278 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
279 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
280 \ ------------------------------\
281 \ RC5_FirstStartBitHalfCycle:   \
282 \ ------------------------------\
283 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
284 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
285 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
286 MOV     #1778,X                 \ RC5_Period in us
287 MOV     #14,W                   \ count of loop
288 BEGIN                           \
289 \ ------------------------------\
290 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
291 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
292     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
293 \ RC5_Compute_3/4_Period:       \                   |
294     RRUM    #1,X                \ X=1/2 cycle       |
295     MOV     X,Y                 \ Y=1/2             ^
296     RRUM    #1,Y                \ Y=1/4
297     ADD     X,Y                 \ Y=3/4
298 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
299     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
300     0= UNTIL                    \
301 \ ------------------------------\
302 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
303 \ ------------------------------\
304     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
305     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
306     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
307     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
308     SUB     #1,W                \ decrement count loop
309 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
310 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
311 0<> WHILE                       \ ----> out of loop ----+
312 \ RC5_compute_7/4_Time_out:     \                       |
313     ADD     X,Y                 \                       |   out of bound = 7/4 period 
314 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
315     BEGIN                       \                       |
316         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
317         0>= IF                  \                       |   if cycle time out of bound
318             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
319             RETI                \                       |   then quit to do nothing
320         THEN                    \                       |
321 \ ------------------------------\                       |
322         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
323     0<> UNTIL                   \                   |   |
324     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
325 REPEAT                          \ ----> loop back --+   |
326 \ ------------------------------\                       |
327 \ RC5_SampleEndOf:              \ <---------------------+
328 \ ------------------------------\
329 BIC     #$30,&TA0CTL           \ stop timer_A0
330 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
331 \ ******************************\
332 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
333 \ ******************************\
334 MOV     @RSP,X                  \ retiSR(9)  = old UF9 = old RC5 toggle bit
335 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
336 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
337 BIT     #BIT13,X                \ X(13) = New_RC5_command
338 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
339 THEN                            \
340 XOR     #UF9,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
341 \ ******************************\
342 \ RC5_ComputeNewRC5word         \
343 \ ******************************\
344 SUB     #4,PSP                  \
345 MOV     &BASE,2(PSP)            \ save variable BASE before use
346 MOV     TOS,0(PSP)              \ save TOS before use
347 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
348 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
349 \ ******************************\
350 \ RC5_ComputeC6bit              \
351 \ ******************************\
352 BIT     #$4000,IP              \ test /C6 bit in IP
353 0= IF   BIS #$40,TOS           \ set C6 bit in S
354 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
355 \ ******************************\
356 \ RC5_CommandByteIsDone         \ RC5_code --
357 \ ******************************\
358
359 \ ------------------------------\
360 \ Display IR_RC5 code           \
361 \ ------------------------------\
362 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
363 \ ------------------------------\
364 LO2HI                           \ switch from assembler to FORTH
365     ['] LCD_CLEAR IS CR         \ redirects CR
366     ['] LCD_WrC  IS EMIT        \ redirects EMIT
367     $10 BASE !                 \ change BASE to hexadecimal
368     CR ." $" 2 U.R             \ print IR_RC5 code
369     ['] (CR) IS CR              \ restore CR
370     ['] (EMIT) IS EMIT          \ restore EMIT
371 HI2LO                           \ switch from FORTH to assembler
372 \ ------------------------------\
373 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
374 \ ------------------------------\
375 MOV @PSP+,&BASE                 \ restore variable BASE
376 RETI                            \ CPU is ON, GIE is OFF
377 ENDASM                          \
378     \ 
379
380 CODE START                      \
381 \ ------------------------------\
382 \ TB0CTL = %0000 0010 1001 0100\$3C0
383 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
384 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
385 \                      --       \ID input divider \ 10 = /4
386 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
387 \                            -  \TBCLR TimerB Clear
388 \                             - \TBIE
389 \                              -\TBIFG
390 \ --------------------------------\\
391 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
392 \              --                 \CM Capture Mode
393 \                --               \CCIS
394 \                   -             \SCS
395 \                    --           \CLLD
396 \                      -          \CAP
397 \                        ---      \OUTMOD \ 011 = set/reset
398 \                           -     \CCIE
399 \                             -   \CCI
400 \                              -  \OUT
401 \                               - \COV
402 \                                -\CCIFG
403 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
404 \ TB0EX0                          \$3E0 
405 \ ------------------------------\
406 \ set TimerB to make 50kHz PWM  \
407 \ ------------------------------\
408 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
409 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
410 \ ------------------------------\
411 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
412 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
413 \ ------------------------------\
414     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
415     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
416 \ ------------------------------\
417 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
418 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
419 \ ------------------------------\
420 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
421 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
422 \ ------------------------------\
423     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
424 \ ------------------------------\
425 \ set TimerB to generate PWM for LCD_Vo
426 \ ------------------------------\
427     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
428 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
429     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
430 \ ------------------------------\
431     BIS.B #LCDVo,&LCDVo_DIR     \
432     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
433 \ ------------------------------\
434     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
435     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
436 \ ------------------------------\
437     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
438     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
439 \ ------------------------------\
440 \ WDT interval init part        \
441 \ ------------------------------\
442     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
443 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
444 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
445     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
446 \ ------------------------------\
447 \ init RC5_Int                  \
448 \ ------------------------------\
449     BIS.B #RC5,&IR_IE           \ enable RC5_Int
450     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
451 \ ------------------------------\
452 \ init interrupt vectors
453 \ ------------------------------\
454     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
455     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
456 \ ------------------------------\
457 \ define LPM mode for ACCEPT    \
458 \ ------------------------------\
459 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
460 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
461 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
462
463 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
464
465 \ ------------------------------\
466 \ Init LCD 2x20                 \
467 \ ------------------------------\
468     $03E8 20_US                \ 1-  wait 20 ms
469     $03 TOP_LCD                \ 2- send DB5=DB4=1
470     $CD 20_US                  \ 3- wait 4,1 ms
471     $03 TOP_LCD                \ 4- send again DB5=DB4=1
472     $5 20_US                   \ 5- wait 0,1 ms
473     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
474     $2 20_US                   \    wait 40 us = LCD cycle
475     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
476     $2 20_US                   \    wait 40 us = LCD cycle
477     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
478     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
479     LCD_Clear                   \ 10- "LCD_Clear"
480     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
481     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
482     LCD_Clear                   \ 10- "LCD_Clear"
483     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
484     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
485     CR ." I love you"   
486     ['] (CR) IS CR              \ ' (CR) is CR
487     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
488     CR
489     ."    RC5toLCD is running. Type STOP to quit"
490 \    NOECHO                      \ uncomment to run this app without terminal connexion
491     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
492     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
493 ;
494     \
495
496 : STOP                  \ stops multitasking, must to be used before downloading app
497     ['] (WARM) IS WARM  \ remove START app from FORTH init process
498     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
499 ;
500     \
501
502
503 PWR_STATE
504
505
506 CODE MAX    \    n1 n2 -- n3       signed maximum
507             CMP     @PSP,TOS    \ n2-n1
508             S<      ?GOTO FW1   \ n2<n1
509 BW1         ADD     #2,PSP
510             MOV     @IP+,PC
511 ENDCODE
512     \
513
514 CODE MIN    \    n1 n2 -- n3       signed minimum
515             CMP     @PSP,TOS     \ n2-n1
516             S<      ?GOTO BW1    \ n2<n1
517 FW1         MOV     @PSP+,TOS
518             MOV     @IP+,PC
519 ENDCODE
520     \
521
522 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
523   >R  <# 0 # #S #>  
524   R> OVER - 0 MAX SPACES TYPE
525 ;
526     \
527
528 CODE 20_US                      \ n --      n * 20 us
529 BEGIN                           \ 3 cycles loop + 6~  
530 \    MOV     #5,W                \ 3 MCLK = 1 MHz
531 \    MOV     #23,W               \ 3 MCLK = 4 MHz
532     MOV     #51,W               \ 3 MCLK = 8 MHz
533 \    MOV     #104,W              \ 3 MCLK = 16 MHz
534 \    MOV     #158,W              \ 3 MCLK = 24 MHz
535     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
536         SUB #1,W                \ 1
537     0= UNTIL                    \ 2
538     SUB     #1,TOS              \ 1
539 0= UNTIL                        \ 2
540     MOV     @PSP+,TOS           \ 2
541     MOV     @IP+,PC             \ 4
542 ENDCODE
543     \
544
545 CODE TOP_LCD                    \ LCD Sample
546 \                               \ if write : %xxxxWWWW --
547 \                               \ if read  : -- %0000RRRR
548     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
549     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
550 0= IF                           \ write LCD bits pattern
551     AND.B #LCD_DB,TOS           \ 
552     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
553     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
554     MOV @PSP+,TOS               \
555     MOV @IP+,PC
556 THEN                            \ read LCD bits pattern
557     SUB #2,PSP
558     MOV TOS,0(PSP)
559     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
560     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
561     AND.B #LCD_DB,TOS           \
562     MOV @IP+,PC
563 ENDCODE
564     \
565
566 CODE LCD_W                      \ byte --       write byte to LCD 
567     SUB #2,PSP                  \
568     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
569     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
570     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
571     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
572 COLON                           \ high level word starts here 
573     TOP_LCD 2 20_US             \ write high nibble first
574     TOP_LCD 2 20_US 
575 ;
576     \
577
578 CODE LCD_WrC                    \ char --         Write Char
579     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
580     JMP LCD_W 
581 ENDCODE
582     \
583
584 CODE LCD_WrF                    \ func --         Write Fonction
585     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
586     JMP LCD_W 
587 ENDCODE
588     \
589
590 : LCD_Clear 
591     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
592 ;
593     \
594
595 : LCD_Home 
596     $02 LCD_WrF 100 20_us 
597 ;
598     \
599
600 \ : LCD_Entry_set       $04 OR LCD_WrF ;
601
602 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
603
604 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
605
606 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
607
608 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
609
610 \ : LCD_Goto            $80 OR LCD_WrF ;
611
612 \ CODE LCD_R                      \ -- byte       read byte from LCD
613 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
614 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
615 \ COLON                           \ starts a FORTH word
616 \     TOP_LCD 2 20_us             \ -- %0000HHHH
617 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
618 \ HI2LO                           \ switch from FORTH to assembler
619 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
620 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
621 \     MOV @RSP+,IP                \ restore IP saved by COLON
622 \     MOV @IP+,PC                 \
623 \ ENDCODE
624 \     \
625
626 \ CODE LCD_RdS                    \ -- status       Read Status
627 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
628 \     JMP LCD_R
629 \ ENDCODE
630 \     \
631
632 \ CODE LCD_RdC                    \ -- char         Read Char
633 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
634 \     JMP LCD_R
635 \ ENDCODE
636 \     \
637
638 \ -------------+------+------+------+------++---+---+---+---+---------+
639 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
640 \ -------------+------+------+------+------++---+---+---+---+---------+
641 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
642 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
643 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
644 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
645 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
646 \ -------------+------+------+------+------++---+---+---+---+---------+
647
648
649 \ ******************************\
650 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
651 \ ******************************\
652 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
653 \ ------------------------------\
654 \ define LPM mode for ACCEPT    \
655 \ ------------------------------\
656 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
657 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
658 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
659 BIT.B #SW2,&SW2_IN              \ test switch S2
660 0= IF                           \ case of switch S2 pressed
661     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
662     U< IF
663         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
664     THEN
665 ELSE
666     BIT.B #SW1,&SW1_IN          \ test switch S1 input
667     0= IF                       \ case of Switch S1 pressed
668         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
669         U>= IF                  \
670             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
671         THEN                    \
672     THEN                        \
673 THEN                            \
674 RETI                            \ CPU is ON, GIE is OFF
675 ENDASM                          \
676     \
677
678
679 \ ------------------------------\
680 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
681 \ ******************************\
682 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
683 \ ******************************\
684 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
685 \                               \       SMclock = 8|16|24 MHz
686 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
687 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
688 \                               \       SR(9)=new Toggle bit memory (ADD on)
689 \ ------------------------------\
690 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
691 \ ------------------------------\
692 \ define LPM mode for ACCEPT    \
693 \ ------------------------------\
694 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
695 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
696 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
697 \ ------------------------------\
698 \ RC5_FirstStartBitHalfCycle:   \
699 \ ------------------------------\
700 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
701 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
702 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
703 MOV     #1778,X                 \ RC5_Period in us
704 MOV     #14,W                   \ count of loop
705 BEGIN                           \
706 \ ------------------------------\
707 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
708 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
709     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
710 \ RC5_Compute_3/4_Period:       \                   |
711     RRUM    #1,X                \ X=1/2 cycle       |
712     MOV     X,Y                 \ Y=1/2             ^
713     RRUM    #1,Y                \ Y=1/4
714     ADD     X,Y                 \ Y=3/4
715 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
716     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
717     0= UNTIL                    \
718 \ ------------------------------\
719 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
720 \ ------------------------------\
721     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
722     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
723     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
724     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
725     SUB     #1,W                \ decrement count loop
726 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
727 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
728 0<> WHILE                       \ ----> out of loop ----+
729 \ RC5_compute_7/4_Time_out:     \                       |
730     ADD     X,Y                 \                       |   out of bound = 7/4 period 
731 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
732     BEGIN                       \                       |
733         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
734         0>= IF                  \                       |   if cycle time out of bound
735             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
736             RETI                \                       |   then quit to do nothing
737         THEN                    \                       |
738 \ ------------------------------\                       |
739         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
740     0<> UNTIL                   \                   |   |
741     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
742 REPEAT                          \ ----> loop back --+   |
743 \ ------------------------------\                       |
744 \ RC5_SampleEndOf:              \ <---------------------+
745 \ ------------------------------\
746 BIC     #$30,&TA0CTL           \ stop timer_A0
747 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
748 \ ******************************\
749 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
750 \ ******************************\
751 MOV     @RSP,X                  \ retiSR(9)  = old UF9 = old RC5 toggle bit
752 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
753 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
754 BIT     #BIT13,X                \ X(13) = New_RC5_command
755 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
756 THEN                            \
757 XOR     #UF9,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
758 \ ******************************\
759 \ RC5_ComputeNewRC5word         \
760 \ ******************************\
761 SUB     #4,PSP                  \
762 MOV     &BASE,2(PSP)            \ save variable BASE before use
763 MOV     TOS,0(PSP)              \ save TOS before use
764 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
765 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
766 \ ******************************\
767 \ RC5_ComputeC6bit              \
768 \ ******************************\
769 BIT     #$4000,IP              \ test /C6 bit in IP
770 0= IF   BIS #$40,TOS           \ set C6 bit in S
771 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
772 \ ******************************\
773 \ RC5_CommandByteIsDone         \ RC5_code --
774 \ ******************************\
775
776 \ ------------------------------\
777 \ Display IR_RC5 code           \
778 \ ------------------------------\
779 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
780 \ ------------------------------\
781 LO2HI                           \ switch from assembler to FORTH
782     ['] LCD_CLEAR IS CR         \ redirects CR
783     ['] LCD_WrC  IS EMIT        \ redirects EMIT
784     $10 BASE !                 \ change BASE to hexadecimal
785     CR ." $" 2 U.R             \ print IR_RC5 code
786     ['] (CR) IS CR              \ restore CR
787     ['] (EMIT) IS EMIT          \ restore EMIT
788 HI2LO                           \ switch from FORTH to assembler
789 \ ------------------------------\
790 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
791 \ ------------------------------\
792 MOV @PSP+,&BASE                 \ restore variable BASE
793 RETI                            \ CPU is ON, GIE is OFF
794 ENDASM                          \
795     \ 
796
797 CODE START                      \
798 \ ------------------------------\
799 \ TB0CTL = %0000 0010 1001 0100\$3C0
800 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
801 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
802 \                      --       \ID input divider \ 10 = /4
803 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
804 \                            -  \TBCLR TimerB Clear
805 \                             - \TBIE
806 \                              -\TBIFG
807 \ --------------------------------\\
808 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
809 \              --                 \CM Capture Mode
810 \                --               \CCIS
811 \                   -             \SCS
812 \                    --           \CLLD
813 \                      -          \CAP
814 \                        ---      \OUTMOD \ 011 = set/reset
815 \                           -     \CCIE
816 \                             -   \CCI
817 \                              -  \OUT
818 \                               - \COV
819 \                                -\CCIFG
820 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
821 \ TB0EX0                          \$3E0 
822 \ ------------------------------\
823 \ set TimerB to make 50kHz PWM  \
824 \ ------------------------------\
825 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
826 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
827 \ ------------------------------\
828 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
829 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
830 \ ------------------------------\
831     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
832     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
833 \ ------------------------------\
834 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
835 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
836 \ ------------------------------\
837 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
838 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
839 \ ------------------------------\
840     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
841 \ ------------------------------\
842 \ set TimerB to generate PWM for LCD_Vo
843 \ ------------------------------\
844     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
845 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
846     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
847 \ ------------------------------\
848     BIS.B #LCDVo,&LCDVo_DIR     \
849     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
850 \ ------------------------------\
851     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
852     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
853 \ ------------------------------\
854     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
855     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
856 \ ------------------------------\
857 \ WDT interval init part        \
858 \ ------------------------------\
859     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
860 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
861 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
862     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
863 \ ------------------------------\
864 \ init RC5_Int                  \
865 \ ------------------------------\
866     BIS.B #RC5,&IR_IE           \ enable RC5_Int
867     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
868 \ ------------------------------\
869 \ init interrupt vectors
870 \ ------------------------------\
871     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
872     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
873 \ ------------------------------\
874 \ define LPM mode for ACCEPT    \
875 \ ------------------------------\
876 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
877 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
878 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
879
880 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
881
882 \ ------------------------------\
883 \ Init LCD 2x20                 \
884 \ ------------------------------\
885     $03E8 20_US                \ 1-  wait 20 ms
886     $03 TOP_LCD                \ 2- send DB5=DB4=1
887     $CD 20_US                  \ 3- wait 4,1 ms
888     $03 TOP_LCD                \ 4- send again DB5=DB4=1
889     $5 20_US                   \ 5- wait 0,1 ms
890     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
891     $2 20_US                   \    wait 40 us = LCD cycle
892     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
893     $2 20_US                   \    wait 40 us = LCD cycle
894     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
895     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
896     LCD_Clear                   \ 10- "LCD_Clear"
897     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
898     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
899     LCD_Clear                   \ 10- "LCD_Clear"
900     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
901     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
902     CR ." I love you"   
903     ['] (CR) IS CR              \ ' (CR) is CR
904     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
905     CR
906     ."    RC5toLCD is running. Type STOP to quit"
907 \    NOECHO                      \ uncomment to run this app without terminal connexion
908     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
909     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
910 ;
911     \
912
913 : STOP                  \ stops multitasking, must to be used before downloading app
914     ['] (WARM) IS WARM  \ remove START app from FORTH init process
915     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
916 ;
917     \
918
919
920
921 PWR_STATE
922
923
924 CODE MAX    \    n1 n2 -- n3       signed maximum
925             CMP     @PSP,TOS    \ n2-n1
926             S<      ?GOTO FW1   \ n2<n1
927 BW1         ADD     #2,PSP
928             MOV     @IP+,PC
929 ENDCODE
930     \
931
932 CODE MIN    \    n1 n2 -- n3       signed minimum
933             CMP     @PSP,TOS     \ n2-n1
934             S<      ?GOTO BW1    \ n2<n1
935 FW1         MOV     @PSP+,TOS
936             MOV     @IP+,PC
937 ENDCODE
938     \
939
940 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
941   >R  <# 0 # #S #>  
942   R> OVER - 0 MAX SPACES TYPE
943 ;
944     \
945
946 CODE 20_US                      \ n --      n * 20 us
947 BEGIN                           \ 3 cycles loop + 6~  
948 \    MOV     #5,W                \ 3 MCLK = 1 MHz
949 \    MOV     #23,W               \ 3 MCLK = 4 MHz
950     MOV     #51,W               \ 3 MCLK = 8 MHz
951 \    MOV     #104,W              \ 3 MCLK = 16 MHz
952 \    MOV     #158,W              \ 3 MCLK = 24 MHz
953     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
954         SUB #1,W                \ 1
955     0= UNTIL                    \ 2
956     SUB     #1,TOS              \ 1
957 0= UNTIL                        \ 2
958     MOV     @PSP+,TOS           \ 2
959     MOV     @IP+,PC             \ 4
960 ENDCODE
961     \
962
963 CODE TOP_LCD                    \ LCD Sample
964 \                               \ if write : %xxxxWWWW --
965 \                               \ if read  : -- %0000RRRR
966     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
967     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
968 0= IF                           \ write LCD bits pattern
969     AND.B #LCD_DB,TOS           \ 
970     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
971     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
972     MOV @PSP+,TOS               \
973     MOV @IP+,PC
974 THEN                            \ read LCD bits pattern
975     SUB #2,PSP
976     MOV TOS,0(PSP)
977     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
978     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
979     AND.B #LCD_DB,TOS           \
980     MOV @IP+,PC
981 ENDCODE
982     \
983
984 CODE LCD_W                      \ byte --       write byte to LCD 
985     SUB #2,PSP                  \
986     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
987     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
988     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
989     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
990 COLON                           \ high level word starts here 
991     TOP_LCD 2 20_US             \ write high nibble first
992     TOP_LCD 2 20_US 
993 ;
994     \
995
996 CODE LCD_WrC                    \ char --         Write Char
997     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
998     JMP LCD_W 
999 ENDCODE
1000     \
1001
1002 CODE LCD_WrF                    \ func --         Write Fonction
1003     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
1004     JMP LCD_W 
1005 ENDCODE
1006     \
1007
1008 : LCD_Clear 
1009     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
1010 ;
1011     \
1012
1013 : LCD_Home 
1014     $02 LCD_WrF 100 20_us 
1015 ;
1016     \
1017
1018 \ : LCD_Entry_set       $04 OR LCD_WrF ;
1019
1020 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
1021
1022 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
1023
1024 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
1025
1026 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
1027
1028 \ : LCD_Goto            $80 OR LCD_WrF ;
1029
1030 \ CODE LCD_R                      \ -- byte       read byte from LCD
1031 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
1032 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
1033 \ COLON                           \ starts a FORTH word
1034 \     TOP_LCD 2 20_us             \ -- %0000HHHH
1035 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
1036 \ HI2LO                           \ switch from FORTH to assembler
1037 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
1038 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
1039 \     MOV @RSP+,IP                \ restore IP saved by COLON
1040 \     MOV @IP+,PC                 \
1041 \ ENDCODE
1042 \     \
1043
1044 \ CODE LCD_RdS                    \ -- status       Read Status
1045 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
1046 \     JMP LCD_R
1047 \ ENDCODE
1048 \     \
1049
1050 \ CODE LCD_RdC                    \ -- char         Read Char
1051 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
1052 \     JMP LCD_R
1053 \ ENDCODE
1054 \     \
1055
1056 \ -------------+------+------+------+------++---+---+---+---+---------+
1057 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
1058 \ -------------+------+------+------+------++---+---+---+---+---------+
1059 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
1060 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
1061 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
1062 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
1063 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
1064 \ -------------+------+------+------+------++---+---+---+---+---------+
1065
1066
1067 \ ******************************\
1068 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
1069 \ ******************************\
1070 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
1071 \ ------------------------------\
1072 \ define LPM mode for ACCEPT    \
1073 \ ------------------------------\
1074 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
1075 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1076 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1077 BIT.B #SW2,&SW2_IN              \ test switch S2
1078 0= IF                           \ case of switch S2 pressed
1079     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
1080     U< IF
1081         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
1082     THEN
1083 ELSE
1084     BIT.B #SW1,&SW1_IN          \ test switch S1 input
1085     0= IF                       \ case of Switch S1 pressed
1086         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
1087         U>= IF                  \
1088             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
1089         THEN                    \
1090     THEN                        \
1091 THEN                            \
1092 RETI                            \ CPU is ON, GIE is OFF
1093 ENDASM                          \
1094     \
1095
1096
1097 \ ------------------------------\
1098 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
1099 \ ******************************\
1100 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
1101 \ ******************************\
1102 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
1103 \                               \       SMclock = 8|16|24 MHz
1104 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
1105 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
1106 \                               \       SR(9)=new Toggle bit memory (ADD on)
1107 \ ------------------------------\
1108 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
1109 \ ------------------------------\
1110 \ define LPM mode for ACCEPT    \
1111 \ ------------------------------\
1112 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
1113 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1114 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1115 \ ------------------------------\
1116 \ RC5_FirstStartBitHalfCycle:   \
1117 \ ------------------------------\
1118 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
1119 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
1120 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
1121 MOV     #1778,X                 \ RC5_Period in us
1122 MOV     #14,W                   \ count of loop
1123 BEGIN                           \
1124 \ ------------------------------\
1125 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
1126 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
1127     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
1128 \ RC5_Compute_3/4_Period:       \                   |
1129     RRUM    #1,X                \ X=1/2 cycle       |
1130     MOV     X,Y                 \ Y=1/2             ^
1131     RRUM    #1,Y                \ Y=1/4
1132     ADD     X,Y                 \ Y=3/4
1133 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
1134     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
1135     0= UNTIL                    \
1136 \ ------------------------------\
1137 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
1138 \ ------------------------------\
1139     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
1140     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
1141     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
1142     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
1143     SUB     #1,W                \ decrement count loop
1144 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
1145 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
1146 0<> WHILE                       \ ----> out of loop ----+
1147 \ RC5_compute_7/4_Time_out:     \                       |
1148     ADD     X,Y                 \                       |   out of bound = 7/4 period 
1149 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
1150     BEGIN                       \                       |
1151         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
1152         0>= IF                  \                       |   if cycle time out of bound
1153             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
1154             RETI                \                       |   then quit to do nothing
1155         THEN                    \                       |
1156 \ ------------------------------\                       |
1157         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
1158     0<> UNTIL                   \                   |   |
1159     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
1160 REPEAT                          \ ----> loop back --+   |
1161 \ ------------------------------\                       |
1162 \ RC5_SampleEndOf:              \ <---------------------+
1163 \ ------------------------------\
1164 BIC     #$30,&TA0CTL           \ stop timer_A0
1165 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
1166 \ ******************************\
1167 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
1168 \ ******************************\
1169 MOV     @RSP,X                  \ retiSR(9)  = old UF9 = old RC5 toggle bit
1170 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
1171 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
1172 BIT     #BIT13,X                \ X(13) = New_RC5_command
1173 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
1174 THEN                            \
1175 XOR     #UF9,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
1176 \ ******************************\
1177 \ RC5_ComputeNewRC5word         \
1178 \ ******************************\
1179 SUB     #4,PSP                  \
1180 MOV     &BASE,2(PSP)            \ save variable BASE before use
1181 MOV     TOS,0(PSP)              \ save TOS before use
1182 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
1183 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
1184 \ ******************************\
1185 \ RC5_ComputeC6bit              \
1186 \ ******************************\
1187 BIT     #$4000,IP              \ test /C6 bit in IP
1188 0= IF   BIS #$40,TOS           \ set C6 bit in S
1189 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
1190 \ ******************************\
1191 \ RC5_CommandByteIsDone         \ RC5_code --
1192 \ ******************************\
1193
1194 \ ------------------------------\
1195 \ Display IR_RC5 code           \
1196 \ ------------------------------\
1197 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
1198 \ ------------------------------\
1199 LO2HI                           \ switch from assembler to FORTH
1200     ['] LCD_CLEAR IS CR         \ redirects CR
1201     ['] LCD_WrC  IS EMIT        \ redirects EMIT
1202     $10 BASE !                 \ change BASE to hexadecimal
1203     CR ." $" 2 U.R             \ print IR_RC5 code
1204     ['] (CR) IS CR              \ restore CR
1205     ['] (EMIT) IS EMIT          \ restore EMIT
1206 HI2LO                           \ switch from FORTH to assembler
1207 \ ------------------------------\
1208 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
1209 \ ------------------------------\
1210 MOV @PSP+,&BASE                 \ restore variable BASE
1211 RETI                            \ CPU is ON, GIE is OFF
1212 ENDASM                          \
1213     \ 
1214
1215 CODE START                      \
1216 \ ------------------------------\
1217 \ TB0CTL = %0000 0010 1001 0100\$3C0
1218 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
1219 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
1220 \                      --       \ID input divider \ 10 = /4
1221 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
1222 \                            -  \TBCLR TimerB Clear
1223 \                             - \TBIE
1224 \                              -\TBIFG
1225 \ --------------------------------\\
1226 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
1227 \              --                 \CM Capture Mode
1228 \                --               \CCIS
1229 \                   -             \SCS
1230 \                    --           \CLLD
1231 \                      -          \CAP
1232 \                        ---      \OUTMOD \ 011 = set/reset
1233 \                           -     \CCIE
1234 \                             -   \CCI
1235 \                              -  \OUT
1236 \                               - \COV
1237 \                                -\CCIFG
1238 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
1239 \ TB0EX0                          \$3E0 
1240 \ ------------------------------\
1241 \ set TimerB to make 50kHz PWM  \
1242 \ ------------------------------\
1243 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
1244 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
1245 \ ------------------------------\
1246 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
1247 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
1248 \ ------------------------------\
1249     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
1250     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
1251 \ ------------------------------\
1252 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
1253 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
1254 \ ------------------------------\
1255 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
1256 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
1257 \ ------------------------------\
1258     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
1259 \ ------------------------------\
1260 \ set TimerB to generate PWM for LCD_Vo
1261 \ ------------------------------\
1262     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
1263 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
1264     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
1265 \ ------------------------------\
1266     BIS.B #LCDVo,&LCDVo_DIR     \
1267     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
1268 \ ------------------------------\
1269     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
1270     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
1271 \ ------------------------------\
1272     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
1273     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
1274 \ ------------------------------\
1275 \ WDT interval init part        \
1276 \ ------------------------------\
1277     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
1278 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
1279 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
1280     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
1281 \ ------------------------------\
1282 \ init RC5_Int                  \
1283 \ ------------------------------\
1284     BIS.B #RC5,&IR_IE           \ enable RC5_Int
1285     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
1286 \ ------------------------------\
1287 \ init interrupt vectors
1288 \ ------------------------------\
1289     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
1290     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
1291 \ ------------------------------\
1292 \ define LPM mode for ACCEPT    \
1293 \ ------------------------------\
1294 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
1295 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1296 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1297
1298 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
1299
1300 \ ------------------------------\
1301 \ Init LCD 2x20                 \
1302 \ ------------------------------\
1303     $03E8 20_US                \ 1-  wait 20 ms
1304     $03 TOP_LCD                \ 2- send DB5=DB4=1
1305     $CD 20_US                  \ 3- wait 4,1 ms
1306     $03 TOP_LCD                \ 4- send again DB5=DB4=1
1307     $5 20_US                   \ 5- wait 0,1 ms
1308     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
1309     $2 20_US                   \    wait 40 us = LCD cycle
1310     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
1311     $2 20_US                   \    wait 40 us = LCD cycle
1312     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
1313     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
1314     LCD_Clear                   \ 10- "LCD_Clear"
1315     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
1316     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
1317     LCD_Clear                   \ 10- "LCD_Clear"
1318     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
1319     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
1320     CR ." I love you"   
1321     ['] (CR) IS CR              \ ' (CR) is CR
1322     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
1323     CR
1324     ."    RC5toLCD is running. Type STOP to quit"
1325 \    NOECHO                      \ uncomment to run this app without terminal connexion
1326     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
1327     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
1328 ;
1329     \
1330
1331 : STOP                  \ stops multitasking, must to be used before downloading app
1332     ['] (WARM) IS WARM  \ remove START app from FORTH init process
1333     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
1334 ;
1335     \
1336
1337
1338
1339 PWR_STATE
1340
1341
1342 CODE MAX    \    n1 n2 -- n3       signed maximum
1343             CMP     @PSP,TOS    \ n2-n1
1344             S<      ?GOTO FW1   \ n2<n1
1345 BW1         ADD     #2,PSP
1346             MOV     @IP+,PC
1347 ENDCODE
1348     \
1349
1350 CODE MIN    \    n1 n2 -- n3       signed minimum
1351             CMP     @PSP,TOS     \ n2-n1
1352             S<      ?GOTO BW1    \ n2<n1
1353 FW1         MOV     @PSP+,TOS
1354             MOV     @IP+,PC
1355 ENDCODE
1356     \
1357
1358 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
1359   >R  <# 0 # #S #>  
1360   R> OVER - 0 MAX SPACES TYPE
1361 ;
1362     \
1363
1364 CODE 20_US                      \ n --      n * 20 us
1365 BEGIN                           \ 3 cycles loop + 6~  
1366 \    MOV     #5,W                \ 3 MCLK = 1 MHz
1367 \    MOV     #23,W               \ 3 MCLK = 4 MHz
1368     MOV     #51,W               \ 3 MCLK = 8 MHz
1369 \    MOV     #104,W              \ 3 MCLK = 16 MHz
1370 \    MOV     #158,W              \ 3 MCLK = 24 MHz
1371     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
1372         SUB #1,W                \ 1
1373     0= UNTIL                    \ 2
1374     SUB     #1,TOS              \ 1
1375 0= UNTIL                        \ 2
1376     MOV     @PSP+,TOS           \ 2
1377     MOV     @IP+,PC             \ 4
1378 ENDCODE
1379     \
1380
1381 CODE TOP_LCD                    \ LCD Sample
1382 \                               \ if write : %xxxxWWWW --
1383 \                               \ if read  : -- %0000RRRR
1384     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
1385     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
1386 0= IF                           \ write LCD bits pattern
1387     AND.B #LCD_DB,TOS           \ 
1388     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
1389     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
1390     MOV @PSP+,TOS               \
1391     MOV @IP+,PC
1392 THEN                            \ read LCD bits pattern
1393     SUB #2,PSP
1394     MOV TOS,0(PSP)
1395     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
1396     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
1397     AND.B #LCD_DB,TOS           \
1398     MOV @IP+,PC
1399 ENDCODE
1400     \
1401
1402 CODE LCD_W                      \ byte --       write byte to LCD 
1403     SUB #2,PSP                  \
1404     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
1405     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
1406     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
1407     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
1408 COLON                           \ high level word starts here 
1409     TOP_LCD 2 20_US             \ write high nibble first
1410     TOP_LCD 2 20_US 
1411 ;
1412     \
1413
1414 CODE LCD_WrC                    \ char --         Write Char
1415     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
1416     JMP LCD_W 
1417 ENDCODE
1418     \
1419
1420 CODE LCD_WrF                    \ func --         Write Fonction
1421     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
1422     JMP LCD_W 
1423 ENDCODE
1424     \
1425
1426 : LCD_Clear 
1427     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
1428 ;
1429     \
1430
1431 : LCD_Home 
1432     $02 LCD_WrF 100 20_us 
1433 ;
1434     \
1435
1436 \ : LCD_Entry_set       $04 OR LCD_WrF ;
1437
1438 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
1439
1440 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
1441
1442 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
1443
1444 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
1445
1446 \ : LCD_Goto            $80 OR LCD_WrF ;
1447
1448 \ CODE LCD_R                      \ -- byte       read byte from LCD
1449 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
1450 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
1451 \ COLON                           \ starts a FORTH word
1452 \     TOP_LCD 2 20_us             \ -- %0000HHHH
1453 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
1454 \ HI2LO                           \ switch from FORTH to assembler
1455 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
1456 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
1457 \     MOV @RSP+,IP                \ restore IP saved by COLON
1458 \     MOV @IP+,PC                 \
1459 \ ENDCODE
1460 \     \
1461
1462 \ CODE LCD_RdS                    \ -- status       Read Status
1463 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
1464 \     JMP LCD_R
1465 \ ENDCODE
1466 \     \
1467
1468 \ CODE LCD_RdC                    \ -- char         Read Char
1469 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
1470 \     JMP LCD_R
1471 \ ENDCODE
1472 \     \
1473
1474 \ -------------+------+------+------+------++---+---+---+---+---------+
1475 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
1476 \ -------------+------+------+------+------++---+---+---+---+---------+
1477 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
1478 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
1479 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
1480 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
1481 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
1482 \ -------------+------+------+------+------++---+---+---+---+---------+
1483
1484
1485 \ ******************************\
1486 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
1487 \ ******************************\
1488 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
1489 \ ------------------------------\
1490 \ define LPM mode for ACCEPT    \
1491 \ ------------------------------\
1492 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
1493 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1494 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1495 BIT.B #SW2,&SW2_IN              \ test switch S2
1496 0= IF                           \ case of switch S2 pressed
1497     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
1498     U< IF
1499         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
1500     THEN
1501 ELSE
1502     BIT.B #SW1,&SW1_IN          \ test switch S1 input
1503     0= IF                       \ case of Switch S1 pressed
1504         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
1505         U>= IF                  \
1506             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
1507         THEN                    \
1508     THEN                        \
1509 THEN                            \
1510 RETI                            \ CPU is ON, GIE is OFF
1511 ENDASM                          \
1512     \
1513
1514
1515 \ ------------------------------\
1516 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
1517 \ ******************************\
1518 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
1519 \ ******************************\
1520 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
1521 \                               \       SMclock = 8|16|24 MHz
1522 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
1523 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
1524 \                               \       SR(9)=new Toggle bit memory (ADD on)
1525 \ ------------------------------\
1526 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
1527 \ ------------------------------\
1528 \ define LPM mode for ACCEPT    \
1529 \ ------------------------------\
1530 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
1531 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1532 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1533 \ ------------------------------\
1534 \ RC5_FirstStartBitHalfCycle:   \
1535 \ ------------------------------\
1536 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
1537 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
1538 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
1539 MOV     #1778,X                 \ RC5_Period in us
1540 MOV     #14,W                   \ count of loop
1541 BEGIN                           \
1542 \ ------------------------------\
1543 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
1544 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
1545     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
1546 \ RC5_Compute_3/4_Period:       \                   |
1547     RRUM    #1,X                \ X=1/2 cycle       |
1548     MOV     X,Y                 \ Y=1/2             ^
1549     RRUM    #1,Y                \ Y=1/4
1550     ADD     X,Y                 \ Y=3/4
1551 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
1552     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
1553     0= UNTIL                    \
1554 \ ------------------------------\
1555 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
1556 \ ------------------------------\
1557     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
1558     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
1559     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
1560     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
1561     SUB     #1,W                \ decrement count loop
1562 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
1563 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
1564 0<> WHILE                       \ ----> out of loop ----+
1565 \ RC5_compute_7/4_Time_out:     \                       |
1566     ADD     X,Y                 \                       |   out of bound = 7/4 period 
1567 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
1568     BEGIN                       \                       |
1569         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
1570         0>= IF                  \                       |   if cycle time out of bound
1571             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
1572             RETI                \                       |   then quit to do nothing
1573         THEN                    \                       |
1574 \ ------------------------------\                       |
1575         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
1576     0<> UNTIL                   \                   |   |
1577     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
1578 REPEAT                          \ ----> loop back --+   |
1579 \ ------------------------------\                       |
1580 \ RC5_SampleEndOf:              \ <---------------------+
1581 \ ------------------------------\
1582 BIC     #$30,&TA0CTL           \ stop timer_A0
1583 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
1584 \ ******************************\
1585 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
1586 \ ******************************\
1587 MOV     @RSP,X                  \ retiSR(9)  = old UF9 = old RC5 toggle bit
1588 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
1589 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
1590 BIT     #BIT13,X                \ X(13) = New_RC5_command
1591 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
1592 THEN                            \
1593 XOR     #UF9,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
1594 \ ******************************\
1595 \ RC5_ComputeNewRC5word         \
1596 \ ******************************\
1597 SUB     #4,PSP                  \
1598 MOV     &BASE,2(PSP)            \ save variable BASE before use
1599 MOV     TOS,0(PSP)              \ save TOS before use
1600 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
1601 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
1602 \ ******************************\
1603 \ RC5_ComputeC6bit              \
1604 \ ******************************\
1605 BIT     #$4000,IP              \ test /C6 bit in IP
1606 0= IF   BIS #$40,TOS           \ set C6 bit in S
1607 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
1608 \ ******************************\
1609 \ RC5_CommandByteIsDone         \ RC5_code --
1610 \ ******************************\
1611
1612 \ ------------------------------\
1613 \ Display IR_RC5 code           \
1614 \ ------------------------------\
1615 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
1616 \ ------------------------------\
1617 LO2HI                           \ switch from assembler to FORTH
1618     ['] LCD_CLEAR IS CR         \ redirects CR
1619     ['] LCD_WrC  IS EMIT        \ redirects EMIT
1620     $10 BASE !                 \ change BASE to hexadecimal
1621     CR ." $" 2 U.R             \ print IR_RC5 code
1622     ['] (CR) IS CR              \ restore CR
1623     ['] (EMIT) IS EMIT          \ restore EMIT
1624 HI2LO                           \ switch from FORTH to assembler
1625 \ ------------------------------\
1626 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
1627 \ ------------------------------\
1628 MOV @PSP+,&BASE                 \ restore variable BASE
1629 RETI                            \ CPU is ON, GIE is OFF
1630 ENDASM                          \
1631     \ 
1632
1633 CODE START                      \
1634 \ ------------------------------\
1635 \ TB0CTL = %0000 0010 1001 0100\$3C0
1636 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
1637 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
1638 \                      --       \ID input divider \ 10 = /4
1639 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
1640 \                            -  \TBCLR TimerB Clear
1641 \                             - \TBIE
1642 \                              -\TBIFG
1643 \ --------------------------------\\
1644 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
1645 \              --                 \CM Capture Mode
1646 \                --               \CCIS
1647 \                   -             \SCS
1648 \                    --           \CLLD
1649 \                      -          \CAP
1650 \                        ---      \OUTMOD \ 011 = set/reset
1651 \                           -     \CCIE
1652 \                             -   \CCI
1653 \                              -  \OUT
1654 \                               - \COV
1655 \                                -\CCIFG
1656 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
1657 \ TB0EX0                          \$3E0 
1658 \ ------------------------------\
1659 \ set TimerB to make 50kHz PWM  \
1660 \ ------------------------------\
1661 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
1662 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
1663 \ ------------------------------\
1664 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
1665 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
1666 \ ------------------------------\
1667     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
1668     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
1669 \ ------------------------------\
1670 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
1671 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
1672 \ ------------------------------\
1673 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
1674 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
1675 \ ------------------------------\
1676     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
1677 \ ------------------------------\
1678 \ set TimerB to generate PWM for LCD_Vo
1679 \ ------------------------------\
1680     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
1681 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
1682     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
1683 \ ------------------------------\
1684     BIS.B #LCDVo,&LCDVo_DIR     \
1685     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
1686 \ ------------------------------\
1687     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
1688     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
1689 \ ------------------------------\
1690     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
1691     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
1692 \ ------------------------------\
1693 \ WDT interval init part        \
1694 \ ------------------------------\
1695     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
1696 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
1697 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
1698     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
1699 \ ------------------------------\
1700 \ init RC5_Int                  \
1701 \ ------------------------------\
1702     BIS.B #RC5,&IR_IE           \ enable RC5_Int
1703     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
1704 \ ------------------------------\
1705 \ init interrupt vectors
1706 \ ------------------------------\
1707     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
1708     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
1709 \ ------------------------------\
1710 \ define LPM mode for ACCEPT    \
1711 \ ------------------------------\
1712 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
1713 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1714 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1715
1716 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
1717
1718 \ ------------------------------\
1719 \ Init LCD 2x20                 \
1720 \ ------------------------------\
1721     $03E8 20_US                \ 1-  wait 20 ms
1722     $03 TOP_LCD                \ 2- send DB5=DB4=1
1723     $CD 20_US                  \ 3- wait 4,1 ms
1724     $03 TOP_LCD                \ 4- send again DB5=DB4=1
1725     $5 20_US                   \ 5- wait 0,1 ms
1726     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
1727     $2 20_US                   \    wait 40 us = LCD cycle
1728     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
1729     $2 20_US                   \    wait 40 us = LCD cycle
1730     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
1731     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
1732     LCD_Clear                   \ 10- "LCD_Clear"
1733     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
1734     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
1735     LCD_Clear                   \ 10- "LCD_Clear"
1736     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
1737     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
1738     CR ." I love you"   
1739     ['] (CR) IS CR              \ ' (CR) is CR
1740     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
1741     CR
1742     ."    RC5toLCD is running. Type STOP to quit"
1743 \    NOECHO                      \ uncomment to run this app without terminal connexion
1744     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
1745     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
1746 ;
1747     \
1748
1749 : STOP                  \ stops multitasking, must to be used before downloading app
1750     ['] (WARM) IS WARM  \ remove START app from FORTH init process
1751     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
1752 ;
1753     \
1754
1755
1756
1757 PWR_STATE
1758
1759
1760 CODE MAX    \    n1 n2 -- n3       signed maximum
1761             CMP     @PSP,TOS    \ n2-n1
1762             S<      ?GOTO FW1   \ n2<n1
1763 BW1         ADD     #2,PSP
1764             MOV     @IP+,PC
1765 ENDCODE
1766     \
1767
1768 CODE MIN    \    n1 n2 -- n3       signed minimum
1769             CMP     @PSP,TOS     \ n2-n1
1770             S<      ?GOTO BW1    \ n2<n1
1771 FW1         MOV     @PSP+,TOS
1772             MOV     @IP+,PC
1773 ENDCODE
1774     \
1775
1776 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
1777   >R  <# 0 # #S #>  
1778   R> OVER - 0 MAX SPACES TYPE
1779 ;
1780     \
1781
1782 CODE 20_US                      \ n --      n * 20 us
1783 BEGIN                           \ 3 cycles loop + 6~  
1784 \    MOV     #5,W                \ 3 MCLK = 1 MHz
1785 \    MOV     #23,W               \ 3 MCLK = 4 MHz
1786     MOV     #51,W               \ 3 MCLK = 8 MHz
1787 \    MOV     #104,W              \ 3 MCLK = 16 MHz
1788 \    MOV     #158,W              \ 3 MCLK = 24 MHz
1789     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
1790         SUB #1,W                \ 1
1791     0= UNTIL                    \ 2
1792     SUB     #1,TOS              \ 1
1793 0= UNTIL                        \ 2
1794     MOV     @PSP+,TOS           \ 2
1795     MOV     @IP+,PC             \ 4
1796 ENDCODE
1797     \
1798
1799 CODE TOP_LCD                    \ LCD Sample
1800 \                               \ if write : %xxxxWWWW --
1801 \                               \ if read  : -- %0000RRRR
1802     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
1803     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
1804 0= IF                           \ write LCD bits pattern
1805     AND.B #LCD_DB,TOS           \ 
1806     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
1807     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
1808     MOV @PSP+,TOS               \
1809     MOV @IP+,PC
1810 THEN                            \ read LCD bits pattern
1811     SUB #2,PSP
1812     MOV TOS,0(PSP)
1813     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
1814     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
1815     AND.B #LCD_DB,TOS           \
1816     MOV @IP+,PC
1817 ENDCODE
1818     \
1819
1820 CODE LCD_W                      \ byte --       write byte to LCD 
1821     SUB #2,PSP                  \
1822     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
1823     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
1824     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
1825     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
1826 COLON                           \ high level word starts here 
1827     TOP_LCD 2 20_US             \ write high nibble first
1828     TOP_LCD 2 20_US 
1829 ;
1830     \
1831
1832 CODE LCD_WrC                    \ char --         Write Char
1833     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
1834     JMP LCD_W 
1835 ENDCODE
1836     \
1837
1838 CODE LCD_WrF                    \ func --         Write Fonction
1839     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
1840     JMP LCD_W 
1841 ENDCODE
1842     \
1843
1844 : LCD_Clear 
1845     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
1846 ;
1847     \
1848
1849 : LCD_Home 
1850     $02 LCD_WrF 100 20_us 
1851 ;
1852     \
1853
1854 \ : LCD_Entry_set       $04 OR LCD_WrF ;
1855
1856 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
1857
1858 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
1859
1860 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
1861
1862 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
1863
1864 \ : LCD_Goto            $80 OR LCD_WrF ;
1865
1866 \ CODE LCD_R                      \ -- byte       read byte from LCD
1867 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
1868 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
1869 \ COLON                           \ starts a FORTH word
1870 \     TOP_LCD 2 20_us             \ -- %0000HHHH
1871 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
1872 \ HI2LO                           \ switch from FORTH to assembler
1873 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
1874 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
1875 \     MOV @RSP+,IP                \ restore IP saved by COLON
1876 \     MOV @IP+,PC                 \
1877 \ ENDCODE
1878 \     \
1879
1880 \ CODE LCD_RdS                    \ -- status       Read Status
1881 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
1882 \     JMP LCD_R
1883 \ ENDCODE
1884 \     \
1885
1886 \ CODE LCD_RdC                    \ -- char         Read Char
1887 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
1888 \     JMP LCD_R
1889 \ ENDCODE
1890 \     \
1891
1892 \ -------------+------+------+------+------++---+---+---+---+---------+
1893 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
1894 \ -------------+------+------+------+------++---+---+---+---+---------+
1895 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
1896 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
1897 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
1898 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
1899 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
1900 \ -------------+------+------+------+------++---+---+---+---+---------+
1901
1902
1903 \ ******************************\
1904 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
1905 \ ******************************\
1906 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
1907 \ ------------------------------\
1908 \ define LPM mode for ACCEPT    \
1909 \ ------------------------------\
1910 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
1911 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1912 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1913 BIT.B #SW2,&SW2_IN              \ test switch S2
1914 0= IF                           \ case of switch S2 pressed
1915     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
1916     U< IF
1917         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
1918     THEN
1919 ELSE
1920     BIT.B #SW1,&SW1_IN          \ test switch S1 input
1921     0= IF                       \ case of Switch S1 pressed
1922         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
1923         U>= IF                  \
1924             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
1925         THEN                    \
1926     THEN                        \
1927 THEN                            \
1928 RETI                            \ CPU is ON, GIE is OFF
1929 ENDASM                          \
1930     \
1931
1932
1933 \ ------------------------------\
1934 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
1935 \ ******************************\
1936 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
1937 \ ******************************\
1938 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
1939 \                               \       SMclock = 8|16|24 MHz
1940 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
1941 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
1942 \                               \       SR(9)=new Toggle bit memory (ADD on)
1943 \ ------------------------------\
1944 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
1945 \ ------------------------------\
1946 \ define LPM mode for ACCEPT    \
1947 \ ------------------------------\
1948 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
1949 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
1950 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
1951 \ ------------------------------\
1952 \ RC5_FirstStartBitHalfCycle:   \
1953 \ ------------------------------\
1954 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
1955 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
1956 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
1957 MOV     #1778,X                 \ RC5_Period in us
1958 MOV     #14,W                   \ count of loop
1959 BEGIN                           \
1960 \ ------------------------------\
1961 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
1962 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
1963     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
1964 \ RC5_Compute_3/4_Period:       \                   |
1965     RRUM    #1,X                \ X=1/2 cycle       |
1966     MOV     X,Y                 \ Y=1/2             ^
1967     RRUM    #1,Y                \ Y=1/4
1968     ADD     X,Y                 \ Y=3/4
1969 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
1970     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
1971     0= UNTIL                    \
1972 \ ------------------------------\
1973 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
1974 \ ------------------------------\
1975     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
1976     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
1977     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
1978     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
1979     SUB     #1,W                \ decrement count loop
1980 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
1981 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
1982 0<> WHILE                       \ ----> out of loop ----+
1983 \ RC5_compute_7/4_Time_out:     \                       |
1984     ADD     X,Y                 \                       |   out of bound = 7/4 period 
1985 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
1986     BEGIN                       \                       |
1987         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
1988         0>= IF                  \                       |   if cycle time out of bound
1989             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
1990             RETI                \                       |   then quit to do nothing
1991         THEN                    \                       |
1992 \ ------------------------------\                       |
1993         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
1994     0<> UNTIL                   \                   |   |
1995     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
1996 REPEAT                          \ ----> loop back --+   |
1997 \ ------------------------------\                       |
1998 \ RC5_SampleEndOf:              \ <---------------------+
1999 \ ------------------------------\
2000 BIC     #$30,&TA0CTL           \ stop timer_A0
2001 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
2002 \ ******************************\
2003 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
2004 \ ******************************\
2005 MOV     @RSP,X                  \ retiSR(9)  = old UF9 = old RC5 toggle bit
2006 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
2007 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
2008 BIT     #BIT13,X                \ X(13) = New_RC5_command
2009 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
2010 THEN                            \
2011 XOR     #UF9,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
2012 \ ******************************\
2013 \ RC5_ComputeNewRC5word         \
2014 \ ******************************\
2015 SUB     #4,PSP                  \
2016 MOV     &BASE,2(PSP)            \ save variable BASE before use
2017 MOV     TOS,0(PSP)              \ save TOS before use
2018 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
2019 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
2020 \ ******************************\
2021 \ RC5_ComputeC6bit              \
2022 \ ******************************\
2023 BIT     #$4000,IP              \ test /C6 bit in IP
2024 0= IF   BIS #$40,TOS           \ set C6 bit in S
2025 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
2026 \ ******************************\
2027 \ RC5_CommandByteIsDone         \ RC5_code --
2028 \ ******************************\
2029
2030 \ ------------------------------\
2031 \ Display IR_RC5 code           \
2032 \ ------------------------------\
2033 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
2034 \ ------------------------------\
2035 LO2HI                           \ switch from assembler to FORTH
2036     ['] LCD_CLEAR IS CR         \ redirects CR
2037     ['] LCD_WrC  IS EMIT        \ redirects EMIT
2038     $10 BASE !                 \ change BASE to hexadecimal
2039     CR ." $" 2 U.R             \ print IR_RC5 code
2040     ['] (CR) IS CR              \ restore CR
2041     ['] (EMIT) IS EMIT          \ restore EMIT
2042 HI2LO                           \ switch from FORTH to assembler
2043 \ ------------------------------\
2044 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
2045 \ ------------------------------\
2046 MOV @PSP+,&BASE                 \ restore variable BASE
2047 RETI                            \ CPU is ON, GIE is OFF
2048 ENDASM                          \
2049     \ 
2050
2051 CODE START                      \
2052 \ ------------------------------\
2053 \ TB0CTL = %0000 0010 1001 0100\$3C0
2054 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
2055 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
2056 \                      --       \ID input divider \ 10 = /4
2057 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
2058 \                            -  \TBCLR TimerB Clear
2059 \                             - \TBIE
2060 \                              -\TBIFG
2061 \ --------------------------------\\
2062 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
2063 \              --                 \CM Capture Mode
2064 \                --               \CCIS
2065 \                   -             \SCS
2066 \                    --           \CLLD
2067 \                      -          \CAP
2068 \                        ---      \OUTMOD \ 011 = set/reset
2069 \                           -     \CCIE
2070 \                             -   \CCI
2071 \                              -  \OUT
2072 \                               - \COV
2073 \                                -\CCIFG
2074 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
2075 \ TB0EX0                          \$3E0 
2076 \ ------------------------------\
2077 \ set TimerB to make 50kHz PWM  \
2078 \ ------------------------------\
2079 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
2080 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
2081 \ ------------------------------\
2082 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
2083 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
2084 \ ------------------------------\
2085     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
2086     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
2087 \ ------------------------------\
2088 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
2089 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
2090 \ ------------------------------\
2091 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
2092 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
2093 \ ------------------------------\
2094     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
2095 \ ------------------------------\
2096 \ set TimerB to generate PWM for LCD_Vo
2097 \ ------------------------------\
2098     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
2099 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
2100     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
2101 \ ------------------------------\
2102     BIS.B #LCDVo,&LCDVo_DIR     \
2103     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
2104 \ ------------------------------\
2105     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
2106     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
2107 \ ------------------------------\
2108     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
2109     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
2110 \ ------------------------------\
2111 \ WDT interval init part        \
2112 \ ------------------------------\
2113     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
2114 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
2115 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
2116     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
2117 \ ------------------------------\
2118 \ init RC5_Int                  \
2119 \ ------------------------------\
2120     BIS.B #RC5,&IR_IE           \ enable RC5_Int
2121     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
2122 \ ------------------------------\
2123 \ init interrupt vectors
2124 \ ------------------------------\
2125     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
2126     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
2127 \ ------------------------------\
2128 \ define LPM mode for ACCEPT    \
2129 \ ------------------------------\
2130 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
2131 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
2132 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
2133
2134 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
2135
2136 \ ------------------------------\
2137 \ Init LCD 2x20                 \
2138 \ ------------------------------\
2139     $03E8 20_US                \ 1-  wait 20 ms
2140     $03 TOP_LCD                \ 2- send DB5=DB4=1
2141     $CD 20_US                  \ 3- wait 4,1 ms
2142     $03 TOP_LCD                \ 4- send again DB5=DB4=1
2143     $5 20_US                   \ 5- wait 0,1 ms
2144     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
2145     $2 20_US                   \    wait 40 us = LCD cycle
2146     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
2147     $2 20_US                   \    wait 40 us = LCD cycle
2148     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
2149     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
2150     LCD_Clear                   \ 10- "LCD_Clear"
2151     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
2152     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
2153     LCD_Clear                   \ 10- "LCD_Clear"
2154     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
2155     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
2156     CR ." I love you"   
2157     ['] (CR) IS CR              \ ' (CR) is CR
2158     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
2159     CR
2160     ."    RC5toLCD is running. Type STOP to quit"
2161 \    NOECHO                      \ uncomment to run this app without terminal connexion
2162     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
2163     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
2164 ;
2165     \
2166
2167 : STOP                  \ stops multitasking, must to be used before downloading app
2168     ['] (WARM) IS WARM  \ remove START app from FORTH init process
2169     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
2170 ;
2171     \
2172
2173
2174
2175 PWR_STATE
2176
2177
2178 CODE MAX    \    n1 n2 -- n3       signed maximum
2179             CMP     @PSP,TOS    \ n2-n1
2180             S<      ?GOTO FW1   \ n2<n1
2181 BW1         ADD     #2,PSP
2182             MOV     @IP+,PC
2183 ENDCODE
2184     \
2185
2186 CODE MIN    \    n1 n2 -- n3       signed minimum
2187             CMP     @PSP,TOS     \ n2-n1
2188             S<      ?GOTO BW1    \ n2<n1
2189 FW1         MOV     @PSP+,TOS
2190             MOV     @IP+,PC
2191 ENDCODE
2192     \
2193
2194 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
2195   >R  <# 0 # #S #>  
2196   R> OVER - 0 MAX SPACES TYPE
2197 ;
2198     \
2199
2200 CODE 20_US                      \ n --      n * 20 us
2201 BEGIN                           \ 3 cycles loop + 6~  
2202 \    MOV     #5,W                \ 3 MCLK = 1 MHz
2203 \    MOV     #23,W               \ 3 MCLK = 4 MHz
2204     MOV     #51,W               \ 3 MCLK = 8 MHz
2205 \    MOV     #104,W              \ 3 MCLK = 16 MHz
2206 \    MOV     #158,W              \ 3 MCLK = 24 MHz
2207     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
2208         SUB #1,W                \ 1
2209     0= UNTIL                    \ 2
2210     SUB     #1,TOS              \ 1
2211 0= UNTIL                        \ 2
2212     MOV     @PSP+,TOS           \ 2
2213     MOV     @IP+,PC             \ 4
2214 ENDCODE
2215     \
2216
2217 CODE TOP_LCD                    \ LCD Sample
2218 \                               \ if write : %xxxxWWWW --
2219 \                               \ if read  : -- %0000RRRR
2220     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
2221     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
2222 0= IF                           \ write LCD bits pattern
2223     AND.B #LCD_DB,TOS           \ 
2224     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
2225     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
2226     MOV @PSP+,TOS               \
2227     MOV @IP+,PC
2228 THEN                            \ read LCD bits pattern
2229     SUB #2,PSP
2230     MOV TOS,0(PSP)
2231     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
2232     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
2233     AND.B #LCD_DB,TOS           \
2234     MOV @IP+,PC
2235 ENDCODE
2236     \
2237
2238 CODE LCD_W                      \ byte --       write byte to LCD 
2239     SUB #2,PSP                  \
2240     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
2241     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
2242     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
2243     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
2244 COLON                           \ high level word starts here 
2245     TOP_LCD 2 20_US             \ write high nibble first
2246     TOP_LCD 2 20_US 
2247 ;
2248     \
2249
2250 CODE LCD_WrC                    \ char --         Write Char
2251     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
2252     JMP LCD_W 
2253 ENDCODE
2254     \
2255
2256 CODE LCD_WrF                    \ func --         Write Fonction
2257     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
2258     JMP LCD_W 
2259 ENDCODE
2260     \
2261
2262 : LCD_Clear 
2263     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
2264 ;
2265     \
2266
2267 : LCD_Home 
2268     $02 LCD_WrF 100 20_us 
2269 ;
2270     \
2271
2272 \ : LCD_Entry_set       $04 OR LCD_WrF ;
2273
2274 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
2275
2276 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
2277
2278 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
2279
2280 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
2281
2282 \ : LCD_Goto            $80 OR LCD_WrF ;
2283
2284 \ CODE LCD_R                      \ -- byte       read byte from LCD
2285 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
2286 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
2287 \ COLON                           \ starts a FORTH word
2288 \     TOP_LCD 2 20_us             \ -- %0000HHHH
2289 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
2290 \ HI2LO                           \ switch from FORTH to assembler
2291 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
2292 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
2293 \     MOV @RSP+,IP                \ restore IP saved by COLON
2294 \     MOV @IP+,PC                 \
2295 \ ENDCODE
2296 \     \
2297
2298 \ CODE LCD_RdS                    \ -- status       Read Status
2299 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
2300 \     JMP LCD_R
2301 \ ENDCODE
2302 \     \
2303
2304 \ CODE LCD_RdC                    \ -- char         Read Char
2305 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
2306 \     JMP LCD_R
2307 \ ENDCODE
2308 \     \
2309
2310 \ -------------+------+------+------+------++---+---+---+---+---------+
2311 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
2312 \ -------------+------+------+------+------++---+---+---+---+---------+
2313 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
2314 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
2315 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
2316 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
2317 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
2318 \ -------------+------+------+------+------++---+---+---+---+---------+
2319
2320
2321 \ ******************************\
2322 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
2323 \ ******************************\
2324 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
2325 \ ------------------------------\
2326 \ define LPM mode for ACCEPT    \
2327 \ ------------------------------\
2328 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
2329 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
2330 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
2331 BIT.B #SW2,&SW2_IN              \ test switch S2
2332 0= IF                           \ case of switch S2 pressed
2333     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
2334     U< IF
2335         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
2336     THEN
2337 ELSE
2338     BIT.B #SW1,&SW1_IN          \ test switch S1 input
2339     0= IF                       \ case of Switch S1 pressed
2340         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
2341         U>= IF                  \
2342             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
2343         THEN                    \
2344     THEN                        \
2345 THEN                            \
2346 RETI                            \ CPU is ON, GIE is OFF
2347 ENDASM                          \
2348     \
2349
2350
2351 \ ------------------------------\
2352 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
2353 \ ******************************\
2354 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
2355 \ ******************************\
2356 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
2357 \                               \       SMclock = 8|16|24 MHz
2358 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
2359 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
2360 \                               \       SR(9)=new Toggle bit memory (ADD on)
2361 \ ------------------------------\
2362 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
2363 \ ------------------------------\
2364 \ define LPM mode for ACCEPT    \
2365 \ ------------------------------\
2366 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
2367 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
2368 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
2369 \ ------------------------------\
2370 \ RC5_FirstStartBitHalfCycle:   \
2371 \ ------------------------------\
2372 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
2373 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
2374 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
2375 MOV     #1778,X                 \ RC5_Period in us
2376 MOV     #14,W                   \ count of loop
2377 BEGIN                           \
2378 \ ------------------------------\
2379 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
2380 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
2381     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
2382 \ RC5_Compute_3/4_Period:       \                   |
2383     RRUM    #1,X                \ X=1/2 cycle       |
2384     MOV     X,Y                 \ Y=1/2             ^
2385     RRUM    #1,Y                \ Y=1/4
2386     ADD     X,Y                 \ Y=3/4
2387 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
2388     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
2389     0= UNTIL                    \
2390 \ ------------------------------\
2391 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
2392 \ ------------------------------\
2393     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
2394     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
2395     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
2396     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
2397     SUB     #1,W                \ decrement count loop
2398 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
2399 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
2400 0<> WHILE                       \ ----> out of loop ----+
2401 \ RC5_compute_7/4_Time_out:     \                       |
2402     ADD     X,Y                 \                       |   out of bound = 7/4 period 
2403 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
2404     BEGIN                       \                       |
2405         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
2406         0>= IF                  \                       |   if cycle time out of bound
2407             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
2408             RETI                \                       |   then quit to do nothing
2409         THEN                    \                       |
2410 \ ------------------------------\                       |
2411         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
2412     0<> UNTIL                   \                   |   |
2413     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
2414 REPEAT                          \ ----> loop back --+   |
2415 \ ------------------------------\                       |
2416 \ RC5_SampleEndOf:              \ <---------------------+
2417 \ ------------------------------\
2418 BIC     #$30,&TA0CTL           \ stop timer_A0
2419 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
2420 \ ******************************\
2421 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
2422 \ ******************************\
2423 MOV     @RSP,X                  \ retiSR(9)  = old UF9 = old RC5 toggle bit
2424 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
2425 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
2426 BIT     #BIT13,X                \ X(13) = New_RC5_command
2427 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
2428 THEN                            \
2429 XOR     #UF9,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
2430 \ ******************************\
2431 \ RC5_ComputeNewRC5word         \
2432 \ ******************************\
2433 SUB     #4,PSP                  \
2434 MOV     &BASE,2(PSP)            \ save variable BASE before use
2435 MOV     TOS,0(PSP)              \ save TOS before use
2436 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
2437 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
2438 \ ******************************\
2439 \ RC5_ComputeC6bit              \
2440 \ ******************************\
2441 BIT     #$4000,IP              \ test /C6 bit in IP
2442 0= IF   BIS #$40,TOS           \ set C6 bit in S
2443 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
2444 \ ******************************\
2445 \ RC5_CommandByteIsDone         \ RC5_code --
2446 \ ******************************\
2447
2448 \ ------------------------------\
2449 \ Display IR_RC5 code           \
2450 \ ------------------------------\
2451 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
2452 \ ------------------------------\
2453 LO2HI                           \ switch from assembler to FORTH
2454     ['] LCD_CLEAR IS CR         \ redirects CR
2455     ['] LCD_WrC  IS EMIT        \ redirects EMIT
2456     $10 BASE !                 \ change BASE to hexadecimal
2457     CR ." $" 2 U.R             \ print IR_RC5 code
2458     ['] (CR) IS CR              \ restore CR
2459     ['] (EMIT) IS EMIT          \ restore EMIT
2460 HI2LO                           \ switch from FORTH to assembler
2461 \ ------------------------------\
2462 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
2463 \ ------------------------------\
2464 MOV @PSP+,&BASE                 \ restore variable BASE
2465 RETI                            \ CPU is ON, GIE is OFF
2466 ENDASM                          \
2467     \ 
2468
2469 CODE START                      \
2470 \ ------------------------------\
2471 \ TB0CTL = %0000 0010 1001 0100\$3C0
2472 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
2473 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
2474 \                      --       \ID input divider \ 10 = /4
2475 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
2476 \                            -  \TBCLR TimerB Clear
2477 \                             - \TBIE
2478 \                              -\TBIFG
2479 \ --------------------------------\\
2480 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
2481 \              --                 \CM Capture Mode
2482 \                --               \CCIS
2483 \                   -             \SCS
2484 \                    --           \CLLD
2485 \                      -          \CAP
2486 \                        ---      \OUTMOD \ 011 = set/reset
2487 \                           -     \CCIE
2488 \                             -   \CCI
2489 \                              -  \OUT
2490 \                               - \COV
2491 \                                -\CCIFG
2492 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
2493 \ TB0EX0                          \$3E0 
2494 \ ------------------------------\
2495 \ set TimerB to make 50kHz PWM  \
2496 \ ------------------------------\
2497 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
2498 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
2499 \ ------------------------------\
2500 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
2501 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
2502 \ ------------------------------\
2503     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
2504     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
2505 \ ------------------------------\
2506 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
2507 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
2508 \ ------------------------------\
2509 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
2510 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
2511 \ ------------------------------\
2512     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
2513 \ ------------------------------\
2514 \ set TimerB to generate PWM for LCD_Vo
2515 \ ------------------------------\
2516     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
2517 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
2518     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
2519 \ ------------------------------\
2520     BIS.B #LCDVo,&LCDVo_DIR     \
2521     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
2522 \ ------------------------------\
2523     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
2524     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
2525 \ ------------------------------\
2526     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
2527     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
2528 \ ------------------------------\
2529 \ WDT interval init part        \
2530 \ ------------------------------\
2531     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
2532 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
2533 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
2534     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
2535 \ ------------------------------\
2536 \ init RC5_Int                  \
2537 \ ------------------------------\
2538     BIS.B #RC5,&IR_IE           \ enable RC5_Int
2539     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
2540 \ ------------------------------\
2541 \ init interrupt vectors
2542 \ ------------------------------\
2543     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
2544     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
2545 \ ------------------------------\
2546 \ define LPM mode for ACCEPT    \
2547 \ ------------------------------\
2548 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
2549 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
2550 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
2551
2552 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
2553
2554 \ ------------------------------\
2555 \ Init LCD 2x20                 \
2556 \ ------------------------------\
2557     $03E8 20_US                \ 1-  wait 20 ms
2558     $03 TOP_LCD                \ 2- send DB5=DB4=1
2559     $CD 20_US                  \ 3- wait 4,1 ms
2560     $03 TOP_LCD                \ 4- send again DB5=DB4=1
2561     $5 20_US                   \ 5- wait 0,1 ms
2562     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
2563     $2 20_US                   \    wait 40 us = LCD cycle
2564     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
2565     $2 20_US                   \    wait 40 us = LCD cycle
2566     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
2567     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
2568     LCD_Clear                   \ 10- "LCD_Clear"
2569     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
2570     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
2571     LCD_Clear                   \ 10- "LCD_Clear"
2572     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
2573     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
2574     CR ." I love you"   
2575     ['] (CR) IS CR              \ ' (CR) is CR
2576     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
2577     CR
2578     ."    RC5toLCD is running. Type STOP to quit"
2579 \    NOECHO                      \ uncomment to run this app without terminal connexion
2580     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
2581     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
2582 ;
2583     \
2584
2585 : STOP                  \ stops multitasking, must to be used before downloading app
2586     ['] (WARM) IS WARM  \ remove START app from FORTH init process
2587     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
2588 ;
2589     \
2590
2591
2592
2593 PWR_STATE
2594
2595
2596 CODE MAX    \    n1 n2 -- n3       signed maximum
2597             CMP     @PSP,TOS    \ n2-n1
2598             S<      ?GOTO FW1   \ n2<n1
2599 BW1         ADD     #2,PSP
2600             MOV     @IP+,PC
2601 ENDCODE
2602     \
2603
2604 CODE MIN    \    n1 n2 -- n3       signed minimum
2605             CMP     @PSP,TOS     \ n2-n1
2606             S<      ?GOTO BW1    \ n2<n1
2607 FW1         MOV     @PSP+,TOS
2608             MOV     @IP+,PC
2609 ENDCODE
2610     \
2611
2612 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
2613   >R  <# 0 # #S #>  
2614   R> OVER - 0 MAX SPACES TYPE
2615 ;
2616     \
2617
2618 CODE 20_US                      \ n --      n * 20 us
2619 BEGIN                           \ 3 cycles loop + 6~  
2620 \    MOV     #5,W                \ 3 MCLK = 1 MHz
2621 \    MOV     #23,W               \ 3 MCLK = 4 MHz
2622     MOV     #51,W               \ 3 MCLK = 8 MHz
2623 \    MOV     #104,W              \ 3 MCLK = 16 MHz
2624 \    MOV     #158,W              \ 3 MCLK = 24 MHz
2625     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
2626         SUB #1,W                \ 1
2627     0= UNTIL                    \ 2
2628     SUB     #1,TOS              \ 1
2629 0= UNTIL                        \ 2
2630     MOV     @PSP+,TOS           \ 2
2631     MOV     @IP+,PC             \ 4
2632 ENDCODE
2633     \
2634
2635 CODE TOP_LCD                    \ LCD Sample
2636 \                               \ if write : %xxxxWWWW --
2637 \                               \ if read  : -- %0000RRRR
2638     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
2639     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
2640 0= IF                           \ write LCD bits pattern
2641     AND.B #LCD_DB,TOS           \ 
2642     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
2643     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
2644     MOV @PSP+,TOS               \
2645     MOV @IP+,PC
2646 THEN                            \ read LCD bits pattern
2647     SUB #2,PSP
2648     MOV TOS,0(PSP)
2649     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
2650     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
2651     AND.B #LCD_DB,TOS           \
2652     MOV @IP+,PC
2653 ENDCODE
2654     \
2655
2656 CODE LCD_W                      \ byte --       write byte to LCD 
2657     SUB #2,PSP                  \
2658     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
2659     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
2660     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
2661     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
2662 COLON                           \ high level word starts here 
2663     TOP_LCD 2 20_US             \ write high nibble first
2664     TOP_LCD 2 20_US 
2665 ;
2666     \
2667
2668 CODE LCD_WrC                    \ char --         Write Char
2669     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
2670     JMP LCD_W 
2671 ENDCODE
2672     \
2673
2674 CODE LCD_WrF                    \ func --         Write Fonction
2675     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
2676     JMP LCD_W 
2677 ENDCODE
2678     \
2679
2680 : LCD_Clear 
2681     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
2682 ;
2683     \
2684
2685 : LCD_Home 
2686     $02 LCD_WrF 100 20_us 
2687 ;
2688     \
2689
2690 \ : LCD_Entry_set       $04 OR LCD_WrF ;
2691
2692 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
2693
2694 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
2695
2696 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
2697
2698 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
2699
2700 \ : LCD_Goto            $80 OR LCD_WrF ;
2701
2702 \ CODE LCD_R                      \ -- byte       read byte from LCD
2703 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
2704 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
2705 \ COLON                           \ starts a FORTH word
2706 \     TOP_LCD 2 20_us             \ -- %0000HHHH
2707 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
2708 \ HI2LO                           \ switch from FORTH to assembler
2709 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
2710 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
2711 \     MOV @RSP+,IP                \ restore IP saved by COLON
2712 \     MOV @IP+,PC                 \
2713 \ ENDCODE
2714 \     \
2715
2716 \ CODE LCD_RdS                    \ -- status       Read Status
2717 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
2718 \     JMP LCD_R
2719 \ ENDCODE
2720 \     \
2721
2722 \ CODE LCD_RdC                    \ -- char         Read Char
2723 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
2724 \     JMP LCD_R
2725 \ ENDCODE
2726 \     \
2727
2728 \ -------------+------+------+------+------++---+---+---+---+---------+
2729 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
2730 \ -------------+------+------+------+------++---+---+---+---+---------+
2731 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
2732 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
2733 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
2734 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
2735 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
2736 \ -------------+------+------+------+------++---+---+---+---+---------+
2737
2738
2739 \ ******************************\
2740 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
2741 \ ******************************\
2742 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
2743 \ ------------------------------\
2744 \ define LPM mode for ACCEPT    \
2745 \ ------------------------------\
2746 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
2747 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
2748 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
2749 BIT.B #SW2,&SW2_IN              \ test switch S2
2750 0= IF                           \ case of switch S2 pressed
2751     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
2752     U< IF
2753         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
2754     THEN
2755 ELSE
2756     BIT.B #SW1,&SW1_IN          \ test switch S1 input
2757     0= IF                       \ case of Switch S1 pressed
2758         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
2759         U>= IF                  \
2760             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
2761         THEN                    \
2762     THEN                        \
2763 THEN                            \
2764 RETI                            \ CPU is ON, GIE is OFF
2765 ENDASM                          \
2766     \
2767
2768
2769 \ ------------------------------\
2770 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
2771 \ ******************************\
2772 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
2773 \ ******************************\
2774 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
2775 \                               \       SMclock = 8|16|24 MHz
2776 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
2777 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
2778 \                               \       SR(9)=new Toggle bit memory (ADD on)
2779 \ ------------------------------\
2780 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
2781 \ ------------------------------\
2782 \ define LPM mode for ACCEPT    \
2783 \ ------------------------------\
2784 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
2785 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
2786 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
2787 \ ------------------------------\
2788 \ RC5_FirstStartBitHalfCycle:   \
2789 \ ------------------------------\
2790 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
2791 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
2792 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
2793 MOV     #1778,X                 \ RC5_Period in us
2794 MOV     #14,W                   \ count of loop
2795 BEGIN                           \
2796 \ ------------------------------\
2797 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
2798 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
2799     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
2800 \ RC5_Compute_3/4_Period:       \                   |
2801     RRUM    #1,X                \ X=1/2 cycle       |
2802     MOV     X,Y                 \ Y=1/2             ^
2803     RRUM    #1,Y                \ Y=1/4
2804     ADD     X,Y                 \ Y=3/4
2805 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
2806     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
2807     0= UNTIL                    \
2808 \ ------------------------------\
2809 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
2810 \ ------------------------------\
2811     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
2812     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
2813     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
2814     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
2815     SUB     #1,W                \ decrement count loop
2816 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
2817 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
2818 0<> WHILE                       \ ----> out of loop ----+
2819 \ RC5_compute_7/4_Time_out:     \                       |
2820     ADD     X,Y                 \                       |   out of bound = 7/4 period 
2821 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
2822     BEGIN                       \                       |
2823         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
2824         0>= IF                  \                       |   if cycle time out of bound
2825             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
2826             RETI                \                       |   then quit to do nothing
2827         THEN                    \                       |
2828 \ ------------------------------\                       |
2829         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
2830     0<> UNTIL                   \                   |   |
2831     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
2832 REPEAT                          \ ----> loop back --+   |
2833 \ ------------------------------\                       |
2834 \ RC5_SampleEndOf:              \ <---------------------+
2835 \ ------------------------------\
2836 BIC     #$30,&TA0CTL           \ stop timer_A0
2837 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
2838 \ ******************************\
2839 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
2840 \ ******************************\
2841 MOV     @RSP,X                  \ retiSR(9)  = old UF9 = old RC5 toggle bit
2842 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
2843 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
2844 BIT     #BIT13,X                \ X(13) = New_RC5_command
2845 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
2846 THEN                            \
2847 XOR     #UF9,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
2848 \ ******************************\
2849 \ RC5_ComputeNewRC5word         \
2850 \ ******************************\
2851 SUB     #4,PSP                  \
2852 MOV     &BASE,2(PSP)            \ save variable BASE before use
2853 MOV     TOS,0(PSP)              \ save TOS before use
2854 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
2855 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
2856 \ ******************************\
2857 \ RC5_ComputeC6bit              \
2858 \ ******************************\
2859 BIT     #$4000,IP              \ test /C6 bit in IP
2860 0= IF   BIS #$40,TOS           \ set C6 bit in S
2861 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
2862 \ ******************************\
2863 \ RC5_CommandByteIsDone         \ RC5_code --
2864 \ ******************************\
2865
2866 \ ------------------------------\
2867 \ Display IR_RC5 code           \
2868 \ ------------------------------\
2869 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
2870 \ ------------------------------\
2871 LO2HI                           \ switch from assembler to FORTH
2872     ['] LCD_CLEAR IS CR         \ redirects CR
2873     ['] LCD_WrC  IS EMIT        \ redirects EMIT
2874     $10 BASE !                 \ change BASE to hexadecimal
2875     CR ." $" 2 U.R             \ print IR_RC5 code
2876     ['] (CR) IS CR              \ restore CR
2877     ['] (EMIT) IS EMIT          \ restore EMIT
2878 HI2LO                           \ switch from FORTH to assembler
2879 \ ------------------------------\
2880 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
2881 \ ------------------------------\
2882 MOV @PSP+,&BASE                 \ restore variable BASE
2883 RETI                            \ CPU is ON, GIE is OFF
2884 ENDASM                          \
2885     \ 
2886
2887 CODE START                      \
2888 \ ------------------------------\
2889 \ TB0CTL = %0000 0010 1001 0100\$3C0
2890 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
2891 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
2892 \                      --       \ID input divider \ 10 = /4
2893 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
2894 \                            -  \TBCLR TimerB Clear
2895 \                             - \TBIE
2896 \                              -\TBIFG
2897 \ --------------------------------\\
2898 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
2899 \              --                 \CM Capture Mode
2900 \                --               \CCIS
2901 \                   -             \SCS
2902 \                    --           \CLLD
2903 \                      -          \CAP
2904 \                        ---      \OUTMOD \ 011 = set/reset
2905 \                           -     \CCIE
2906 \                             -   \CCI
2907 \                              -  \OUT
2908 \                               - \COV
2909 \                                -\CCIFG
2910 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
2911 \ TB0EX0                          \$3E0 
2912 \ ------------------------------\
2913 \ set TimerB to make 50kHz PWM  \
2914 \ ------------------------------\
2915 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
2916 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
2917 \ ------------------------------\
2918 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
2919 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
2920 \ ------------------------------\
2921     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
2922     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
2923 \ ------------------------------\
2924 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
2925 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
2926 \ ------------------------------\
2927 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
2928 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
2929 \ ------------------------------\
2930     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
2931 \ ------------------------------\
2932 \ set TimerB to generate PWM for LCD_Vo
2933 \ ------------------------------\
2934     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
2935 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
2936     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
2937 \ ------------------------------\
2938     BIS.B #LCDVo,&LCDVo_DIR     \
2939     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
2940 \ ------------------------------\
2941     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
2942     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
2943 \ ------------------------------\
2944     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
2945     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
2946 \ ------------------------------\
2947 \ WDT interval init part        \
2948 \ ------------------------------\
2949     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
2950 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
2951 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
2952     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
2953 \ ------------------------------\
2954 \ init RC5_Int                  \
2955 \ ------------------------------\
2956     BIS.B #RC5,&IR_IE           \ enable RC5_Int
2957     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
2958 \ ------------------------------\
2959 \ init interrupt vectors
2960 \ ------------------------------\
2961     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
2962     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
2963 \ ------------------------------\
2964 \ define LPM mode for ACCEPT    \
2965 \ ------------------------------\
2966 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
2967 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
2968 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
2969
2970 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
2971
2972 \ ------------------------------\
2973 \ Init LCD 2x20                 \
2974 \ ------------------------------\
2975     $03E8 20_US                \ 1-  wait 20 ms
2976     $03 TOP_LCD                \ 2- send DB5=DB4=1
2977     $CD 20_US                  \ 3- wait 4,1 ms
2978     $03 TOP_LCD                \ 4- send again DB5=DB4=1
2979     $5 20_US                   \ 5- wait 0,1 ms
2980     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
2981     $2 20_US                   \    wait 40 us = LCD cycle
2982     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
2983     $2 20_US                   \    wait 40 us = LCD cycle
2984     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
2985     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
2986     LCD_Clear                   \ 10- "LCD_Clear"
2987     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
2988     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
2989     LCD_Clear                   \ 10- "LCD_Clear"
2990     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
2991     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
2992     CR ." I love you"   
2993     ['] (CR) IS CR              \ ' (CR) is CR
2994     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
2995     CR
2996     ."    RC5toLCD is running. Type STOP to quit"
2997 \    NOECHO                      \ uncomment to run this app without terminal connexion
2998     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
2999     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
3000 ;
3001     \
3002
3003 : STOP                  \ stops multitasking, must to be used before downloading app
3004     ['] (WARM) IS WARM  \ remove START app from FORTH init process
3005     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
3006 ;
3007     \
3008
3009
3010
3011 PWR_STATE
3012
3013
3014 CODE MAX    \    n1 n2 -- n3       signed maximum
3015             CMP     @PSP,TOS    \ n2-n1
3016             S<      ?GOTO FW1   \ n2<n1
3017 BW1         ADD     #2,PSP
3018             MOV     @IP+,PC
3019 ENDCODE
3020     \
3021
3022 CODE MIN    \    n1 n2 -- n3       signed minimum
3023             CMP     @PSP,TOS     \ n2-n1
3024             S<      ?GOTO BW1    \ n2<n1
3025 FW1         MOV     @PSP+,TOS
3026             MOV     @IP+,PC
3027 ENDCODE
3028     \
3029
3030 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
3031   >R  <# 0 # #S #>  
3032   R> OVER - 0 MAX SPACES TYPE
3033 ;
3034     \
3035
3036 CODE 20_US                      \ n --      n * 20 us
3037 BEGIN                           \ 3 cycles loop + 6~  
3038 \    MOV     #5,W                \ 3 MCLK = 1 MHz
3039 \    MOV     #23,W               \ 3 MCLK = 4 MHz
3040     MOV     #51,W               \ 3 MCLK = 8 MHz
3041 \    MOV     #104,W              \ 3 MCLK = 16 MHz
3042 \    MOV     #158,W              \ 3 MCLK = 24 MHz
3043     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
3044         SUB #1,W                \ 1
3045     0= UNTIL                    \ 2
3046     SUB     #1,TOS              \ 1
3047 0= UNTIL                        \ 2
3048     MOV     @PSP+,TOS           \ 2
3049     MOV     @IP+,PC             \ 4
3050 ENDCODE
3051     \
3052
3053 CODE TOP_LCD                    \ LCD Sample
3054 \                               \ if write : %xxxxWWWW --
3055 \                               \ if read  : -- %0000RRRR
3056     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
3057     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
3058 0= IF                           \ write LCD bits pattern
3059     AND.B #LCD_DB,TOS           \ 
3060     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
3061     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
3062     MOV @PSP+,TOS               \
3063     MOV @IP+,PC
3064 THEN                            \ read LCD bits pattern
3065     SUB #2,PSP
3066     MOV TOS,0(PSP)
3067     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
3068     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
3069     AND.B #LCD_DB,TOS           \
3070     MOV @IP+,PC
3071 ENDCODE
3072     \
3073
3074 CODE LCD_W                      \ byte --       write byte to LCD 
3075     SUB #2,PSP                  \
3076     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
3077     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
3078     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
3079     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
3080 COLON                           \ high level word starts here 
3081     TOP_LCD 2 20_US             \ write high nibble first
3082     TOP_LCD 2 20_US 
3083 ;
3084     \
3085
3086 CODE LCD_WrC                    \ char --         Write Char
3087     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
3088     JMP LCD_W 
3089 ENDCODE
3090     \
3091
3092 CODE LCD_WrF                    \ func --         Write Fonction
3093     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
3094     JMP LCD_W 
3095 ENDCODE
3096     \
3097
3098 : LCD_Clear 
3099     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
3100 ;
3101     \
3102
3103 : LCD_Home 
3104     $02 LCD_WrF 100 20_us 
3105 ;
3106     \
3107
3108 \ : LCD_Entry_set       $04 OR LCD_WrF ;
3109
3110 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
3111
3112 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
3113
3114 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
3115
3116 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
3117
3118 \ : LCD_Goto            $80 OR LCD_WrF ;
3119
3120 \ CODE LCD_R                      \ -- byte       read byte from LCD
3121 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
3122 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
3123 \ COLON                           \ starts a FORTH word
3124 \     TOP_LCD 2 20_us             \ -- %0000HHHH
3125 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
3126 \ HI2LO                           \ switch from FORTH to assembler
3127 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
3128 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
3129 \     MOV @RSP+,IP                \ restore IP saved by COLON
3130 \     MOV @IP+,PC                 \
3131 \ ENDCODE
3132 \     \
3133
3134 \ CODE LCD_RdS                    \ -- status       Read Status
3135 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
3136 \     JMP LCD_R
3137 \ ENDCODE
3138 \     \
3139
3140 \ CODE LCD_RdC                    \ -- char         Read Char
3141 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
3142 \     JMP LCD_R
3143 \ ENDCODE
3144 \     \
3145
3146 \ -------------+------+------+------+------++---+---+---+---+---------+
3147 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
3148 \ -------------+------+------+------+------++---+---+---+---+---------+
3149 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
3150 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
3151 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
3152 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
3153 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
3154 \ -------------+------+------+------+------++---+---+---+---+---------+
3155
3156
3157 \ ******************************\
3158 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
3159 \ ******************************\
3160 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
3161 \ ------------------------------\
3162 \ define LPM mode for ACCEPT    \
3163 \ ------------------------------\
3164 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
3165 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
3166 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
3167 BIT.B #SW2,&SW2_IN              \ test switch S2
3168 0= IF                           \ case of switch S2 pressed
3169     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
3170     U< IF
3171         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
3172     THEN
3173 ELSE
3174     BIT.B #SW1,&SW1_IN          \ test switch S1 input
3175     0= IF                       \ case of Switch S1 pressed
3176         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
3177         U>= IF                  \
3178             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
3179         THEN                    \
3180     THEN                        \
3181 THEN                            \
3182 RETI                            \ CPU is ON, GIE is OFF
3183 ENDASM                          \
3184     \
3185
3186
3187 \ ------------------------------\
3188 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
3189 \ ******************************\
3190 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
3191 \ ******************************\
3192 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
3193 \                               \       SMclock = 8|16|24 MHz
3194 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
3195 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
3196 \                               \       SR(9)=new Toggle bit memory (ADD on)
3197 \ ------------------------------\
3198 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
3199 \ ------------------------------\
3200 \ define LPM mode for ACCEPT    \
3201 \ ------------------------------\
3202 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
3203 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
3204 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
3205 \ ------------------------------\
3206 \ RC5_FirstStartBitHalfCycle:   \
3207 \ ------------------------------\
3208 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
3209 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
3210 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
3211 MOV     #1778,X                 \ RC5_Period in us
3212 MOV     #14,W                   \ count of loop
3213 BEGIN                           \
3214 \ ------------------------------\
3215 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
3216 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
3217     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
3218 \ RC5_Compute_3/4_Period:       \                   |
3219     RRUM    #1,X                \ X=1/2 cycle       |
3220     MOV     X,Y                 \ Y=1/2             ^
3221     RRUM    #1,Y                \ Y=1/4
3222     ADD     X,Y                 \ Y=3/4
3223 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
3224     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
3225     0= UNTIL                    \
3226 \ ------------------------------\
3227 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
3228 \ ------------------------------\
3229     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
3230     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
3231     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
3232     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
3233     SUB     #1,W                \ decrement count loop
3234 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
3235 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
3236 0<> WHILE                       \ ----> out of loop ----+
3237 \ RC5_compute_7/4_Time_out:     \                       |
3238     ADD     X,Y                 \                       |   out of bound = 7/4 period 
3239 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
3240     BEGIN                       \                       |
3241         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
3242         0>= IF                  \                       |   if cycle time out of bound
3243             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
3244             RETI                \                       |   then quit to do nothing
3245         THEN                    \                       |
3246 \ ------------------------------\                       |
3247         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
3248     0<> UNTIL                   \                   |   |
3249     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
3250 REPEAT                          \ ----> loop back --+   |
3251 \ ------------------------------\                       |
3252 \ RC5_SampleEndOf:              \ <---------------------+
3253 \ ------------------------------\
3254 BIC     #$30,&TA0CTL           \ stop timer_A0
3255 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
3256 \ ******************************\
3257 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
3258 \ ******************************\
3259 MOV     @RSP,X                  \ retiSR(9)  = old UF9 = old RC5 toggle bit
3260 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
3261 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
3262 BIT     #BIT13,X                \ X(13) = New_RC5_command
3263 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
3264 THEN                            \
3265 XOR     #UF9,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
3266 \ ******************************\
3267 \ RC5_ComputeNewRC5word         \
3268 \ ******************************\
3269 SUB     #4,PSP                  \
3270 MOV     &BASE,2(PSP)            \ save variable BASE before use
3271 MOV     TOS,0(PSP)              \ save TOS before use
3272 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
3273 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
3274 \ ******************************\
3275 \ RC5_ComputeC6bit              \
3276 \ ******************************\
3277 BIT     #$4000,IP              \ test /C6 bit in IP
3278 0= IF   BIS #$40,TOS           \ set C6 bit in S
3279 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
3280 \ ******************************\
3281 \ RC5_CommandByteIsDone         \ RC5_code --
3282 \ ******************************\
3283
3284 \ ------------------------------\
3285 \ Display IR_RC5 code           \
3286 \ ------------------------------\
3287 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
3288 \ ------------------------------\
3289 LO2HI                           \ switch from assembler to FORTH
3290     ['] LCD_CLEAR IS CR         \ redirects CR
3291     ['] LCD_WrC  IS EMIT        \ redirects EMIT
3292     $10 BASE !                 \ change BASE to hexadecimal
3293     CR ." $" 2 U.R             \ print IR_RC5 code
3294     ['] (CR) IS CR              \ restore CR
3295     ['] (EMIT) IS EMIT          \ restore EMIT
3296 HI2LO                           \ switch from FORTH to assembler
3297 \ ------------------------------\
3298 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
3299 \ ------------------------------\
3300 MOV @PSP+,&BASE                 \ restore variable BASE
3301 RETI                            \ CPU is ON, GIE is OFF
3302 ENDASM                          \
3303     \ 
3304
3305 CODE START                      \
3306 \ ------------------------------\
3307 \ TB0CTL = %0000 0010 1001 0100\$3C0
3308 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
3309 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
3310 \                      --       \ID input divider \ 10 = /4
3311 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
3312 \                            -  \TBCLR TimerB Clear
3313 \                             - \TBIE
3314 \                              -\TBIFG
3315 \ --------------------------------\\
3316 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
3317 \              --                 \CM Capture Mode
3318 \                --               \CCIS
3319 \                   -             \SCS
3320 \                    --           \CLLD
3321 \                      -          \CAP
3322 \                        ---      \OUTMOD \ 011 = set/reset
3323 \                           -     \CCIE
3324 \                             -   \CCI
3325 \                              -  \OUT
3326 \                               - \COV
3327 \                                -\CCIFG
3328 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
3329 \ TB0EX0                          \$3E0 
3330 \ ------------------------------\
3331 \ set TimerB to make 50kHz PWM  \
3332 \ ------------------------------\
3333 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
3334 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
3335 \ ------------------------------\
3336 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
3337 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
3338 \ ------------------------------\
3339     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
3340     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
3341 \ ------------------------------\
3342 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
3343 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
3344 \ ------------------------------\
3345 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
3346 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
3347 \ ------------------------------\
3348     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
3349 \ ------------------------------\
3350 \ set TimerB to generate PWM for LCD_Vo
3351 \ ------------------------------\
3352     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
3353 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
3354     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
3355 \ ------------------------------\
3356     BIS.B #LCDVo,&LCDVo_DIR     \
3357     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
3358 \ ------------------------------\
3359     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
3360     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
3361 \ ------------------------------\
3362     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
3363     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
3364 \ ------------------------------\
3365 \ WDT interval init part        \
3366 \ ------------------------------\
3367     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
3368 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
3369 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
3370     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
3371 \ ------------------------------\
3372 \ init RC5_Int                  \
3373 \ ------------------------------\
3374     BIS.B #RC5,&IR_IE           \ enable RC5_Int
3375     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
3376 \ ------------------------------\
3377 \ init interrupt vectors
3378 \ ------------------------------\
3379     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
3380     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
3381 \ ------------------------------\
3382 \ define LPM mode for ACCEPT    \
3383 \ ------------------------------\
3384 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
3385 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
3386 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
3387
3388 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
3389
3390 \ ------------------------------\
3391 \ Init LCD 2x20                 \
3392 \ ------------------------------\
3393     $03E8 20_US                \ 1-  wait 20 ms
3394     $03 TOP_LCD                \ 2- send DB5=DB4=1
3395     $CD 20_US                  \ 3- wait 4,1 ms
3396     $03 TOP_LCD                \ 4- send again DB5=DB4=1
3397     $5 20_US                   \ 5- wait 0,1 ms
3398     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
3399     $2 20_US                   \    wait 40 us = LCD cycle
3400     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
3401     $2 20_US                   \    wait 40 us = LCD cycle
3402     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
3403     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
3404     LCD_Clear                   \ 10- "LCD_Clear"
3405     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
3406     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
3407     LCD_Clear                   \ 10- "LCD_Clear"
3408     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
3409     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
3410     CR ." I love you"   
3411     ['] (CR) IS CR              \ ' (CR) is CR
3412     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
3413     CR
3414     ."    RC5toLCD is running. Type STOP to quit"
3415 \    NOECHO                      \ uncomment to run this app without terminal connexion
3416     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
3417     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
3418 ;
3419     \
3420
3421 : STOP                  \ stops multitasking, must to be used before downloading app
3422     ['] (WARM) IS WARM  \ remove START app from FORTH init process
3423     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
3424 ;
3425     \
3426
3427
3428
3429 PWR_STATE
3430
3431
3432 CODE MAX    \    n1 n2 -- n3       signed maximum
3433             CMP     @PSP,TOS    \ n2-n1
3434             S<      ?GOTO FW1   \ n2<n1
3435 BW1         ADD     #2,PSP
3436             MOV     @IP+,PC
3437 ENDCODE
3438     \
3439
3440 CODE MIN    \    n1 n2 -- n3       signed minimum
3441             CMP     @PSP,TOS     \ n2-n1
3442             S<      ?GOTO BW1    \ n2<n1
3443 FW1         MOV     @PSP+,TOS
3444             MOV     @IP+,PC
3445 ENDCODE
3446     \
3447
3448 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
3449   >R  <# 0 # #S #>  
3450   R> OVER - 0 MAX SPACES TYPE
3451 ;
3452     \
3453
3454 CODE 20_US                      \ n --      n * 20 us
3455 BEGIN                           \ 3 cycles loop + 6~  
3456 \    MOV     #5,W                \ 3 MCLK = 1 MHz
3457 \    MOV     #23,W               \ 3 MCLK = 4 MHz
3458     MOV     #51,W               \ 3 MCLK = 8 MHz
3459 \    MOV     #104,W              \ 3 MCLK = 16 MHz
3460 \    MOV     #158,W              \ 3 MCLK = 24 MHz
3461     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
3462         SUB #1,W                \ 1
3463     0= UNTIL                    \ 2
3464     SUB     #1,TOS              \ 1
3465 0= UNTIL                        \ 2
3466     MOV     @PSP+,TOS           \ 2
3467     MOV     @IP+,PC             \ 4
3468 ENDCODE
3469     \
3470
3471 CODE TOP_LCD                    \ LCD Sample
3472 \                               \ if write : %xxxxWWWW --
3473 \                               \ if read  : -- %0000RRRR
3474     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
3475     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
3476 0= IF                           \ write LCD bits pattern
3477     AND.B #LCD_DB,TOS           \ 
3478     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
3479     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
3480     MOV @PSP+,TOS               \
3481     MOV @IP+,PC
3482 THEN                            \ read LCD bits pattern
3483     SUB #2,PSP
3484     MOV TOS,0(PSP)
3485     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
3486     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
3487     AND.B #LCD_DB,TOS           \
3488     MOV @IP+,PC
3489 ENDCODE
3490     \
3491
3492 CODE LCD_W                      \ byte --       write byte to LCD 
3493     SUB #2,PSP                  \
3494     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
3495     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
3496     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
3497     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
3498 COLON                           \ high level word starts here 
3499     TOP_LCD 2 20_US             \ write high nibble first
3500     TOP_LCD 2 20_US 
3501 ;
3502     \
3503
3504 CODE LCD_WrC                    \ char --         Write Char
3505     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
3506     JMP LCD_W 
3507 ENDCODE
3508     \
3509
3510 CODE LCD_WrF                    \ func --         Write Fonction
3511     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
3512     JMP LCD_W 
3513 ENDCODE
3514     \
3515
3516 : LCD_Clear 
3517     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
3518 ;
3519     \
3520
3521 : LCD_Home 
3522     $02 LCD_WrF 100 20_us 
3523 ;
3524     \
3525
3526 \ : LCD_Entry_set       $04 OR LCD_WrF ;
3527
3528 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
3529
3530 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
3531
3532 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
3533
3534 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
3535
3536 \ : LCD_Goto            $80 OR LCD_WrF ;
3537
3538 \ CODE LCD_R                      \ -- byte       read byte from LCD
3539 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
3540 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
3541 \ COLON                           \ starts a FORTH word
3542 \     TOP_LCD 2 20_us             \ -- %0000HHHH
3543 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
3544 \ HI2LO                           \ switch from FORTH to assembler
3545 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
3546 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
3547 \     MOV @RSP+,IP                \ restore IP saved by COLON
3548 \     MOV @IP+,PC                 \
3549 \ ENDCODE
3550 \     \
3551
3552 \ CODE LCD_RdS                    \ -- status       Read Status
3553 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
3554 \     JMP LCD_R
3555 \ ENDCODE
3556 \     \
3557
3558 \ CODE LCD_RdC                    \ -- char         Read Char
3559 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
3560 \     JMP LCD_R
3561 \ ENDCODE
3562 \     \
3563
3564 \ -------------+------+------+------+------++---+---+---+---+---------+
3565 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
3566 \ -------------+------+------+------+------++---+---+---+---+---------+
3567 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
3568 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
3569 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
3570 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
3571 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
3572 \ -------------+------+------+------+------++---+---+---+---+---------+
3573
3574
3575 \ ******************************\
3576 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
3577 \ ******************************\
3578 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
3579 \ ------------------------------\
3580 \ define LPM mode for ACCEPT    \
3581 \ ------------------------------\
3582 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
3583 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
3584 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
3585 BIT.B #SW2,&SW2_IN              \ test switch S2
3586 0= IF                           \ case of switch S2 pressed
3587     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
3588     U< IF
3589         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
3590     THEN
3591 ELSE
3592     BIT.B #SW1,&SW1_IN          \ test switch S1 input
3593     0= IF                       \ case of Switch S1 pressed
3594         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
3595         U>= IF                  \
3596             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
3597         THEN                    \
3598     THEN                        \
3599 THEN                            \
3600 RETI                            \ CPU is ON, GIE is OFF
3601 ENDASM                          \
3602     \
3603
3604
3605 \ ------------------------------\
3606 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
3607 \ ******************************\
3608 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
3609 \ ******************************\
3610 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
3611 \                               \       SMclock = 8|16|24 MHz
3612 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
3613 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
3614 \                               \       SR(9)=new Toggle bit memory (ADD on)
3615 \ ------------------------------\
3616 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
3617 \ ------------------------------\
3618 \ define LPM mode for ACCEPT    \
3619 \ ------------------------------\
3620 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
3621 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
3622 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
3623 \ ------------------------------\
3624 \ RC5_FirstStartBitHalfCycle:   \
3625 \ ------------------------------\
3626 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
3627 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
3628 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
3629 MOV     #1778,X                 \ RC5_Period in us
3630 MOV     #14,W                   \ count of loop
3631 BEGIN                           \
3632 \ ------------------------------\
3633 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
3634 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
3635     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
3636 \ RC5_Compute_3/4_Period:       \                   |
3637     RRUM    #1,X                \ X=1/2 cycle       |
3638     MOV     X,Y                 \ Y=1/2             ^
3639     RRUM    #1,Y                \ Y=1/4
3640     ADD     X,Y                 \ Y=3/4
3641 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
3642     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
3643     0= UNTIL                    \
3644 \ ------------------------------\
3645 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
3646 \ ------------------------------\
3647     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
3648     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
3649     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
3650     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
3651     SUB     #1,W                \ decrement count loop
3652 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
3653 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
3654 0<> WHILE                       \ ----> out of loop ----+
3655 \ RC5_compute_7/4_Time_out:     \                       |
3656     ADD     X,Y                 \                       |   out of bound = 7/4 period 
3657 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
3658     BEGIN                       \                       |
3659         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
3660         0>= IF                  \                       |   if cycle time out of bound
3661             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
3662             RETI                \                       |   then quit to do nothing
3663         THEN                    \                       |
3664 \ ------------------------------\                       |
3665         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
3666     0<> UNTIL                   \                   |   |
3667     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
3668 REPEAT                          \ ----> loop back --+   |
3669 \ ------------------------------\                       |
3670 \ RC5_SampleEndOf:              \ <---------------------+
3671 \ ------------------------------\
3672 BIC     #$30,&TA0CTL           \ stop timer_A0
3673 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
3674 \ ******************************\
3675 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
3676 \ ******************************\
3677 MOV     @RSP,X                  \ retiSR(9)  = old UF9 = old RC5 toggle bit
3678 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
3679 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
3680 BIT     #BIT13,X                \ X(13) = New_RC5_command
3681 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
3682 THEN                            \
3683 XOR     #UF9,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
3684 \ ******************************\
3685 \ RC5_ComputeNewRC5word         \
3686 \ ******************************\
3687 SUB     #4,PSP                  \
3688 MOV     &BASE,2(PSP)            \ save variable BASE before use
3689 MOV     TOS,0(PSP)              \ save TOS before use
3690 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
3691 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
3692 \ ******************************\
3693 \ RC5_ComputeC6bit              \
3694 \ ******************************\
3695 BIT     #$4000,IP              \ test /C6 bit in IP
3696 0= IF   BIS #$40,TOS           \ set C6 bit in S
3697 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
3698 \ ******************************\
3699 \ RC5_CommandByteIsDone         \ RC5_code --
3700 \ ******************************\
3701
3702 \ ------------------------------\
3703 \ Display IR_RC5 code           \
3704 \ ------------------------------\
3705 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
3706 \ ------------------------------\
3707 LO2HI                           \ switch from assembler to FORTH
3708     ['] LCD_CLEAR IS CR         \ redirects CR
3709     ['] LCD_WrC  IS EMIT        \ redirects EMIT
3710     $10 BASE !                 \ change BASE to hexadecimal
3711     CR ." $" 2 U.R             \ print IR_RC5 code
3712     ['] (CR) IS CR              \ restore CR
3713     ['] (EMIT) IS EMIT          \ restore EMIT
3714 HI2LO                           \ switch from FORTH to assembler
3715 \ ------------------------------\
3716 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
3717 \ ------------------------------\
3718 MOV @PSP+,&BASE                 \ restore variable BASE
3719 RETI                            \ CPU is ON, GIE is OFF
3720 ENDASM                          \
3721     \ 
3722
3723 CODE START                      \
3724 \ ------------------------------\
3725 \ TB0CTL = %0000 0010 1001 0100\$3C0
3726 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
3727 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
3728 \                      --       \ID input divider \ 10 = /4
3729 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
3730 \                            -  \TBCLR TimerB Clear
3731 \                             - \TBIE
3732 \                              -\TBIFG
3733 \ --------------------------------\\
3734 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
3735 \              --                 \CM Capture Mode
3736 \                --               \CCIS
3737 \                   -             \SCS
3738 \                    --           \CLLD
3739 \                      -          \CAP
3740 \                        ---      \OUTMOD \ 011 = set/reset
3741 \                           -     \CCIE
3742 \                             -   \CCI
3743 \                              -  \OUT
3744 \                               - \COV
3745 \                                -\CCIFG
3746 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
3747 \ TB0EX0                          \$3E0 
3748 \ ------------------------------\
3749 \ set TimerB to make 50kHz PWM  \
3750 \ ------------------------------\
3751 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
3752 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
3753 \ ------------------------------\
3754 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
3755 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
3756 \ ------------------------------\
3757     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
3758     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
3759 \ ------------------------------\
3760 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
3761 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
3762 \ ------------------------------\
3763 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
3764 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
3765 \ ------------------------------\
3766     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
3767 \ ------------------------------\
3768 \ set TimerB to generate PWM for LCD_Vo
3769 \ ------------------------------\
3770     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
3771 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
3772     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
3773 \ ------------------------------\
3774     BIS.B #LCDVo,&LCDVo_DIR     \
3775     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
3776 \ ------------------------------\
3777     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
3778     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
3779 \ ------------------------------\
3780     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
3781     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
3782 \ ------------------------------\
3783 \ WDT interval init part        \
3784 \ ------------------------------\
3785     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
3786 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
3787 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
3788     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
3789 \ ------------------------------\
3790 \ init RC5_Int                  \
3791 \ ------------------------------\
3792     BIS.B #RC5,&IR_IE           \ enable RC5_Int
3793     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
3794 \ ------------------------------\
3795 \ init interrupt vectors
3796 \ ------------------------------\
3797     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
3798     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
3799 \ ------------------------------\
3800 \ define LPM mode for ACCEPT    \
3801 \ ------------------------------\
3802 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
3803 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
3804 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
3805
3806 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
3807
3808 \ ------------------------------\
3809 \ Init LCD 2x20                 \
3810 \ ------------------------------\
3811     $03E8 20_US                \ 1-  wait 20 ms
3812     $03 TOP_LCD                \ 2- send DB5=DB4=1
3813     $CD 20_US                  \ 3- wait 4,1 ms
3814     $03 TOP_LCD                \ 4- send again DB5=DB4=1
3815     $5 20_US                   \ 5- wait 0,1 ms
3816     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
3817     $2 20_US                   \    wait 40 us = LCD cycle
3818     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
3819     $2 20_US                   \    wait 40 us = LCD cycle
3820     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
3821     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
3822     LCD_Clear                   \ 10- "LCD_Clear"
3823     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
3824     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
3825     LCD_Clear                   \ 10- "LCD_Clear"
3826     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
3827     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
3828     CR ." I love you"   
3829     ['] (CR) IS CR              \ ' (CR) is CR
3830     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
3831     CR
3832     ."    RC5toLCD is running. Type STOP to quit"
3833 \    NOECHO                      \ uncomment to run this app without terminal connexion
3834     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
3835     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
3836 ;
3837     \
3838
3839 : STOP                  \ stops multitasking, must to be used before downloading app
3840     ['] (WARM) IS WARM  \ remove START app from FORTH init process
3841     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
3842 ;
3843     \
3844
3845
3846
3847 PWR_STATE
3848
3849
3850 CODE MAX    \    n1 n2 -- n3       signed maximum
3851             CMP     @PSP,TOS    \ n2-n1
3852             S<      ?GOTO FW1   \ n2<n1
3853 BW1         ADD     #2,PSP
3854             MOV     @IP+,PC
3855 ENDCODE
3856     \
3857
3858 CODE MIN    \    n1 n2 -- n3       signed minimum
3859             CMP     @PSP,TOS     \ n2-n1
3860             S<      ?GOTO BW1    \ n2<n1
3861 FW1         MOV     @PSP+,TOS
3862             MOV     @IP+,PC
3863 ENDCODE
3864     \
3865
3866 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
3867   >R  <# 0 # #S #>  
3868   R> OVER - 0 MAX SPACES TYPE
3869 ;
3870     \
3871
3872 CODE 20_US                      \ n --      n * 20 us
3873 BEGIN                           \ 3 cycles loop + 6~  
3874 \    MOV     #5,W                \ 3 MCLK = 1 MHz
3875 \    MOV     #23,W               \ 3 MCLK = 4 MHz
3876     MOV     #51,W               \ 3 MCLK = 8 MHz
3877 \    MOV     #104,W              \ 3 MCLK = 16 MHz
3878 \    MOV     #158,W              \ 3 MCLK = 24 MHz
3879     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
3880         SUB #1,W                \ 1
3881     0= UNTIL                    \ 2
3882     SUB     #1,TOS              \ 1
3883 0= UNTIL                        \ 2
3884     MOV     @PSP+,TOS           \ 2
3885     MOV     @IP+,PC             \ 4
3886 ENDCODE
3887     \
3888
3889 CODE TOP_LCD                    \ LCD Sample
3890 \                               \ if write : %xxxxWWWW --
3891 \                               \ if read  : -- %0000RRRR
3892     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
3893     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
3894 0= IF                           \ write LCD bits pattern
3895     AND.B #LCD_DB,TOS           \ 
3896     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
3897     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
3898     MOV @PSP+,TOS               \
3899     MOV @IP+,PC
3900 THEN                            \ read LCD bits pattern
3901     SUB #2,PSP
3902     MOV TOS,0(PSP)
3903     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
3904     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
3905     AND.B #LCD_DB,TOS           \
3906     MOV @IP+,PC
3907 ENDCODE
3908     \
3909
3910 CODE LCD_W                      \ byte --       write byte to LCD 
3911     SUB #2,PSP                  \
3912     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
3913     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
3914     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
3915     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
3916 COLON                           \ high level word starts here 
3917     TOP_LCD 2 20_US             \ write high nibble first
3918     TOP_LCD 2 20_US 
3919 ;
3920     \
3921
3922 CODE LCD_WrC                    \ char --         Write Char
3923     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
3924     JMP LCD_W 
3925 ENDCODE
3926     \
3927
3928 CODE LCD_WrF                    \ func --         Write Fonction
3929     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
3930     JMP LCD_W 
3931 ENDCODE
3932     \
3933
3934 : LCD_Clear 
3935     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
3936 ;
3937     \
3938
3939 : LCD_Home 
3940     $02 LCD_WrF 100 20_us 
3941 ;
3942     \
3943
3944 \ : LCD_Entry_set       $04 OR LCD_WrF ;
3945
3946 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
3947
3948 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
3949
3950 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
3951
3952 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
3953
3954 \ : LCD_Goto            $80 OR LCD_WrF ;
3955
3956 \ CODE LCD_R                      \ -- byte       read byte from LCD
3957 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
3958 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
3959 \ COLON                           \ starts a FORTH word
3960 \     TOP_LCD 2 20_us             \ -- %0000HHHH
3961 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
3962 \ HI2LO                           \ switch from FORTH to assembler
3963 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
3964 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
3965 \     MOV @RSP+,IP                \ restore IP saved by COLON
3966 \     MOV @IP+,PC                 \
3967 \ ENDCODE
3968 \     \
3969
3970 \ CODE LCD_RdS                    \ -- status       Read Status
3971 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
3972 \     JMP LCD_R
3973 \ ENDCODE
3974 \     \
3975
3976 \ CODE LCD_RdC                    \ -- char         Read Char
3977 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
3978 \     JMP LCD_R
3979 \ ENDCODE
3980 \     \
3981
3982 \ -------------+------+------+------+------++---+---+---+---+---------+
3983 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
3984 \ -------------+------+------+------+------++---+---+---+---+---------+
3985 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
3986 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
3987 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
3988 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
3989 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
3990 \ -------------+------+------+------+------++---+---+---+---+---------+
3991
3992
3993 \ ******************************\
3994 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
3995 \ ******************************\
3996 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
3997 \ ------------------------------\
3998 \ define LPM mode for ACCEPT    \
3999 \ ------------------------------\
4000 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
4001 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
4002 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
4003 BIT.B #SW2,&SW2_IN              \ test switch S2
4004 0= IF                           \ case of switch S2 pressed
4005     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
4006     U< IF
4007         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
4008     THEN
4009 ELSE
4010     BIT.B #SW1,&SW1_IN          \ test switch S1 input
4011     0= IF                       \ case of Switch S1 pressed
4012         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
4013         U>= IF                  \
4014             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
4015         THEN                    \
4016     THEN                        \
4017 THEN                            \
4018 RETI                            \ CPU is ON, GIE is OFF
4019 ENDASM                          \
4020     \
4021
4022
4023 \ ------------------------------\
4024 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
4025 \ ******************************\
4026 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
4027 \ ******************************\
4028 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
4029 \                               \       SMclock = 8|16|24 MHz
4030 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
4031 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
4032 \                               \       SR(9)=new Toggle bit memory (ADD on)
4033 \ ------------------------------\
4034 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
4035 \ ------------------------------\
4036 \ define LPM mode for ACCEPT    \
4037 \ ------------------------------\
4038 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
4039 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
4040 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
4041 \ ------------------------------\
4042 \ RC5_FirstStartBitHalfCycle:   \
4043 \ ------------------------------\
4044 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
4045 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
4046 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
4047 MOV     #1778,X                 \ RC5_Period in us
4048 MOV     #14,W                   \ count of loop
4049 BEGIN                           \
4050 \ ------------------------------\
4051 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
4052 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
4053     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
4054 \ RC5_Compute_3/4_Period:       \                   |
4055     RRUM    #1,X                \ X=1/2 cycle       |
4056     MOV     X,Y                 \ Y=1/2             ^
4057     RRUM    #1,Y                \ Y=1/4
4058     ADD     X,Y                 \ Y=3/4
4059 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
4060     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
4061     0= UNTIL                    \
4062 \ ------------------------------\
4063 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
4064 \ ------------------------------\
4065     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
4066     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
4067     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
4068     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
4069     SUB     #1,W                \ decrement count loop
4070 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
4071 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
4072 0<> WHILE                       \ ----> out of loop ----+
4073 \ RC5_compute_7/4_Time_out:     \                       |
4074     ADD     X,Y                 \                       |   out of bound = 7/4 period 
4075 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
4076     BEGIN                       \                       |
4077         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
4078         0>= IF                  \                       |   if cycle time out of bound
4079             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
4080             RETI                \                       |   then quit to do nothing
4081         THEN                    \                       |
4082 \ ------------------------------\                       |
4083         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
4084     0<> UNTIL                   \                   |   |
4085     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
4086 REPEAT                          \ ----> loop back --+   |
4087 \ ------------------------------\                       |
4088 \ RC5_SampleEndOf:              \ <---------------------+
4089 \ ------------------------------\
4090 BIC     #$30,&TA0CTL           \ stop timer_A0
4091 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
4092 \ ******************************\
4093 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
4094 \ ******************************\
4095 MOV     @RSP,X                  \ retiSR(9)  = old UF9 = old RC5 toggle bit
4096 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
4097 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
4098 BIT     #BIT13,X                \ X(13) = New_RC5_command
4099 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
4100 THEN                            \
4101 XOR     #UF9,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
4102 \ ******************************\
4103 \ RC5_ComputeNewRC5word         \
4104 \ ******************************\
4105 SUB     #4,PSP                  \
4106 MOV     &BASE,2(PSP)            \ save variable BASE before use
4107 MOV     TOS,0(PSP)              \ save TOS before use
4108 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
4109 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
4110 \ ******************************\
4111 \ RC5_ComputeC6bit              \
4112 \ ******************************\
4113 BIT     #$4000,IP              \ test /C6 bit in IP
4114 0= IF   BIS #$40,TOS           \ set C6 bit in S
4115 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
4116 \ ******************************\
4117 \ RC5_CommandByteIsDone         \ RC5_code --
4118 \ ******************************\
4119
4120 \ ------------------------------\
4121 \ Display IR_RC5 code           \
4122 \ ------------------------------\
4123 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
4124 \ ------------------------------\
4125 LO2HI                           \ switch from assembler to FORTH
4126     ['] LCD_CLEAR IS CR         \ redirects CR
4127     ['] LCD_WrC  IS EMIT        \ redirects EMIT
4128     $10 BASE !                 \ change BASE to hexadecimal
4129     CR ." $" 2 U.R             \ print IR_RC5 code
4130     ['] (CR) IS CR              \ restore CR
4131     ['] (EMIT) IS EMIT          \ restore EMIT
4132 HI2LO                           \ switch from FORTH to assembler
4133 \ ------------------------------\
4134 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
4135 \ ------------------------------\
4136 MOV @PSP+,&BASE                 \ restore variable BASE
4137 RETI                            \ CPU is ON, GIE is OFF
4138 ENDASM                          \
4139     \ 
4140
4141 CODE START                      \
4142 \ ------------------------------\
4143 \ TB0CTL = %0000 0010 1001 0100\$3C0
4144 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
4145 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
4146 \                      --       \ID input divider \ 10 = /4
4147 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
4148 \                            -  \TBCLR TimerB Clear
4149 \                             - \TBIE
4150 \                              -\TBIFG
4151 \ --------------------------------\\
4152 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
4153 \              --                 \CM Capture Mode
4154 \                --               \CCIS
4155 \                   -             \SCS
4156 \                    --           \CLLD
4157 \                      -          \CAP
4158 \                        ---      \OUTMOD \ 011 = set/reset
4159 \                           -     \CCIE
4160 \                             -   \CCI
4161 \                              -  \OUT
4162 \                               - \COV
4163 \                                -\CCIFG
4164 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
4165 \ TB0EX0                          \$3E0 
4166 \ ------------------------------\
4167 \ set TimerB to make 50kHz PWM  \
4168 \ ------------------------------\
4169 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
4170 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
4171 \ ------------------------------\
4172 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
4173 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
4174 \ ------------------------------\
4175     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
4176     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
4177 \ ------------------------------\
4178 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
4179 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
4180 \ ------------------------------\
4181 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
4182 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
4183 \ ------------------------------\
4184     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
4185 \ ------------------------------\
4186 \ set TimerB to generate PWM for LCD_Vo
4187 \ ------------------------------\
4188     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
4189 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
4190     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
4191 \ ------------------------------\
4192     BIS.B #LCDVo,&LCDVo_DIR     \
4193     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
4194 \ ------------------------------\
4195     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
4196     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
4197 \ ------------------------------\
4198     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
4199     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
4200 \ ------------------------------\
4201 \ WDT interval init part        \
4202 \ ------------------------------\
4203     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
4204 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
4205 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
4206     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
4207 \ ------------------------------\
4208 \ init RC5_Int                  \
4209 \ ------------------------------\
4210     BIS.B #RC5,&IR_IE           \ enable RC5_Int
4211     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
4212 \ ------------------------------\
4213 \ init interrupt vectors
4214 \ ------------------------------\
4215     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
4216     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
4217 \ ------------------------------\
4218 \ define LPM mode for ACCEPT    \
4219 \ ------------------------------\
4220 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
4221 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
4222 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
4223
4224 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
4225
4226 \ ------------------------------\
4227 \ Init LCD 2x20                 \
4228 \ ------------------------------\
4229     $03E8 20_US                \ 1-  wait 20 ms
4230     $03 TOP_LCD                \ 2- send DB5=DB4=1
4231     $CD 20_US                  \ 3- wait 4,1 ms
4232     $03 TOP_LCD                \ 4- send again DB5=DB4=1
4233     $5 20_US                   \ 5- wait 0,1 ms
4234     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
4235     $2 20_US                   \    wait 40 us = LCD cycle
4236     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
4237     $2 20_US                   \    wait 40 us = LCD cycle
4238     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
4239     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
4240     LCD_Clear                   \ 10- "LCD_Clear"
4241     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
4242     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
4243     LCD_Clear                   \ 10- "LCD_Clear"
4244     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
4245     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
4246     CR ." I love you"   
4247     ['] (CR) IS CR              \ ' (CR) is CR
4248     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
4249     CR
4250     ."    RC5toLCD is running. Type STOP to quit"
4251 \    NOECHO                      \ uncomment to run this app without terminal connexion
4252     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
4253     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
4254 ;
4255     \
4256
4257 : STOP                  \ stops multitasking, must to be used before downloading app
4258     ['] (WARM) IS WARM  \ remove START app from FORTH init process
4259     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
4260 ;
4261     \
4262
4263
4264
4265 PWR_STATE
4266
4267
4268 CODE MAX    \    n1 n2 -- n3       signed maximum
4269             CMP     @PSP,TOS    \ n2-n1
4270             S<      ?GOTO FW1   \ n2<n1
4271 BW1         ADD     #2,PSP
4272             MOV     @IP+,PC
4273 ENDCODE
4274     \
4275
4276 CODE MIN    \    n1 n2 -- n3       signed minimum
4277             CMP     @PSP,TOS     \ n2-n1
4278             S<      ?GOTO BW1    \ n2<n1
4279 FW1         MOV     @PSP+,TOS
4280             MOV     @IP+,PC
4281 ENDCODE
4282     \
4283
4284 : U.R                       \ u n --           display u unsigned in n width (n >= 2)
4285   >R  <# 0 # #S #>  
4286   R> OVER - 0 MAX SPACES TYPE
4287 ;
4288     \
4289
4290 CODE 20_US                      \ n --      n * 20 us
4291 BEGIN                           \ 3 cycles loop + 6~  
4292 \    MOV     #5,W                \ 3 MCLK = 1 MHz
4293 \    MOV     #23,W               \ 3 MCLK = 4 MHz
4294     MOV     #51,W               \ 3 MCLK = 8 MHz
4295 \    MOV     #104,W              \ 3 MCLK = 16 MHz
4296 \    MOV     #158,W              \ 3 MCLK = 24 MHz
4297     BEGIN                       \ 3 cycles loop ==> 3 * W / F us = 100 us - 1 @ 8 MHz
4298         SUB #1,W                \ 1
4299     0= UNTIL                    \ 2
4300     SUB     #1,TOS              \ 1
4301 0= UNTIL                        \ 2
4302     MOV     @PSP+,TOS           \ 2
4303     MOV     @IP+,PC             \ 4
4304 ENDCODE
4305     \
4306
4307 CODE TOP_LCD                    \ LCD Sample
4308 \                               \ if write : %xxxxWWWW --
4309 \                               \ if read  : -- %0000RRRR
4310     BIS.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 0-->1
4311     BIT.B #LCD_RW,&LCD_CMD_IN   \ lcd_rw test
4312 0= IF                           \ write LCD bits pattern
4313     AND.B #LCD_DB,TOS           \ 
4314     MOV.B TOS,&LCD_DB_OUT       \ send LCD_Data
4315     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
4316     MOV @PSP+,TOS               \
4317     MOV @IP+,PC
4318 THEN                            \ read LCD bits pattern
4319     SUB #2,PSP
4320     MOV TOS,0(PSP)
4321     BIC.B #LCD_EN,&LCD_CMD_OUT  \ lcd_en 1-->0 ==> strobe data
4322     MOV.B &LCD_DB_IN,TOS        \ get LCD_Data
4323     AND.B #LCD_DB,TOS           \
4324     MOV @IP+,PC
4325 ENDCODE
4326     \
4327
4328 CODE LCD_W                      \ byte --       write byte to LCD 
4329     SUB #2,PSP                  \
4330     MOV TOS,0(PSP)              \ -- %xxxxLLLL %HHHHLLLL
4331     RRUM #4,TOS                 \ -- %xxxxLLLL %xxxxHHHH
4332     BIC.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=0
4333     BIS.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as output
4334 COLON                           \ high level word starts here 
4335     TOP_LCD 2 20_US             \ write high nibble first
4336     TOP_LCD 2 20_US 
4337 ;
4338     \
4339
4340 CODE LCD_WrC                    \ char --         Write Char
4341     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
4342     JMP LCD_W 
4343 ENDCODE
4344     \
4345
4346 CODE LCD_WrF                    \ func --         Write Fonction
4347     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
4348     JMP LCD_W 
4349 ENDCODE
4350     \
4351
4352 : LCD_Clear 
4353     $01 LCD_WrF 100 20_us      \  $01 LCD_WrF 80 20_us ==> bad init !
4354 ;
4355     \
4356
4357 : LCD_Home 
4358     $02 LCD_WrF 100 20_us 
4359 ;
4360     \
4361
4362 \ : LCD_Entry_set       $04 OR LCD_WrF ;
4363
4364 \ : LCD_Display_Ctrl    $08 OR LCD_WrF ;
4365
4366 \ : LCD_Display_Shift   $10 OR LCD_WrF ;
4367
4368 \ : LCD_Fn_Set          $20 OR LCD_WrF ;
4369
4370 \ : LCD_CGRAM_Set       $40 OR LCD_WrF ;
4371
4372 \ : LCD_Goto            $80 OR LCD_WrF ;
4373
4374 \ CODE LCD_R                      \ -- byte       read byte from LCD
4375 \     BIC.B #LCD_DB,&LCD_DB_DIR   \ LCD_Data as intput
4376 \     BIS.B #LCD_RW,&LCD_CMD_OUT  \ lcd_rw=1
4377 \ COLON                           \ starts a FORTH word
4378 \     TOP_LCD 2 20_us             \ -- %0000HHHH
4379 \     TOP_LCD 2 20_us             \ -- %0000HHHH %0000LLLL
4380 \ HI2LO                           \ switch from FORTH to assembler
4381 \     RLAM #4,0(PSP)              \ -- %HHHH0000 %0000LLLL
4382 \     ADD.B @PSP+,TOS             \ -- %HHHHLLLL
4383 \     MOV @RSP+,IP                \ restore IP saved by COLON
4384 \     MOV @IP+,PC                 \
4385 \ ENDCODE
4386 \     \
4387
4388 \ CODE LCD_RdS                    \ -- status       Read Status
4389 \     BIC.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=0
4390 \     JMP LCD_R
4391 \ ENDCODE
4392 \     \
4393
4394 \ CODE LCD_RdC                    \ -- char         Read Char
4395 \     BIS.B #LCD_RS,&LCD_CMD_OUT  \ lcd_rs=1
4396 \     JMP LCD_R
4397 \ ENDCODE
4398 \     \
4399
4400 \ -------------+------+------+------+------++---+---+---+---+---------+
4401 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
4402 \ -------------+------+------+------+------++---+---+---+---+---------+
4403 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
4404 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
4405 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
4406 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
4407 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
4408 \ -------------+------+------+------+------++---+---+---+---+---------+
4409
4410
4411 \ ******************************\
4412 ASM WDT_INT                     \ Watchdog interrupt routine, warning : not FORTH executable !
4413 \ ******************************\
4414 BIC #$F8,0(RSP)                \ set CPU ON and GIE OFF in retiSR to force fall down to LPM mode
4415 \ ------------------------------\
4416 \ define LPM mode for ACCEPT    \
4417 \ ------------------------------\
4418 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
4419 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
4420 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
4421 BIT.B #SW2,&SW2_IN              \ test switch S2
4422 0= IF                           \ case of switch S2 pressed
4423     CMP #38,&TB0CCR2            \ maxi Ton = 34/40 & VDD=3V6 ==> LCD_Vo = -2V2
4424     U< IF
4425         ADD #1,&TB0CCR2         \ action for switch S2 (P2.5) : 78 mV / increment
4426     THEN
4427 ELSE
4428     BIT.B #SW1,&SW1_IN          \ test switch S1 input
4429     0= IF                       \ case of Switch S1 pressed
4430         CMP #7,&TB0CCR2         \ mini Ton = 6/40 & VDD=3V6 ==> LCD_Vo = 0V
4431         U>= IF                  \
4432             SUB #1,&TB0CCR2     \ action for switch S1 (P2.6) : -78 mV / decrement
4433         THEN                    \
4434     THEN                        \
4435 THEN                            \
4436 RETI                            \ CPU is ON, GIE is OFF
4437 ENDASM                          \
4438     \
4439
4440
4441 \ ------------------------------\
4442 \ IR_RC5 driver                 \ IP,S,T,W,X,Y registers are free for use
4443 \ ******************************\
4444 ASM RC5_INT                     \   wake up on Px.RC5 change interrupt
4445 \ ******************************\
4446 \                               \ in :  SR(9)=old Toggle bit memory (ADD on)
4447 \                               \       SMclock = 8|16|24 MHz
4448 \                               \ use : BASE,TOS,IP,W,X,Y, TA0 timer, TA0R register
4449 \                               \ out : TOS = 0 C6 C5 C4 C3 C2 C1 C0
4450 \                               \       SR(9)=new Toggle bit memory (ADD on)
4451 \ ------------------------------\
4452 BIC     #$F8,0(RSP)            \ CPU is ON and GIE is OFF in retiSR to force fall down to LPM0_LOOP
4453 \ ------------------------------\
4454 \ define LPM mode for ACCEPT    \
4455 \ ------------------------------\
4456 \ MOV #LPM4,&LPM_MODE             \ with MSP430FR59xx
4457 \ MOV #LPM2,&LPM_MODE             \ with MSP430FR57xx, terminal input don't work for LPMx > 2
4458 \                                 \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
4459 \ ------------------------------\
4460 \ RC5_FirstStartBitHalfCycle:   \
4461 \ ------------------------------\
4462 MOV     #0,&TA0EX0              \ predivide by 1 in TA0EX0 register ( 8 MHZ), reset value
4463 \ MOV     #1,&TA0EX0              \ predivide by 2 in TA0EX0 register (16 MHZ)
4464 \ MOV     #2,&TA0EX0              \ predivide by 3 in TA0EX0 register (24 MHZ)
4465 MOV     #1778,X                 \ RC5_Period in us
4466 MOV     #14,W                   \ count of loop
4467 BEGIN                           \
4468 \ ------------------------------\
4469 \ RC5_TopSynchro:               \ <--- loop back ---+ with readjusted RC5_Period
4470 \ ------------------------------\                   | here, we are just after 1/2 RC5_cycle
4471     MOV #%1011100100,&TA0CTL   \ (re)start timer_A | SMCLK/8 : 1us time interval,free running,clear TA0_IFG and TA0R
4472 \ RC5_Compute_3/4_Period:       \                   |
4473     RRUM    #1,X                \ X=1/2 cycle       |
4474     MOV     X,Y                 \ Y=1/2             ^
4475     RRUM    #1,Y                \ Y=1/4
4476     ADD     X,Y                 \ Y=3/4
4477 \ RC5_Wait_1_1/4                \ wait 3/4 cycle after 1/2 cycle to sample RC5_Input at 1/4 cycle+1
4478     BEGIN   CMP Y,&TA0R         \ CMP &TA0R with 3/4 cycle value 
4479     0= UNTIL                    \
4480 \ ------------------------------\
4481 \ RC5_Sample:                   \ at 5/4 cycle, we can sample RC5_input, ST2/C6 bit first
4482 \ ------------------------------\
4483     BIT.B   #RC5,&IR_IN         \ C_flag = IR bit
4484     ADDC    IP,IP               \ C_flag <-- IP(15):IP(0) <-- C_flag
4485     MOV     &IR_IN,&IR_IES      \ preset Px_IES.y state for next IFG
4486     BIC.B   #RC5,&IR_IFG        \ clear Px_IFG.y after 4/4 cycle pin change
4487     SUB     #1,W                \ decrement count loop
4488 \                               \  count = 13 ==> IP = x  x  x  x  x  x  x  x |x  x  x  x  x  x  x /C6
4489 \                               \  count = 0  ==> IP = x  x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0  1 
4490 0<> WHILE                       \ ----> out of loop ----+
4491 \ RC5_compute_7/4_Time_out:     \                       |
4492     ADD     X,Y                 \                       |   out of bound = 7/4 period 
4493 \ RC5_WaitHalfCycleP1.2_IFG:    \                       |
4494     BEGIN                       \                       |
4495         CMP     Y,&TA0R         \                       |   TA0R = 5/4 cycle test
4496         0>= IF                  \                       |   if cycle time out of bound
4497             BIC  #$30,&TA0CTL  \                       |   stop timer_A0
4498             RETI                \                       |   then quit to do nothing
4499         THEN                    \                       |
4500 \ ------------------------------\                       |
4501         BIT.B   #RC5,&IR_IFG    \                   ^   |   test P1.2_IFG
4502     0<> UNTIL                   \                   |   |
4503     MOV     &TA0R,X             \                   |   |   get new RC5_period value 
4504 REPEAT                          \ ----> loop back --+   |
4505 \ ------------------------------\                       |
4506 \ RC5_SampleEndOf:              \ <---------------------+
4507 \ ------------------------------\
4508 BIC     #$30,&TA0CTL           \ stop timer_A0
4509 RLAM    #1,IP                   \ IP =  x /C6 Tg A4 A3 A2|A1 A0 C5 C4 C3 C2 C1 C0  1  0
4510 \ ******************************\
4511 \ Only New_RC5_Command ADD_ON   \ use SR(9) bit as toggle bit
4512 \ ******************************\
4513 MOV     @RSP,X                  \ retiSR(9)  = old UF9 = old RC5 toggle bit
4514 RLAM    #4,X                    \ retiSR(11,10,9)= X(11,10,9) --> X(15,14,13)
4515 XOR     IP,X                    \ (new XOR old) Toggle bit (13)
4516 BIT     #BIT13,X                \ X(13) = New_RC5_command
4517 0= IF RETI                      \ case of repeated RC5_command : RETI without SR(9) change
4518 THEN                            \
4519 XOR     #UF9,0(RSP)             \ change Toggle bit memory, UserFlag1 = SR(9) = 1
4520 \ ******************************\
4521 \ RC5_ComputeNewRC5word         \
4522 \ ******************************\
4523 SUB     #4,PSP                  \
4524 MOV     &BASE,2(PSP)            \ save variable BASE before use
4525 MOV     TOS,0(PSP)              \ save TOS before use
4526 MOV.B   IP,TOS                  \ TOS = C5 C4 C3 C2 C1 C0  0  0
4527 RRUM    #2,TOS                  \ TOS =  0  0 C5 C4 C3 C2 C1 C0
4528 \ ******************************\
4529 \ RC5_ComputeC6bit              \
4530 \ ******************************\
4531 BIT     #$4000,IP              \ test /C6 bit in IP
4532 0= IF   BIS #$40,TOS           \ set C6 bit in S
4533 THEN                            \ TOS =  0  C6 C5 C4 C3 C2 C1 C0
4534 \ ******************************\
4535 \ RC5_CommandByteIsDone         \ RC5_code --
4536 \ ******************************\
4537
4538 \ ------------------------------\
4539 \ Display IR_RC5 code           \
4540 \ ------------------------------\
4541 \ BIS.B #LED1,&LED1_OUT           \ switch ON LED1, comment if no LED
4542 \ ------------------------------\
4543 LO2HI                           \ switch from assembler to FORTH
4544     ['] LCD_CLEAR IS CR         \ redirects CR
4545     ['] LCD_WrC  IS EMIT        \ redirects EMIT
4546     $10 BASE !                 \ change BASE to hexadecimal
4547     CR ." $" 2 U.R             \ print IR_RC5 code
4548     ['] (CR) IS CR              \ restore CR
4549     ['] (EMIT) IS EMIT          \ restore EMIT
4550 HI2LO                           \ switch from FORTH to assembler
4551 \ ------------------------------\
4552 \ BIC.B #LED1,&LED1_OUT           \ switch OFF LED1, comment if no LED
4553 \ ------------------------------\
4554 MOV @PSP+,&BASE                 \ restore variable BASE
4555 RETI                            \ CPU is ON, GIE is OFF
4556 ENDASM                          \
4557     \ 
4558
4559 CODE START                      \
4560 \ ------------------------------\
4561 \ TB0CTL = %0000 0010 1001 0100\$3C0
4562 \               - -             \CNTL Counter lentgh \ 00 = 16 bits
4563 \                   --          \TBSSEL TimerB clock select \ 10 = SMCLK
4564 \                      --       \ID input divider \ 10 = /4
4565 \                        --     \MC Mode Control \ 01 = up to TB0CCR0
4566 \                            -  \TBCLR TimerB Clear
4567 \                             - \TBIE
4568 \                              -\TBIFG
4569 \ --------------------------------\\
4570 \ TB0CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E}
4571 \              --                 \CM Capture Mode
4572 \                --               \CCIS
4573 \                   -             \SCS
4574 \                    --           \CLLD
4575 \                      -          \CAP
4576 \                        ---      \OUTMOD \ 011 = set/reset
4577 \                           -     \CCIE
4578 \                             -   \CCI
4579 \                              -  \OUT
4580 \                               - \COV
4581 \                                -\CCIFG
4582 \ TB0CCRx                         \$3D{2,4,6,8,A,C,E}
4583 \ TB0EX0                          \$3E0 
4584 \ ------------------------------\
4585 \ set TimerB to make 50kHz PWM  \
4586 \ ------------------------------\
4587 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
4588 \    MOV #0,&TB0EX0             \ predivide by 1 in TB0EX0 register (1 MHZ) (25 kHz PWM)
4589 \ ------------------------------\
4590 \    MOV #%1000010100,&TB0CTL  \ SMCLK/1, up mode, clear timer, no int
4591 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (4 MHZ)
4592 \ ------------------------------\
4593     MOV #%1010010100,&TB0CTL   \ SMCLK/4, up mode, clear timer, no int
4594     MOV #0,&TB0EX0              \ predivide by 1 in TB0EX0 register (8 MHZ)
4595 \ ------------------------------\
4596 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
4597 \    MOV #1,&TB0EX0             \ predivide by 2 in TB0EX0 register (16 MHZ)
4598 \ ------------------------------\
4599 \    MOV #%1010010100,&TB0CTL  \ SMCLK/4, up mode, clear timer, no int
4600 \    MOV #2,&TB0EX0             \ predivide by 3 in TB0EX0 register (24 MHZ)
4601 \ ------------------------------\
4602     MOV #40,&TB0CCR0            \ 40*0.5us=20us (40us @ 1MHz)
4603 \ ------------------------------\
4604 \ set TimerB to generate PWM for LCD_Vo
4605 \ ------------------------------\
4606     MOV #%1100000,&TB0CCTL2    \ output mode = set/reset \ clear CCIFG
4607 \    MOV #20,&TB0CCR2           \ contrast adjust : 20/40 ==> LCD_Vo = -1V1|+3V6 (Vcc=3V6)
4608     MOV #25,&TB0CCR2            \ contrast adjust : 25/40 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3)
4609 \ ------------------------------\
4610     BIS.B #LCDVo,&LCDVo_DIR     \
4611     BIS.B #LCDVo,&LCDVo_SEL     \ SEL.2 TB0.2
4612 \ ------------------------------\
4613     BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs
4614     BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable
4615 \ ------------------------------\
4616     BIS.B #LCD_DB,&LCD_DB_DIR   \ as output, wired to DB(4-7) LCD_Data
4617     BIC.B #LCD_DB,&LCD_DB_REN   \ LCD_Data pullup/down disable
4618 \ ------------------------------\
4619 \ WDT interval init part        \
4620 \ ------------------------------\
4621     MOV #$5A5E,&WDTCTL         \ init WDT VLOCLK source ~10kHz /2^9 (50 ms), interval mode
4622 \    MOV #$5A3D,&WDTCTL         \ init WDT ACLK source 32.768kHz /2^13 (250 ms), interval mode
4623 \    MOV #$5A5D,&WDTCTL         \ init WDT Vloclk source 10kHz /2^13 (800 ms), interval mode
4624     BIS #1,&SFRIE1              \ enable WDT interval mode interrupt in SFRIE
4625 \ ------------------------------\
4626 \ init RC5_Int                  \
4627 \ ------------------------------\
4628     BIS.B #RC5,&IR_IE           \ enable RC5_Int
4629     BIC.B #RC5,&IR_IFG          \ reset RC5_Int flag
4630 \ ------------------------------\
4631 \ init interrupt vectors
4632 \ ------------------------------\
4633     MOV #WDT_INT,&WDT_Vec       \ init WDT interval vector interrupt
4634     MOV #RC5_INT,&IR_Vec        \ init interrupt vector
4635 \ ------------------------------\
4636 \ define LPM mode for ACCEPT    \
4637 \ ------------------------------\
4638 \    MOV #LPM4,&LPM_MODE         \ with MSP430FR59xx
4639 \    MOV #LPM2,&LPM_MODE         \ with MSP430FR57xx, terminal input don't work for LPMx > 2
4640 \                               \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value
4641
4642 LO2HI                           \ no need to push IP because (WARM) resets the Return Stack ! 
4643
4644 \ ------------------------------\
4645 \ Init LCD 2x20                 \
4646 \ ------------------------------\
4647     $03E8 20_US                \ 1-  wait 20 ms
4648     $03 TOP_LCD                \ 2- send DB5=DB4=1
4649     $CD 20_US                  \ 3- wait 4,1 ms
4650     $03 TOP_LCD                \ 4- send again DB5=DB4=1
4651     $5 20_US                   \ 5- wait 0,1 ms
4652     $03 TOP_LCD                \ 6- send again again DB5=DB4=1
4653     $2 20_US                   \    wait 40 us = LCD cycle
4654     $02 TOP_LCD                \ 7- send DB5=1 DB4=0
4655     $2 20_US                   \    wait 40 us = LCD cycle
4656     $28 LCD_WRF                \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal
4657     $08 LCD_WRF                \ 9- %1DCB   "DisplayControl" : Display off, Cursor off, Blink off. 
4658     LCD_Clear                   \ 10- "LCD_Clear"
4659     $06 LCD_WRF                \ 11- %01xx   "LCD_EntrySet" : address and cursor shift after writing in RAM
4660     $0C LCD_WRF                \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. 
4661     LCD_Clear                   \ 10- "LCD_Clear"
4662     ['] LCD_HOME IS CR          \ ' CR redirected to LCD_HOME
4663     ['] LCD_WRC  IS EMIT        \ ' EMIT redirected to LCD_WrC
4664     CR ." I love you"   
4665     ['] (CR) IS CR              \ ' (CR) is CR
4666     ['] (EMIT) IS EMIT          \ ' (EMIT) is EMIT
4667     CR
4668     ."    RC5toLCD is running. Type STOP to quit"
4669 \    NOECHO                      \ uncomment to run this app without terminal connexion
4670     LIT RECURSE IS WARM         \ insert this START routine between WARM and (WARM)...
4671     (WARM)                      \ ...and continue with (WARM) (very, very usefull after COLD or RESET !:-)
4672 ;
4673     \
4674
4675 : STOP                  \ stops multitasking, must to be used before downloading app
4676     ['] (WARM) IS WARM  \ remove START app from FORTH init process
4677     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
4678 ;
4679     \
4680
4681
4682
4683
4684 ECHO
4685             ; download is done
4686 PWR_HERE    ; this app is protected against power ON/OFF,
4687 \ START