1 /*
2 * Copyright (c) 2022 OpenLuat & AirM2M
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy of
5 * this software and associated documentation files (the "Software"), to deal in
6 * the Software without restriction, including without limitation the rights to
7 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8 * the Software, and to permit persons to whom the Software is furnished to do so,
9 * subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22 #include "user.h"
23
24 #define IIC_DBG DBG
25 enum
26 {
27 I2C_STATE_FREE,
28 I2C_STATE_INIT_STOP,
29 I2C_STATE_ERROR_STOP,
30 I2C_STATE_WRITE_ADDRESS,
31 I2C_STATE_WRITE_REG,
32 I2C_STATE_WRITE_DATA,
33 I2C_STATE_WRITE_STOP,
34 I2C_STATE_READ_ADDRESS_WR,
35 I2C_STATE_READ_REG_WR,
36 I2C_STATE_READ_ADDRESS_RD,
37 I2C_STATE_READ_DATA_RD,
38 I2C_STATE_READ_STOP,
39 };
40
41 typedef struct
42 {
43 const I2C_TypeDef *RegBase;
44 const int IrqLine;
45 Buffer_Struct DataBuf;
46 CBFuncEx_t Callback;
47 void *pParam;
48 HANDLE Sem;
49 I2C_CommonRegDataStruct *RegQueue;
50 uint32_t TotalQueueNum;
51 uint32_t CurQueuePos;
52 int32_t Result;
53 uint16_t TimeoutMs;
54 uint16_t ChipAddress;
55 uint8_t ChipAddressLen;
56 uint8_t RegAddress;
57 uint8_t State;
58 uint8_t IsBusy;
59 uint8_t IsBlockMode;
60 }I2C_CtrlStruct;
61 static I2C_CtrlStruct prvI2C = {
62 I2C0,
63 I2C0_IRQn,
64 };
65
prvI2C_Done(int32_t Result)66 static void prvI2C_Done(int32_t Result)
67 {
68 prvI2C.State = I2C_STATE_FREE;
69 prvI2C.Result = Result;
70 prvI2C.IsBusy = 0;
71 #ifdef __BUILD_OS__
72 if (prvI2C.IsBlockMode) OS_MutexRelease(prvI2C.Sem);
73 #endif
74 prvI2C.Callback(I2C_ID0, prvI2C.pParam);
75 }
76
prvI2C_DummyCB(void * pData,void * pParam)77 static int32_t prvI2C_DummyCB(void *pData, void *pParam)
78 {
79 prvI2C.IsBusy = 0;
80 }
81
I2C_IrqHandle(int32_t IrqLine,void * pData)82 static void I2C_IrqHandle(int32_t IrqLine, void *pData)
83 {
84 int32_t result = ERROR_NONE;
85 I2C_TypeDef *I2C = prvI2C.RegBase;
86 uint32_t Source = I2C->IC_TX_ABRT_SOURCE;
87 uint32_t State = I2C->IC_RAW_INTR_STAT;
88 uint32_t RegValue = I2C->IC_CLR_INTR;
89
90 if (Source & 0x0000ffff)
91 {
92 result = -ERROR_OPERATION_FAILED;
93 goto I2C_DONE;
94 }
95
96 switch(prvI2C.State)
97 {
98 case I2C_STATE_WRITE_ADDRESS:
99 case I2C_STATE_WRITE_REG:
100 case I2C_STATE_WRITE_DATA:
101 if (State & I2C_IT_TXE)
102 {
103 if (prvI2C.DataBuf.Pos >= prvI2C.DataBuf.MaxLen)
104 {
105 goto I2C_DONE;
106 }
107 else if ((prvI2C.DataBuf.MaxLen - prvI2C.DataBuf.Pos) > 1)
108 {
109 I2C->IC_DATA_CMD = prvI2C.DataBuf.Data[prvI2C.DataBuf.Pos];
110 }
111 else
112 {
113 I2C->IC_DATA_CMD = prvI2C.DataBuf.Data[prvI2C.DataBuf.Pos]|I2C_IC_DATA_CMD_STOP;
114 }
115 prvI2C.DataBuf.Pos++;
116 }
117 break;
118 case I2C_STATE_READ_ADDRESS_WR:
119 if (State & I2C_IT_TXE)
120 {
121 prvI2C.State = I2C_STATE_READ_ADDRESS_RD;
122 if ((prvI2C.DataBuf.MaxLen - prvI2C.DataBuf.Pos) > 1)
123 {
124 I2C->IC_DATA_CMD = I2C_IC_DATA_CMD_CMD;
125 }
126 else
127 {
128 I2C->IC_DATA_CMD = I2C_IC_DATA_CMD_CMD|I2C_IC_DATA_CMD_STOP;
129 }
130 I2C->IC_INTR_MASK = I2C_IC_INTR_MASK_M_RX_FULL|I2C_IC_INTR_MASK_M_STOP_DET;
131 }
132 break;
133 case I2C_STATE_READ_ADDRESS_RD:
134 prvI2C.State = I2C_STATE_READ_DATA_RD;
135 case I2C_STATE_READ_DATA_RD:
136 if (State & I2C_IT_RXF)
137 {
138 prvI2C.DataBuf.Data[prvI2C.DataBuf.Pos] = I2C->IC_DATA_CMD & 0x00ff;
139 prvI2C.DataBuf.Pos++;
140 if (prvI2C.DataBuf.Pos >= prvI2C.DataBuf.MaxLen)
141 {
142 goto I2C_DONE;
143 }
144 else if ((prvI2C.DataBuf.MaxLen - prvI2C.DataBuf.Pos) > 1)
145 {
146 I2C->IC_DATA_CMD = I2C_IC_DATA_CMD_CMD;
147 }
148 else
149 {
150 I2C->IC_DATA_CMD = I2C_IC_DATA_CMD_CMD|I2C_IC_DATA_CMD_STOP;
151 }
152 }
153 break;
154 default:
155 break;
156 }
157 return;
158 I2C_DONE:
159 I2C->IC_INTR_MASK = 0;
160 prvI2C_Done(result);
161 }
162
I2C_IrqHandleRegQueue(int32_t IrqLine,void * pData)163 static void I2C_IrqHandleRegQueue(int32_t IrqLine, void *pData)
164 {
165 int32_t result = ERROR_NONE;
166 I2C_TypeDef *I2C = prvI2C.RegBase;
167 uint32_t Source = I2C->IC_TX_ABRT_SOURCE;
168 uint32_t State = I2C->IC_RAW_INTR_STAT;
169 uint32_t RegValue = I2C->IC_CLR_INTR;
170
171 if (Source & 0x0000ffff)
172 {
173
174 result = -ERROR_OPERATION_FAILED;
175 goto I2C_DONE;
176 }
177
178 if (State & I2C_IT_TXE)
179 {
180 if (prvI2C.DataBuf.Pos >= prvI2C.DataBuf.MaxLen)
181 {
182 prvI2C.CurQueuePos++;
183 if (prvI2C.CurQueuePos >= prvI2C.TotalQueueNum)
184 {
185 goto I2C_DONE;
186 }
187 else
188 {
189 Buffer_StaticInit(&prvI2C.DataBuf, prvI2C.RegQueue[prvI2C.CurQueuePos].Data, 2);
190 I2C->IC_DATA_CMD = prvI2C.DataBuf.Data[0];
191 prvI2C.DataBuf.Pos++;
192 I2C->IC_INTR_MASK = I2C_IC_INTR_MASK_M_TX_EMPTY|I2C_IC_INTR_MASK_M_STOP_DET;
193 }
194
195 }
196 else if ((prvI2C.DataBuf.MaxLen - prvI2C.DataBuf.Pos) > 1)
197 {
198 I2C->IC_DATA_CMD = prvI2C.DataBuf.Data[prvI2C.DataBuf.Pos];
199 }
200 else
201 {
202 I2C->IC_DATA_CMD = prvI2C.DataBuf.Data[prvI2C.DataBuf.Pos]|I2C_IC_DATA_CMD_STOP;
203 }
204 prvI2C.DataBuf.Pos++;
205 }
206 return;
207 I2C_DONE:
208 I2C->IC_INTR_MASK = 0;
209 prvI2C_Done(result);
210 }
211
I2C_GlobalInit(void)212 void I2C_GlobalInit(void)
213 {
214 prvI2C.Callback = prvI2C_DummyCB;
215 ISR_SetHandler(prvI2C.IrqLine, I2C_IrqHandle, NULL);
216 #ifdef __BUILD_OS__
217 prvI2C.Sem = OS_MutexCreate();
218 ISR_SetPriority(prvI2C.IrqLine, configLIBRARY_LOWEST_INTERRUPT_PRIORITY - 1);
219 #else
220 ISR_SetPriority(prvI2C.IrqLine, 7);
221 #endif
222 }
223
I2C_MasterSetup(uint8_t I2CID,uint32_t Speed)224 void I2C_MasterSetup(uint8_t I2CID, uint32_t Speed)
225 {
226 I2C_TypeDef *I2C = prvI2C.RegBase;
227 uint32_t Cnt = ((SystemCoreClock >> 3) / Speed);
228 I2C->IC_ENABLE = 0;
229 while(I2C->IC_ENABLE_STATUS & I2C_IC_ENABLE_STATUS_IC_EN){;}
230 I2C->IC_SDA_HOLD = 5;
231 I2C->IC_SDA_SETUP = Cnt/3;
232 switch(Speed)
233 {
234 case 100000:
235 I2C->IC_SS_SCL_HCNT = Cnt - I2C->IC_FS_SPKLEN;
236 I2C->IC_SS_SCL_LCNT = Cnt;
237 I2C->IC_CON = I2C_IC_CON_RESTART_EN|I2C_IC_CON_SPEED_0|I2C_IC_CON_MASTER_MODE|I2C_IC_CON_SLAVE_DISABLE;
238 break;
239 case 400000:
240 I2C->IC_FS_SCL_HCNT = Cnt - I2C->IC_FS_SPKLEN;
241 I2C->IC_FS_SCL_LCNT = Cnt;
242 I2C->IC_CON = I2C_IC_CON_RESTART_EN|I2C_IC_CON_SPEED_1|I2C_IC_CON_MASTER_MODE|I2C_IC_CON_SLAVE_DISABLE;
243 break;
244 }
245 I2C->IC_ENABLE = 1;
246 I2C->IC_RX_TL = 0;
247 I2C->IC_TX_TL = 0;
248 I2C->IC_INTR_MASK = 0;
249 return;
250 }
251
I2C_Prepare(uint8_t I2CID,uint16_t ChipAddress,uint8_t ChipAddressLen,CBFuncEx_t CB,void * pParam)252 void I2C_Prepare(uint8_t I2CID, uint16_t ChipAddress, uint8_t ChipAddressLen, CBFuncEx_t CB, void *pParam)
253 {
254 I2C_TypeDef *I2C = prvI2C.RegBase;
255 I2C->IC_ENABLE = 0;
256 while(I2C->IC_ENABLE_STATUS & I2C_IC_ENABLE_STATUS_IC_EN){;}
257
258 switch(ChipAddressLen)
259 {
260 case 1:
261 I2C->IC_TAR = ChipAddress & 0x00ff;
262 I2C->IC_SAR = ChipAddress & 0x00ff;
263 break;
264 case 2:
265 I2C->IC_TAR = I2C_IC_TAR_10BITADDR_MASTER | (ChipAddress & I2C_IC_TAR_TAR);
266 I2C->IC_SAR = ChipAddress;
267 break;
268 }
269 I2C->IC_ENABLE = 1;
270 if (CB)
271 {
272 prvI2C.Callback = CB;
273 }
274 else
275 {
276 prvI2C.Callback = prvI2C_DummyCB;
277 }
278 prvI2C.pParam = pParam;
279 }
280
I2C_MasterXfer(uint8_t I2CID,uint8_t Operate,uint8_t RegAddress,uint8_t * Data,uint32_t Len,uint16_t Toms)281 void I2C_MasterXfer(uint8_t I2CID, uint8_t Operate, uint8_t RegAddress, uint8_t *Data, uint32_t Len, uint16_t Toms)
282 {
283 I2C_TypeDef *I2C = prvI2C.RegBase;
284 uint32_t RegValue;
285 I2C->IC_INTR_MASK = 0;
286 ISR_OnOff(prvI2C.IrqLine, 0);
287 if (prvI2C.IsBusy)
288 {
289 I2C->IC_ENABLE |= I2C_IC_ENABLE_ABORT;
290 prvI2C.IsBusy = 0;
291 prvI2C.Result = -ERROR_OPERATION_FAILED;
292 prvI2C.Callback(I2C_ID0, prvI2C.pParam);
293 while(I2C->IC_ENABLE & I2C_IC_ENABLE_ABORT){;}
294 }
295 ISR_SetHandler(prvI2C.IrqLine, I2C_IrqHandle, NULL);
296 prvI2C.IsBusy = 1;
297 if (Toms)
298 {
299 prvI2C.TimeoutMs = Toms;
300 }
301 else
302 {
303 prvI2C.TimeoutMs = 50;
304 }
305 Buffer_StaticInit(&prvI2C.DataBuf, Data, Len);
306 prvI2C.RegQueue = NULL;
307 RegValue = I2C->IC_CLR_INTR;
308 switch(Operate)
309 {
310 case I2C_OP_READ_REG:
311
312 prvI2C.State = I2C_STATE_READ_ADDRESS_WR;
313 I2C->IC_DATA_CMD = I2C_IC_DATA_CMD_RESTART|RegAddress;
314 I2C->IC_INTR_MASK = I2C_IC_INTR_MASK_M_TX_EMPTY|I2C_IC_INTR_MASK_M_STOP_DET;
315 break;
316 case I2C_OP_READ:
317 prvI2C.State = I2C_STATE_READ_ADDRESS_RD;
318 if ((prvI2C.DataBuf.MaxLen - prvI2C.DataBuf.Pos) > 1)
319 {
320 I2C->IC_DATA_CMD = I2C_IC_DATA_CMD_CMD;
321 }
322 else
323 {
324 I2C->IC_DATA_CMD = I2C_IC_DATA_CMD_CMD|I2C_IC_DATA_CMD_STOP;
325 }
326 I2C->IC_INTR_MASK = I2C_IC_INTR_MASK_M_RX_FULL|I2C_IC_INTR_MASK_M_STOP_DET;
327 break;
328 case I2C_OP_WRITE:
329 prvI2C.State = I2C_STATE_WRITE_ADDRESS;
330 if ((prvI2C.DataBuf.MaxLen - prvI2C.DataBuf.Pos) > 1)
331 {
332 I2C->IC_DATA_CMD = prvI2C.DataBuf.Data[0];
333 }
334 else
335 {
336 I2C->IC_DATA_CMD = prvI2C.DataBuf.Data[0]|I2C_IC_DATA_CMD_STOP;
337 }
338 prvI2C.DataBuf.Pos++;
339 I2C->IC_INTR_MASK = I2C_IC_INTR_MASK_M_TX_EMPTY|I2C_IC_INTR_MASK_M_STOP_DET;
340 break;
341 default:
342 prvI2C.IsBusy = 0;
343 prvI2C.Result = -ERROR_PARAM_INVALID;
344 prvI2C.Callback(I2C_ID0, prvI2C.pParam);
345 return;
346 }
347
348 ISR_OnOff(prvI2C.IrqLine, 1);
349 }
350
I2C_MasterWriteRegQueue(uint8_t I2CID,I2C_CommonRegDataStruct * RegQueue,uint32_t TotalNum,uint16_t Toms,uint8_t IsBlock)351 int32_t I2C_MasterWriteRegQueue(uint8_t I2CID, I2C_CommonRegDataStruct *RegQueue, uint32_t TotalNum, uint16_t Toms, uint8_t IsBlock)
352 {
353 I2C_TypeDef *I2C = prvI2C.RegBase;
354 uint32_t RegValue;
355 int32_t Result;
356 I2C->IC_INTR_MASK = 0;
357 ISR_OnOff(prvI2C.IrqLine, 0);
358 if (prvI2C.IsBusy)
359 {
360 I2C->IC_ENABLE |= I2C_IC_ENABLE_ABORT;
361 prvI2C.IsBusy = 0;
362 prvI2C.Result = -ERROR_OPERATION_FAILED;
363 prvI2C.Callback(I2C_ID0, prvI2C.pParam);
364 while(I2C->IC_ENABLE & I2C_IC_ENABLE_ABORT){;}
365 }
366 ISR_SetHandler(prvI2C.IrqLine, I2C_IrqHandleRegQueue, NULL);
367 prvI2C.IsBusy = 1;
368 if (Toms)
369 {
370 prvI2C.TimeoutMs = Toms;
371 }
372 else
373 {
374 prvI2C.TimeoutMs = 50;
375 }
376 prvI2C.RegQueue = RegQueue;
377 prvI2C.TotalQueueNum = TotalNum;
378 prvI2C.CurQueuePos = 0;
379 RegValue = I2C->IC_CLR_INTR;
380 Buffer_StaticInit(&prvI2C.DataBuf, prvI2C.RegQueue[prvI2C.CurQueuePos].Data, 2);
381 I2C->IC_DATA_CMD = prvI2C.DataBuf.Data[0];
382 prvI2C.DataBuf.Pos++;
383 I2C->IC_INTR_MASK = I2C_IC_INTR_MASK_M_TX_EMPTY|I2C_IC_INTR_MASK_M_STOP_DET;
384 ISR_OnOff(prvI2C.IrqLine, 1);
385 if (IsBlock)
386 {
387 while(!I2C_WaitResult(I2CID, &Result)) {;}
388 return Result;
389 }
390 else
391 {
392 return 0;
393 }
394 }
395
396
I2C_WaitResult(uint8_t I2CID,int32_t * Result)397 int I2C_WaitResult(uint8_t I2CID, int32_t *Result)
398 {
399 if (prvI2C.IsBusy) return 0;
400 *Result = prvI2C.Result;
401 return 1;
402 }
403
I2C_BlockWrite(uint8_t I2CID,uint8_t ChipAddress,const uint8_t * Data,uint32_t Len,uint16_t Toms,CBFuncEx_t CB,void * pParam)404 int32_t I2C_BlockWrite(uint8_t I2CID, uint8_t ChipAddress, const uint8_t *Data, uint32_t Len, uint16_t Toms, CBFuncEx_t CB, void *pParam)
405 {
406 int32_t Result;
407 while(!I2C_WaitResult(I2CID, &Result)) {;}
408 prvI2C.IsBlockMode = !OS_CheckInIrq();
409 I2C_Prepare(I2CID, ChipAddress, 1, CB, pParam);
410 I2C_MasterXfer(I2CID, I2C_OP_WRITE, 0, Data, Len, Toms);
411 #ifdef __BUILD_OS__
412 if (!OS_CheckInIrq())
413 {
414 OS_MutexLock(prvI2C.Sem);
415 }
416 #endif
417 while(!I2C_WaitResult(I2CID, &Result)) {;}
418 return Result;
419 }
420
I2C_BlockRead(uint8_t I2CID,uint8_t ChipAddress,uint8_t * Reg,uint8_t * Data,uint32_t Len,uint16_t Toms,CBFuncEx_t CB,void * pParam)421 int32_t I2C_BlockRead(uint8_t I2CID, uint8_t ChipAddress, uint8_t *Reg, uint8_t *Data, uint32_t Len, uint16_t Toms, CBFuncEx_t CB, void *pParam)
422 {
423 int32_t Result;
424 while(!I2C_WaitResult(I2CID, &Result)) {;}
425 prvI2C.IsBlockMode = !OS_CheckInIrq();
426 I2C_Prepare(I2CID, ChipAddress, 1, CB, pParam);
427 if (Reg)
428 {
429 I2C_MasterXfer(I2CID, I2C_OP_READ_REG, *Reg, Data, Len, Toms);
430 }
431 else
432 {
433 I2C_MasterXfer(I2CID, I2C_OP_READ, 0, Data, Len, Toms);
434 }
435 #ifdef __BUILD_OS__
436 if (!OS_CheckInIrq())
437 {
438 OS_MutexLock(prvI2C.Sem);
439 }
440 #endif
441 while(!I2C_WaitResult(I2CID, &Result)) {;}
442 return Result;
443 }
444
I2C_ForceStop(uint8_t I2CID)445 void I2C_ForceStop(uint8_t I2CID)
446 {
447 I2C_TypeDef *I2C = prvI2C.RegBase;
448 IIC_DBG("%d,%x",prvI2C.State, I2C->IC_RAW_INTR_STAT);
449 I2C->IC_ENABLE |= I2C_IC_ENABLE_ABORT;
450 I2C->IC_INTR_MASK = 0;
451 prvI2C_Done(-ERROR_TIMEOUT);
452 while(I2C->IC_ENABLE & I2C_IC_ENABLE_ABORT){;}
453 }
454