OSDN Git Service

bug bug bug...
[fast-forth/master.git] / MSP430-FORTH / lib / I2C_Slave.f
1 \ name : MSP430FR5xxx_I2C_Slave.f
2 RST_STATE
3 \ NOECHO
4
5 \ Copyright (C) <2015>  <J.M. THOORENS>
6 \
7 \ This program is free software: you can redistribute it and/or modify
8 \ it under the terms of the GNU General Public License as published by
9 \ the Free Software Foundation, either version 3 of the License, or
10 \ (at your option) any later version.
11 \
12 \ This program is distributed in the hope that it will be useful,
13 \ but WITHOUT ANY WARRANTY\ without even the implied warranty of
14 \ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 \ GNU General Public License for more details.
16 \
17 \ You should have received a copy of the GNU General Public License
18 \ along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 \
20 \ driver I2C SLAVE with START interrupt only, for any I2C_Slave addresses
21 \ Target: MSP430FR5xxx @ 8,16,24 MHz
22 \ version 1.0 2015-03-17
23
24 \ ---------------------------------------------------------------------------------------------------------------------;
25 \ SCL clock generation, timing, and test of data(s) number are made by I2C_Master.
26 \ slave can strech SCL low after Start Condition and after any bit.
27 \
28 \ address Ack/Nack is generated by the slave on SDA line (released by the master)
29 \ Two groups of eight addresses (000$xxy and 1111xxxy) are not allowed (reserved)
30 \ after address or data is sent, the transmitter (Master or Slave) must release SDA line to allow (N)Ack by the receiver
31 \ data Ack/Nack are generated by the receiver (master or slave) on SDA line
32 \ a master receiver must signal the end of data to the slave transmitter by sending a Nack bit
33 \ Stop or restart conditions must be generated by master after a Nack bit.
34 \ after Ack bit is sent, Slave must release SDA line to allow master to do stop or restart conditions
35 \
36 \     __      _____ _____ _..._ _____ _____ _NACK _____ _____ _..._ _____ _____ _NACK     _
37 \ SDA   \____/_MSB_X_____X_..._X_LSB_X_R/W_x_ACK_x_MSB_X_____X_..._X_____X_LSB_X_ACK_X___/
38 \     _____     _     _           _     _     _     _     _           _     _     _     ___
39 \ SCL      \___/1\___/2\___...___/7\___/8\___/9\___/1\___/2\___...___/7\___/8\___/9\___/
40 \       ^   ^                             ^     ^                             ^     ^    ^
41 \       |   |Slave Stretch Low            |SSL  |SSL                          |SSL  |SSL |
42 \       |                                                                                |
43 \       |Start Condition                                                                 |stoP Condition
44 \
45 \     __      _____ _____ _..._ _____ _____ _NACK _____ _____ _..._ _____ _____ _NACK ___
46 \ SDA   \____/_MSB_X_____X_..._X_LSB_X_R/W_x_ACK_x_MSB_X_____X_..._X_____X_LSB_X_ACK_X   \____...
47 \     _____     _     _           _     _     _     _     _           _     _     _     ____
48 \ SCL      \___/1\___/2\___...___/7\___/8\___/9\___/1\___/2\___...___/7\___/8\___/9\___/    \_...
49 \       ^   ^                             ^     ^                             ^     ^    ^
50 \       |   |Slave Stretch Low            |SSL  |SSL                          |SSL  |SSL |
51 \       |                                                                                |
52 \       |Start Condition                                                                 |reStart Condition
53 \
54 \ tHIGH : SCL high time
55 \ tLOW : SCL low time
56 \ tBUF : SDA high time between Stop and Start conditions
57 \ tHD:STA : Start_Condition SCL high time after SDA is low
58 \ tSU:STO : Stop_Condition SCL high time before SDA rise
59 \ tSU:STA : Start_Condition SCL high time before SDA fall
60 \ tHD:DAT : SDA data change time after SCL is low
61 \ the SDA line must be strobe just after SCL is high
62 \ the SDA data must be change just after SCL is low
63 \ standard mode (up to 100 kHz) :   tHIGH   =   tHD:STA =   tSU:STO =   4µs
64 \                                   tLOW    =   tSU:STA =   tBUF    =   4,7µs
65 \                                   tHD:DAT <=  3,45 µs
66 \
67 \ fast mode     (up to 400 kHz) :   tHIGH   =   tHD:STA =   tSU:STO =   0,6µs
68 \                                   tLOW    =   tSU:STA =   tBUF    =   1,3µs
69 \                                   tHD:DAT <=  0,9 µs
70 \ -------------------------------------------------------------------------------------------------------------------;
71
72
73
74 VARIABLE I2CS_OWN       \ slave I2C address without RW flag (low byte) + DATA0 input (HIGH byte)
75 \ 2 ALLOT               \ next the low byte of I2CS_OWN word, it is the input buffer
76 VARIABLE I2CS_BUF       \ buffer output, lentgh (low byte),DATA0 output (HIGH byte)
77 \ 2 ALLOT               \ this byte lentgh is shared by input and output buffers
78
79 \ ******************************\
80 ASM I2CS_TX                     \ TX part of I2C_Slave
81 \ ******************************\
82 \                               \       T = TX buffer_org
83 \                               \ use   W = TX buffer_ptr
84 \                               \ out : low(I2CS_BUF) = RX or TX lentgh
85 \ ------------------------------\
86 MOV T,W                         \ W = TX_buf_ptr -1
87 BEGIN                           \
88     ADD #1,W                    \ first reserve one byte for length then inc
89     MOV.B @W,&UCB0TXBUF         \ +[W] --> UCB0TXBUF
90 \   ----------------------------\
91 \   slave send byte             \
92 \   ----------------------------\
93     BEGIN                       \
94         BIT #$0C,&UCB0IFG       \ UCB0IFG(STP,STT) = 1 ?
95         0<> IF                  \
96 \           --------------------\
97 \           stop or restart received
98 \           --------------------\
99             SUB   T,W           \
100             SUB.B #1,W          \ sub #1, because char +[W] is not sent
101             MOV.B W,0(T)        \ store length in first byte of buffer output
102             BIC #UCTR,&UCB0CTLW0 \ reset UCTR R/W bit for next START
103             MOV @RSP+,PC        \ ===> ret
104 \           --------------------\
105         THEN                    \
106         BIT #2,&UCB0IFG         \ UCB0IFG(TX0) = 1 ?
107     0<> UNTIL                   \
108 AGAIN                           \
109 ENDASM                          \
110     \
111
112 \ -------------+------+------+------+------++---+---+---+---+---------+
113 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
114 \ -------------+------+------+------+------++---+---+---+---+---------+
115 \ LPM0 = $18  |  0   |  0   |  0   |  1   || 1 | x | x | x |  180uA  | default mode
116 \ LPM1 = $58  |  0   |  1   |  0   |  1   || 1 | x | x | x |         | same mode as LPM0
117 \ LPM2 = $98  |  1   |  0   |  0   |  1   || 1 | x | x | x |   60uA  |
118 \ LPM3 = $D8  |  1   |  1   |  0   |  1   || 1 | x | x | x |   10uA  | 32768Hz XTAL is running
119 \ LPM4 = $F8  |  1   |  1   |  1   |  1   || 1 | x | x | x |    6uA  |
120 \ -------------+------+------+------+------++---+---+---+---+---------+
121
122 \ **************************************\
123 ASM I2C_S                               \ <== eUSCIB0 interrupt vector : i2c_addres&R/w sent by master is received
124 \ **************************************\
125 BIC #$F8,0(RSP)                         \ SCG1,SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP with pending interrupt
126 MOV #$98,&LPM_MODE                      \ to reenter in LPM2 mode. LPM3-4 don't work with MSP430FR57xx.
127 \ --------------------------------------\
128 MOV #I2CS_BUF,T                         \ T = buffer output address -1
129 MOV #I2CS_OWN,S                         \ S = buffer input address -1
130 MOV #0,&UCB0IFG                         \ write UCB0IFG to clear all int flags (STTIFG,TXIFG,..)
131 CMP.B &UCB0I2COA0,&UCB0ADDRX            \ UCB0ADDRX = own address ?
132 0= IF                                   \ 
133 \ --------------------------------------\
134 \ It's my own address                   \
135 \ --------------------------------------\
136     BIS #UCTXACK,&UCB0CTLW0             \ send software Ack address
137     BIT #UCTR,&UCB0CTLW0                \ test UCB0CTLW0(UCTR) R/W bit
138     0= IF                               \ I2C_Master Write
139 \       --------------------------------\
140 \       slave receive datas             \ yes
141 \       --------------------------------\
142         MOV S,W                         \ W = input buffer address - 1
143         BEGIN                           \
144 \           ----------------------------\
145 \           slave receive one byte      \
146 \           ----------------------------\
147             BEGIN                       \
148                 BIT #$8C,&UCB0IFG       \ UCB0IFG(STP,STT,CLTO) = 1 ? (STOP, START, SCL low timeout)
149                 0<> IF                  \
150 \                   --------------------\
151 \                   TX stop or restart  \ from master
152 \                   --------------------\
153                     SUB   S,W           \ W = Adr_end - Adr_start = length
154                     MOV.B W,0(T)        \ store length in first byte of buffer output
155 \                   --------------------\
156 \                   insert here post RX code
157 \                   --------------------\
158                     RETI                \
159                 THEN                    \ if not (stop, restart, CLTO)
160                 BIT #1,&UCB0IFG         \ UCB0IFG(RX0) = 1 ?
161             0<> UNTIL                   \ 
162             ADD #1,W                    \ reserve one byte for length first, then preincrement
163             MOV.B &UCB0RXBUF,0(W)       \ [UCB0RXBUF] = data --> +[W]
164         AGAIN                           \ loop for new received data if any
165     THEN                                \ end of I2C_Master read
166 \   ------------------------------------\
167 \   slave transmit datas variant 1      \ to loop back after bad_own_address code
168 \   ------------------------------------\
169     CALL #I2CS_TX                       \ 
170     RETI                                \
171 \   ------------------------------------\
172 \   slave transmit datas variant 2      \
173 \   ------------------------------------\
174 \         MOV T,W                         \ W = output buffer address -1
175 \         BEGIN                           \
176 \             ADD     #1,W                \ first reserve one byte for length
177 \             MOV.B   @W,&UCB0TXBUF       \ +[W] --> UCB0TXBUF
178 \ \           ----------------------------\
179 \ \           slave send byte             \
180 \ \           ----------------------------\
181 \             BEGIN                       \
182 \                 BIT.B #$0C,&UCB0IFG     \ UCB0IFG(STP,STT) = 1 ?
183 \                 0<> IF                  \
184 \ \               ------------------------\
185 \ \               RX stop or restart      \ from master
186 \ \               ------------------------\
187 \                     SUB   T,W           \ W = Adr_end - Adr_start = length
188 \                     SUB.B #1,W          \ sub #1, because char +[W] is not sent
189 \                     MOV.B W,0(T)        \ store length in first byte of buffer output
190 \                     BIC.B #UCTR,&UCB0CTLW0  \ reset UCTR R/W bit for next START
191 \                     RETI                \
192 \                 THEN                    \
193 \                 BIT.B #$02,&UCB0IFG     \ UCB0IFG(TX0) = 1 ?
194 \             0<> UNTIL                   \
195 \         AGAIN                           \
196 \   ------------------------------------\
197 \   End of slave transmit datas variants\
198 \   ------------------------------------\
199 THEN                                    \ if bad I2C address
200 \ --------------------------------------\
201 \ BAD I2C ADDRESS CaseOf                \
202 \ --------------------------------------\
203 \ insert here post BAD I2C address code \
204 \ ...that can loop back to I2CS_TX...   \
205 \ --------------------------------------\
206 BIC #UCTXACK,&UCB0CTLW0                 \ send Nack address
207 RETI                                    \
208 ENDASM
209     \
210
211 \ --------------------------------------\
212 CODE START                              \ init I2C_slave 
213 \ --------------------------------------\
214 \ UCB0CTLW0 = %0000 0111 1100 0001     $640
215 \                    -                  UCMST = 0 : I2C_Slave
216 \                     --                UCMODE = %11 = I2C
217 \                       _               USYNC=1 (always 1)
218 \                         --            UCSSEL=SMCLK (don't care in slave mode)
219 \                           -           UCTXACK=0 not auto ACK slave address
220 \                            -          UCTR=0 : RX (for RX address)
221 \                                 -     UCSWRST=1
222 \ UCB0CTLW1 = %0000 0000 1101 0000     $642
223 \                       -               UCETXINT=0 : UCTXIFG0 set address match UCxI2COAx and TX mode
224 \                         --            UCCLTO=%11 : SCL low time out = 34 ms
225 \                            -          UCSWACK=1 : UCTXACK must be written to continue
226 \ UCB0RXBUF                             $64C
227 \ UCB0TXBUF                             $64E
228 \ UCB0I2COA0                            $654 must be written ? enabled ?
229 \ UCB0ADDRX                             $65C
230 \ UCB0ADDMSK                            $65E
231 \ UCB0IE    = %0000 0000 0000 0100     $66A
232 \                               -       UCSTTIE : StartCond Interrupt only
233 \ UCB0IFG                               $66C
234 \ UCB0IV                                $66E : write it to clear all IFG 
235
236 \ ------------------------------\
237 \ init I2C_slave                \
238 MOV #1,&UCB0CTLW0               \ set eUSCI_B in reset state, clear UCB0IE & UCB0IFG all flags
239 BIS #$07A0,&UCB0CTLW0           \
240 BIS #$10,&UCB0CTLW1             \ set software ack address (UCSWACK=1)
241 MOV #%1010,&UCB0I2COA0          \ set my own address
242 BIS #$0400,&UCB0I2COA0          \ UCOAEN=1 enable UCB0I2COA0 with address slave
243 \ MOV #0,&UCB0ADDMSK              \ enable address mask for all addresses i.e. software address 
244 BIC #1,&UCB0CTLW0               \ activate eUSCI_B
245 MOV #4,&UCB0IE                  \ enable StartCond interrupt
246 \ ------------------------------\
247 \ init interrupt vectors
248 MOV #I2C_S,&$FFEE               \ eUSCIB0 interrupt vector
249 \ ------------------------------\
250 \ init PORTA (P2:P1) (complement)
251 \ notice : UCB0 I2C driver seems to control only DIR register !!!
252 BIC.B #S_BUS,&I2CS_REN          \ SDA + SCL pullup/down disable
253 BIC.B #S_BUS,&I2CS_OUT          \ OUT0 : preset output low
254 BIS.B #S_BUS,&I2CS_SEL1         \ enable I2C I/O
255 \ ------------------------------\
256 COLON
257 ." I2C_Slave is running. Type STOP to quit"
258 LIT recurse is WARM         \ insert this routine between COLD and WARM...
259 (WARM) ;                    \ ...and continue with WARM
260     \
261
262 : STOP                  \ stops multitasking, must to be used before downloading app
263     ['] (WARM) IS WARM  \ remove START app from FORTH init process
264     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
265 ;
266     \
267
268 ECHO
269 PWR_HERE
270 \ START