OSDN Git Service

bug bug bug...
[fast-forth/master.git] / MSP430_FORTH / lib / I2C_Soft_Master.f
1 \ name : msp430FR5xxx_I2C_Soft_Master.asm
2
3 WIPE
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
21 \ version 2.0 2015-07-30
22 \ ---------------------------------------------------------------------------------------------------------------------\
23 \ SCL clock generation, timing, and test of data(s) number are made by I2C_Master.
24 \ slave can strech SCL low after Start Condition and after any bit.
25 \
26 \ address Ack/Nack is generated by the slave on SDA line (released by the master)
27 \ Two groups of eight addresses (000xxxy and 1111xxxy) are not allowed (reserved)
28 \ after address or data is sent, the transmitter (Master or Slave) must release SDA line to allow (N)Ack by the receiver
29 \ data Ack/Nack are generated by the receiver (master or slave) on SDA line
30 \ a master receiver must signal the end of data to the slave transmitter by sending a Nack bit
31 \ Stop or restart conditions must be generated by master after a Nack bit.
32 \ after Ack bit is sent, Slave must release SDA line to allow master to do stop or restart conditions.
33 \
34 \
35 \             first byte = address + R/W flag    | byte data (one, for example)
36 \     __      _____ _____ _..._ _____ __R__ _NAK_ _____ _____ _..._ _____ _____ _NAK_     _
37 \ SDA   \____/_MSB_X_____X_..._X_LSB_X__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 \       |   |SSL                          |SSL  |SSL                          |SSL  |SSL |
42 \       |                                                                                |
43 \       |Start Condition                                                                 |stoP Condition
44 \
45 \             first byte = address + R/W flag    | byte data (one, for example)
46 \     __      _____ _____ _..._ _____ __R__ _NAK_ _____ _____ _..._ _____ _____ _NAK_ ___
47 \ SDA   \____/_MSB_X_____X_..._X_LSB_X__W__x_ACK_x_MSB_X_____X_..._X_____X_LSB_X_ACK_X   \____...
48 \     _____     _     _           _     _     _     _     _           _     _     _     ____
49 \ SCL      \___/1\___/2\___...___/7\___/8\___/9\___/1\___/2\___...___/7\___/8\___/9\___/    \_...
50 \       ^   ^                             ^     ^                             ^     ^    ^
51 \       |   |SSL                          |SSL  |SSL                          |SSL  |SSL |
52 \       |                                                                                |
53 \       |Start Condition                                                                 |reStart Condition
54 \
55 \ SSL : Slave can strech SCL low
56 \ tHIGH : SCL high time
57 \ tLOW : SCL low time
58 \ tBUF : SDA high time between Stop and Start conditions
59 \ tHD:STA : Start_Condition SCL high time after SDA is low
60 \ tSU:STO : Stop_Condition SCL high time before SDA rise
61 \ tSU:STA : Start_Condition SCL high time before SDA fall
62 \ tHD:DAT : SDA data change time after SCL is low
63 \ the SDA line must be strobe just after SCL is high
64 \ the SDA data must be change just after SCL is low
65 \ standard mode (up to 100 kHz) :   tHIGH   =   tHD:STA =   tSU:STO =   4µs
66 \                                   tLOW    =   tSU:STA =   tBUF    =   4,7µs
67 \                                   tHD:DAT <=  3,45 µs
68 \ -------------------------------------------------------------------------------------------------------------------\
69 \
70 \
71 \ -------------------------------------------------------------------------------------------------------------------\
72 \ I2C Soft MASTER, Standard MODE, 8,16,24MHz
73 \ -------------------------------------------------------------------------------------------------------------------\
74
75 \ ===============================================================================================
76 \ ===============================================================================================
77
78 \ ###  #####   #####      #####                         #     #
79 \  #  #     # #     #    #     #  ####  ###### #####    ##   ##   ##    ####  ##### ###### #####
80 \  #        # #          #       #    # #        #      # # # #  #  #  #        #   #      #    #
81 \  #   #####  #           #####  #    # #####    #      #  #  # #    #  ####    #   #####  #    #
82 \  #  #       #                # #    # #        #      #     # ######      #   #   #      #####
83 \  #  #       #     #    #     # #    # #        #      #     # #    # #    #   #   #      #   #
84 \ ### #######  #####      #####   ####  #        #      #     # #    #  ####    #   ###### #    #
85
86 \ ===============================================================================================
87 \ ===============================================================================================
88
89 \ use Px.0 to Px.3 pins as SCL and SDA pins to use immediate instruction in one byte (#1,#2,#4,#8)
90
91 \ tested with P1.6 SDA, P1.7 SCL @8 MHZ :
92 \ Start + Adr + Write 3 bytes + Stop + Start + adr + read 2 bytes + stop = 600us ==> 105 kHz 
93 \ See MSP430FR5xxx_I2C_Soft_Master.png
94
95 VARIABLE I2CS_ADR   \ low(I2CS_ADR) = slave I2C address with RW flag, high(I2CS_ADR) = RX buffer,data0
96 2 ALLOT             \ data1,data2
97 VARIABLE I2CM_BUF   \ low(I2CM_BUF) = RX or TX lentgh, high(I2CM_BUF) = TX buffer,data0
98 2 ALLOT             \ data1,data2
99     \
100
101 \ ------------------------------\
102 ASM T_I2C                       \ 4 init first once !!!
103 \ ------------------------------\
104 BEGIN                           \ 3~ loop
105     SUB #1,Y                    \ 1
106 0= UNTIL                        \ 2
107     MOV #1,Y                    \ 2 set I2C tHIGH time @ 8MHz
108 \    MOV #9,Y                   \ 2 set I2C tHIGH time @ 16MHz
109 \    MOV #20,Y                  \ 2 set I2C tHIGH time @ 24MHz
110     MOV @RSP+,PC                \ 4 ret
111 ENDASM                          \
112     \
113
114 \ ------------------------------\       _
115 ASM I2C_PLS                     \ SCL _| |_ pulse
116 \ ------------------------------\   
117 CALL #T_I2C                     \   _   wait tLOW
118 BIC.B   #SMSCL,&I2CSM_DIR       \ _^    release SCL (high)
119 BEGIN
120     BIT.B #SMSCL,&I2CSM_IN      \       test if SCL is released
121 0<> UNTIL
122 CALL    #T_I2C                  \       wait tHIGH
123 BIT.B   #SMSDA,&I2CSM_IN        \ _     get SDA
124 BIS.B   #SMSCL,&I2CSM_DIR       \  v_   force SCL low
125 MOV     @RSP+,PC                \       ret
126 ENDASM                          \
127     \
128
129 \ ------------------------------\
130 ASM I2C_MTX                     \ MASTER TX \ shared code for address and TX data
131 \ ------------------------------\
132 BEGIN                           \
133     ADD.B X,X                   \ 1 l   shift one left
134     U>= IF                      \ 2 l   carry set ?
135         BIC.B #SMSDA,&I2CSM_DIR \ 4 l   yes : SDA as input  ==> SDA high because pull up resistor
136     ELSE                        \ 2 l
137         BIS.B #SMSDA,&I2CSM_DIR \ 4 l   no  : SDA as output ==> SDA low
138     THEN                        \   l  _ 
139     CALL I2C_PLS                \    _| |_ SCL
140     SUB.B #1,W                  \   l   count of bits
141 0= UNTIL                        \   l
142 BIC.B   #SMSDA,&I2CSM_DIR       \ 5 l _   SDA as input : release SDA high to prepare read Ack/Nack
143 MOV     @RSP+,PC                \       ret
144 ENDASM                          \
145     \
146
147 \ ==================================\
148 ASM I2C_M                           \
149 \ ==================================\
150 \                                   \ in    I2CS_ADR/I2CM_BUF as RX/TX buffer requested by I2CS_ADR(0(0))
151 \                                   \       I2CS_ADR(0) = I2C_Slave_addr&R/w
152 \                                   \       I2CM_BUF(0) = TX/RX count of datas
153 \                                   \       I2CM_BUF(0) = 0 ==> send only I2C address
154 \                                   \ used  S           BUF ptr
155 \                                   \       T           datas countdown
156 \                                   \       W           bits countdown
157 \                                   \       X           dataI2CM_
158 \                                   \ out   I2CSLA_ADR & (R/W) unCHNGd
159 \                                   \       S = BUF PTR pointing on first data not exCHNGd
160 \                                   \       T = count+1 of TX/RX datas exCHNGd
161 \                                   \       I2CS_ADR(0) = unCHNGd
162 \                                   \       I2CM_BUF(0) = count of data not exCHNGd (normally = 0)
163 \                                   \       I2CM_BUF(0) = -1 <==> Nack on address
164 \ ----------------------------------\
165 \ I2C_MR_DC_ListenBeforeStart:      \ test if SCL & SDA lines are idle (high)
166 \ ----------------------------------\
167     BIC.B #SM_BUS,&I2CSM_DIR        \ SDA & SCL pins as input
168     BIC.B #SM_BUS,&I2CSM_OUT        \ preset output LOW for SDA & SCL pins
169     MOV #2,T                        \ I2C_MR_DC_Wait_Start_Loop = 8 µs @ 8 MHz
170 \    MOV #4,T                        \ I2C_MR_DC_Wait_Start_Loop = 8 µs @ 16 MHz
171 \    MOV #6,T                        \ I2C_MR_DC_Wait_Start_Loop = 8 µs @ 24 MHz
172     BEGIN                           \
173         BEGIN                       \
174             BEGIN                   \
175                BIT.B #SMSCL,&I2CSM_IN \ 4 P1DIR.3 SCL high ? 
176             0<> UNTIL                 \ 2
177             BIT.B #SMSDA,&I2CSM_IN    \ 4 P1IN.2 SDA high ?
178         0<> UNTIL                     \ 2
179             SUB #1,T                    \ 1
180     0= UNTIL                          \ 2 here the I2C bus is idle
181 \ ------------------------------\
182 \ I2C_Master_Start_Cond:        \ here, SDA and SCL are in idle state
183 \ ------------------------------\
184 BIS.B #SMSDA,&I2CSM_DIR         \ 4- P1DIR.2 force SDA output (low)
185 MOV #5,Y                        \ 2  tHD\STA time 8 MHz
186 \ MOV #15,Y                     \ 2  tHD\STA time 16MHz
187 \ MOV #25,Y                     \ 2  tHD\STA time 24MHz
188 CALL #T_I2C                     \   wait tHD\STA
189 BIS.B #SMSCL,&I2CSM_DIR         \ 4- P1DIR.3 force SCL output (low)
190 \ ------------------------------\
191 \ I2C_Master_Start_EndOf:       \
192 \ ------------------------------\
193 MOV #I2CS_ADR,S                 \ 2 l
194 MOV.B @S+,X                     \ 3 l X = slave address, S = RX buffer
195 MOV #I2CM_BUF,W                 \ 2 l
196 MOV.B @W+,T                     \ 2 l T = count of datas, W = TX buffer
197 BIT.B #1,X                      \ 1 l test I2C R/w flag
198 0= IF                           \ 2 l write flag
199     MOV W,S                     \ 3 l TX buffer
200 THEN                            \
201 \ ------------------------------\
202 \ I2C_Master_Send_address       \     SCL is held low by slave 
203 \ ------------------------------\
204 ADD #1,T                        \     to add address in count
205 MOV #8,W                        \ 1 l prepare 8 bit Master writing
206 MOV #1,Y                        \ 2 tHD\STA time 8 MHz value
207 \ MOV #5,Y                       \ 2 tHD\STA time 16MHz value
208 \ MOV #15,Y                      \ 2 tHD\STA time 24MHz value
209 CALL #I2C_MTX                   \ 4  to send address
210 \ ------------------------------\
211 \ I2C_Master_Loop_Data          \
212 \ ------------------------------\
213 BEGIN                           \
214 \   ----------------------------\
215 \   Master TX/RX ACK/NACK       \
216 \   ----------------------------\
217     MOV #2,Y                    \ 2     tLOW time complement @ 8MHz
218 \     MOV #15,Y                  \ 2     tLOW time complement @ 16MHz
219 \     MOV #20,Y                  \ 2     tLOW time complement @ 24MHz
220     CALL #I2C_PLS               \ _| |_ SCL with BIT SDA, then ret
221     0<> IF  BIS #2,SR           \ l     if Nack (TX), force Z=1 ==> StopCond
222     ELSE    SUB.B #1,T          \       else dec count
223     THEN                        \ l
224 \   ----------------------------\
225 \   I2C_Master_CheckCountDown   \       count=0 or Nack received
226 \   ----------------------------\
227     0= IF                       \       count reached or Nack
228 \   ----------------------------\
229 \   I2C_Master_StopCond         \
230 \   ----------------------------\       before releasing SCL
231         BIS.B #SMSDA,&I2CSM_DIR \ l     P1DIR.2 as output ==> SDA low
232         CALL #T_I2C             \ l _       wait 4 us
233         BIC.B #SMSCL,&I2CSM_DIR \ _|    P1DIR.2 release SCL (high)
234         MOV #5,Y                \ 2      tSU:STO time 8 MHz value
235 \        MOV #15,Y               \ 2     tSU:STO time 16MHz value
236 \        MOV #25,Y               \ 2     tSU:STO time 24MHz value
237         CALL #T_I2C             \     _  wait tSU:STO
238         BIC.B #SMSDA,&I2CSM_DIR \   _|   P1DIR.2 as input  ==> SDA high with pull up resistor
239         SUB.B T,&I2CM_BUF       \ 4 l    refresh buffer length and reach tSU:STO
240         MOV @RSP+,PC            \ ====> 
241 \   ----------------------------\
242     THEN                        \
243 \   ----------------------------\
244     MOV.B #8,W                  \ 1 l     prepare 8 bits transaction
245     BIT.B #1,&I2CS_ADR          \ 3 l     I2C_Master Read/write bit test
246     0=  IF                      \ 2 l     write flag test
247 \       ------------------------\
248 \       I2C write               \
249 \       ------------------------\
250         MOV.B @S+,X             \ 2 l     next byte to transmit
251         CALL #I2C_MTX           \ 4       to send data + test ack
252     ELSE                        \ l
253 \       ------------------------\
254 \       I2C read                \
255 \       ========================\
256 \       I2C_Master_RX:          \       here, SDA is indetermined, SCL is strech low by master
257 \       ========================\
258         BEGIN                   \
259             BIC.B #SMSDA,&I2CSM_DIR \ 4 l _   P1DIR.2 as input  ==> release SDA high because pull up resistor
260             MOV #3,Y                \ 2     tLOW time complement @ 8 MHz
261 \            MOV #15,Y               \ 2    tLOW time complement @ 16MHz
262 \            MOV #24,Y               \ 2    tLOW time complement @ 24MHz
263             CALL #I2C_PLS           \ _| |_ SCL + BIT SDA input (SDA-->carry)
264             ADDC.B X,X              \ 1 l   C <-- X <--- C
265             SUB #1,W                \ 1 l   count of bits
266         0= UNTIL                    \ 2 l
267         MOV.B X, 0(S)               \ 3 l     store byte in buffer
268         ADD #1,S                    \ 1 l
269 \       ------------------------\
270 \       Compute Ack Or Nack     \ here, SDA is released by slave, SCL is strech low by master
271 \       ------------------------\
272         CMP #1,T                \ 1 l     here, SDA is released by slave = Nack
273         0<> IF                  \ 2
274             BIS.B #SMSDA,&I2CSM_DIR  \ 4 l     send Ack if byte count <> 1
275         THEN                    \ l
276     THEN                        \
277 AGAIN                           \ l
278 ENDASM                          \
279     \
280
281 \ ------------------------------\
282 CODE START                      \ 
283 \ ------------------------------\
284 \ init PORTA (P2:P1) (complement) when reset occurs all I/O are set in input with resistors pullup 
285 BIC.B #SM_BUS,&I2CSM_OUT        \ P1OUT.32 preset SDA + SCL output low
286 BIC.B #SM_BUS,&I2CSM_REN        \ P1REN.32 SDA + SCL pullup/down disable
287 \ ------------------------------\
288 LO2HI
289 ." \ type stop to stop :-)"
290 LIT recurse is WARM             \ insert this starting routine between COLD and WARM...
291 (WARM)                          \ ...and continue with (WARM)
292 ;
293     \
294
295 : STOP                  \ stops multitasking, must to be used before downloading app
296     ['] (WARM) IS WARM  \ remove START app from FORTH init process
297     ECHO COLD           \ reset CPU, interrupt vectors, and start FORTH
298 ;
299     \
300