1 /*
2  * Copyright 2021 MindMotion Microelectronics Co., Ltd.
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "hal_i2c.h"
9 
10 /* Configure I2C speed to ordinary speed. */
I2C_CalcBandrate(I2C_Type * I2Cx,uint32_t clk,uint32_t bandrate)11 static bool I2C_CalcBandrate(I2C_Type * I2Cx, uint32_t clk, uint32_t bandrate)
12 {
13     /*
14      * SCLH = (xSHR + 12) * I2C_CLK + tSYNC1;
15      * SCLL = (xSLR + 1) * I2C_CLK + tSYNC2;
16      * tSYNC1 & tSYNC2 equal 0 ~ 1 clk.
17      */
18     if ( (clk / 24u) < bandrate ) /* the system clock cannot meet the baud rate requirement. */
19     {
20         return false;
21     }
22     else
23     {
24         uint32_t tmp = clk / bandrate;
25         I2Cx->SSHR = tmp / 2u - 12u;  /* Configure high level count in normal speed. */
26         I2Cx->SSLR = tmp / 2u - 1u;   /* Configure low level count in normal speed. */
27         I2Cx->FSHR = tmp / 2u - 14u;  /* Configure high level count in fast speed. */
28         I2Cx->FSLR = tmp / 2u - 3u;   /* Configure low level count in fast speed. */
29         return true;
30     }
31 }
32 
33 /* Initialize I2C, Initialization failure return false, Initialization success return true. */
I2C_InitMaster(I2C_Type * I2Cx,I2C_Master_Init_Type * init)34 bool I2C_InitMaster(I2C_Type * I2Cx, I2C_Master_Init_Type * init)
35 {
36     I2Cx->ENR &= ~I2C_ENR_ENABLE_MASK;  /* Disable I2C. */
37 
38     if ( !I2C_CalcBandrate(I2Cx, init->ClockFreqHz, init->BaudRate) )  /* The system clock cannot meet the baud rate requirement. */
39     {
40         return false;
41     }
42 
43     I2Cx->CR = I2C_CR_SPEED(1u);
44 
45     /* Setup I2C. */
46     I2Cx->CR &= ~I2C_CR_MASTER10_MASK;  /* Address format. */
47     I2Cx->CR |= I2C_CR_RESTART_MASK     /* Generate restart signal. */
48              | I2C_CR_DISSLAVE_MASK     /* Disable slave module. */
49              | I2C_CR_REPEN_MASK        /* Enable sending restart condition. */
50              | I2C_CR_EMPINT_MASK       /* Control tx_empty interrupt generation. */
51              | I2C_CR_MASTER_MASK;      /* Enable master module. */
52 
53     I2Cx->IMR   = 0u;  /* Close all interrupts. */
54     I2Cx->RXTLR = 0u;  /* Configure the sending receive value. */
55     I2Cx->TXTLR = 0u;  /* Configure the sending threshold value. */
56     return true;       /* Initialize I2C succeeded, return true. */
57 }
58 
59 /* Enable I2C. */
I2C_Enable(I2C_Type * I2Cx,bool enable)60 void I2C_Enable(I2C_Type * I2Cx, bool enable)
61 {
62     if (enable)
63     {
64         I2Cx->ENR |= I2C_ENR_ENABLE_MASK;
65     }
66     else
67     {
68         I2Cx->ENR &= ~I2C_ENR_ENABLE_MASK;
69     }
70 }
71 
72 /* Configuration the target device address. */
I2C_SetTargetAddr(I2C_Type * I2Cx,uint8_t addr)73 void I2C_SetTargetAddr(I2C_Type * I2Cx, uint8_t addr)
74 {
75     I2Cx->TAR = I2C_TAR_ADDR(addr);
76 }
77 
78 /* Get I2C target device address. */
I2C_GetTargetAddr(I2C_Type * I2Cx)79 uint16_t I2C_GetTargetAddr(I2C_Type * I2Cx)
80 {
81     return (I2Cx->TAR & I2C_TAR_ADDR_MASK);
82 }
83 
84 /* Put data to target device. */
I2C_PutData(I2C_Type * I2Cx,uint8_t val)85 void I2C_PutData(I2C_Type * I2Cx, uint8_t val)
86 {
87     I2Cx->DR = I2C_DR_DAT(val);
88 }
89 
90 /* Control read-write bit to prepare to read data. */
I2C_PrepareToGetData(I2C_Type * I2Cx)91 void I2C_PrepareToGetData(I2C_Type * I2Cx)
92 {
93     I2Cx->DR = I2C_DR_CMD_MASK;
94 }
95 
96 /* Get the data received by target device. */
I2C_GetData(I2C_Type * I2Cx)97 uint8_t I2C_GetData(I2C_Type * I2Cx)
98 {
99     return ( (uint8_t)I2Cx->DR );
100 }
101 
102 /* Get the current status flags of the I2C module. */
I2C_GetStatus(I2C_Type * I2Cx)103 uint32_t I2C_GetStatus(I2C_Type * I2Cx)
104 {
105     return I2Cx->SR;
106 }
107 
108 /* Prepare for the stop, when transfer finish. */
I2C_Stop(I2C_Type * I2Cx)109 void I2C_Stop(I2C_Type * I2Cx)
110 {
111     I2Cx->ENR |= I2C_ENR_ABORT_MASK;  /* Prepare for the stop. */
112     I2Cx->TXABRT;  /* Read register to release tx fifo. */
113 }
114 
115 /* Enable I2C interrupt. */
I2C_EnableInterrupts(I2C_Type * I2Cx,uint32_t interrupts,bool enable)116 void I2C_EnableInterrupts(I2C_Type * I2Cx, uint32_t interrupts, bool enable)
117 {
118     if (enable)
119     {
120         I2Cx->IMR |= interrupts;
121     }
122     else
123     {
124         I2Cx->IMR &= ~interrupts;
125     }
126 }
127 
128 /* Get the current enabled interrupts the I2C module. */
I2C_GetEnabledInterrupts(I2C_Type * I2Cx)129 uint32_t I2C_GetEnabledInterrupts(I2C_Type * I2Cx)
130 {
131     return I2Cx->IMR;
132 }
133 
134 /* Get the I2C interrupt status flags of the I2C module. */
I2C_GetInterruptStatus(I2C_Type * I2Cx)135 uint32_t I2C_GetInterruptStatus(I2C_Type * I2Cx)
136 {
137     return (I2Cx->RAWISR & I2Cx->IMR);  /* To ensure that the acquired interrupt is an enabled interrupt. */
138 }
139 
140 /* Clear I2C interrupt status. */
I2C_ClearInterruptStatus(I2C_Type * I2Cx,uint32_t interrupts)141 void I2C_ClearInterruptStatus(I2C_Type * I2Cx, uint32_t interrupts)
142 {
143     if ( (I2C_INT_RX_UNDER & interrupts) != 0u )  /* Clear receive buffer under status. */
144     {
145         I2Cx->RXUNDER;
146     }
147     if ( (I2C_INT_TX_ABORT & interrupts) != 0u )  /* Clear I2C transmit abort status. */
148     {
149         I2Cx->TXABRT;
150     }
151     if ( (I2C_INT_ACTIVE & interrupts) != 0u )    /* Clear I2C interface activation status. */
152     {
153         I2Cx->ACTIV;
154     }
155     if ( (I2C_INT_STOP & interrupts) != 0u )      /* Clear I2C stop condition detection status. */
156     {
157         I2Cx->STOP;
158     }
159     if ( (I2C_INT_START & interrupts) != 0u )     /* Clear I2C start condition detection status. */
160     {
161         I2Cx->START;
162     }
163 }
164 
165 /* Performs polling tx. */
I2C_MasterWriteBlocking(I2C_Type * I2Cx,I2C_MasterXfer_Type * xfer)166 bool I2C_MasterWriteBlocking(I2C_Type * I2Cx, I2C_MasterXfer_Type * xfer)
167 {
168     /* Put register address. */
169     I2C_PutData(I2Cx, xfer->TxBuf[0u]);
170 
171     uint32_t waittime1 = xfer->WaitTimes;
172     /* Wait to tx fifo empty. */
173     while ( (0u == (I2C_GetStatus(I2Cx) & I2C_STATUS_TX_EMPTY) ) && (0u != waittime1) )
174     {
175         waittime1--;
176     }
177     if (0u == waittime1)  /* I2C write register address timeout. */
178     {
179         return false;
180     }
181 
182     uint32_t waittime2 = xfer->WaitTimes;
183     /* Write data to target device. */
184     for (uint32_t i = 1u; i < xfer->TxLen; i++)
185     {
186         I2C_PutData(I2Cx, xfer->TxBuf[i]);
187 
188         while ( ( 0u == (I2C_GetStatus(I2Cx) & I2C_STATUS_TX_EMPTY) ) && (0u != waittime2) )  /* Wait to tx fifo empty. */
189         {
190             waittime2--;
191         }
192         if (0u == waittime2)  /* I2C write timeout. */
193         {
194             return false;
195         }
196     }
197 
198     I2C_Stop(I2Cx);  /* Prepare to stop send data. */
199 
200     uint32_t waittime3 = xfer->WaitTimes;
201     /* Wait to I2C not active, which means stop is taking effect. */
202     while ( (I2C_GetStatus(I2Cx) & I2C_STATUS_ACTIVE) && (0u != waittime3) )
203     {
204         waittime3--;
205     }
206     if (0u == waittime3)  /* The wait operation is timeout. */
207     {
208         return false;
209     }
210 
211     /* Clear fifo and flags. */
212     I2C1->ICR;
213     I2C1->TXABRT;
214     return true;
215 }
216 
217 /* Performs polling rx. */
I2C_MasterReadBlocking(I2C_Type * I2Cx,I2C_MasterXfer_Type * xfer)218 bool I2C_MasterReadBlocking(I2C_Type * I2Cx, I2C_MasterXfer_Type * xfer)
219 {
220     I2C_PutData(I2Cx, xfer->TxBuf[0u]); /* Put device register address. */
221 
222     uint32_t waittime1 = xfer->WaitTimes;
223     while ( ( 0u == (I2C_GetStatus(I2Cx) & I2C_STATUS_TX_EMPTY) ) && (0u != waittime1) )  /* Wait to tx fifo empty. */
224     {
225         waittime1--;
226     }
227     if (0u == waittime1)
228     {
229         return false;
230     }
231 
232     /* read data from target device. */
233     for (uint32_t i = 0u; i < xfer->RxLen; i++)
234     {
235         I2C_PrepareToGetData(I2Cx);  /* Swich read-write bit, prepare to get data. */
236 
237         while ( 0u == (I2C_GetStatus(I2Cx) & I2C_STATUS_RX_NOTEMPTY) )  /* Wait to rx fifo not empty. */
238         {
239             if ( 0u == (I2C_GetStatus(I2Cx) & I2C_STATUS_ACTIVE) )  /* Receive is active. */
240             {
241                 return false;
242             }
243         }
244         xfer->RxBuf[i] = I2C_GetData(I2Cx);
245     }
246 
247     I2C_Stop(I2Cx);  /* Prepare to stop I2C. */
248 
249     uint32_t waittime2 = xfer->WaitTimes;
250     while ( (I2C_GetStatus(I2Cx) & I2C_STATUS_ACTIVE) && (0u != waittime2) )  /* Wait I2C not active, which means stop being effective. */
251     {
252         waittime2--;
253     }
254     if (0u == waittime2)
255     {
256         return false;
257     }
258 
259     /* Clear fifo and flags. */
260     I2C1->ICR;
261     I2C1->TXABRT;
262 
263     return true;
264 }
265 
266 /* I2C master interrupt transfer of the I2C module. */
I2C_MasterXfer(I2C_Type * I2Cx,I2C_MasterXfer_Type * xfer)267 void I2C_MasterXfer(I2C_Type * I2Cx, I2C_MasterXfer_Type * xfer)
268 {
269     I2C_PutData(I2Cx, (uint8_t)xfer->TxBuf[0u]);  /* Put target register address. */
270     I2C_EnableInterrupts(I2Cx, I2C_INT_TX_EMPTY | I2C_INT_TX_ABORT | I2C_INT_STOP, true);   /* Enable tx required interrupt. */
271     xfer->TxIdx = 1u;   /* One data has been sent. */
272     xfer->RxIdx = 0u;
273     xfer->TxLen--;
274 }
275 
276 /* I2C Master handler. */
I2C_MasterXferHandler(I2C_Type * I2Cx,I2C_MasterXfer_Type * xfer,uint32_t interrupts)277 void I2C_MasterXferHandler(I2C_Type * I2Cx, I2C_MasterXfer_Type * xfer, uint32_t interrupts)
278 {
279     if ( 0u != (interrupts & I2C_INT_TX_ABORT) )  /* Early termination of program. */
280     {
281         I2C_EnableInterrupts(I2Cx, I2C_INT_TX_EMPTY | I2C_INT_TX_ABORT | I2C_INT_STOP, false);  /* Clear the interrupt used for tx. */
282         if (NULL != xfer->AbortCallback)
283         {
284             xfer->AbortCallback(xfer);  /* Use abort call back. */
285         }
286     }
287     else if ( 0u != (interrupts & I2C_INT_TX_EMPTY) )  /* Tx fifo is empty, can send data. */
288     {
289         if (I2C_Direction_Rx == xfer->Direction)  /* The current operation is receive, the register address has been sent. */
290         {
291             I2C_EnableInterrupts(I2Cx, I2C_INT_TX_EMPTY | I2C_INT_TX_ABORT, false);  /* Clear tx interrupt. */
292             I2C_EnableInterrupts(I2Cx, I2C_INT_RX_NOTEMPTY, true);  /* Enable receive required interrupt. */
293             if (0u != xfer->RxLen) /* The data to be received is not 0. */
294             {
295                 I2C_PrepareToGetData(I2Cx);  /* Prepare to get data. */
296                 xfer->RxLen--;
297             }
298             else
299             {
300                 I2C_Stop(I2Cx);  /* No more transmition, prepare to stop. */
301             }
302         }
303         else
304         {
305             if (0u == xfer->TxLen)  /* Tx finish. */
306             {
307                 I2C_EnableInterrupts(I2Cx, I2C_INT_TX_EMPTY | I2C_INT_TX_ABORT, false);  /* Clear Tx interrupt. */
308                 I2C_Stop(I2Cx);  /* Prepare to stop. */
309             }
310             else
311             {
312                 xfer->TxLen--;
313                 I2C_PutData(I2Cx, xfer->TxBuf[xfer->TxIdx++]);  /* Tx is not over, continue to put data. */
314             }
315         }
316     }
317     else if ( 0u != (interrupts & I2C_INT_RX_NOTEMPTY) )  /* Receive interrupt. */
318     {
319         if (0u == xfer->RxLen)  /* Receive finish. */
320         {
321             xfer->RxBuf[xfer->RxIdx++] = I2C_GetData(I2Cx); /* Get last data from I2C bus. */
322             I2C_EnableInterrupts(I2Cx, I2C_INT_RX_NOTEMPTY, false);  /* Clear receive interrupt. */
323             I2C_Stop(I2Cx);  /* Prepare to stop. */
324         }
325         else
326         {
327             xfer->RxLen--;  /* Current count length count -1. */
328             xfer->RxBuf[xfer->RxIdx++] = I2C_GetData(I2Cx);  /* Receive is not over, continue to get data. */
329             I2C_PrepareToGetData(I2Cx);  /* Prepare to get data. */
330         }
331     }
332     else if ( 0u != (interrupts & I2C_INT_STOP) )  /* Xfer stop. */
333     {
334         I2C_EnableInterrupts(I2Cx, I2C_INT_STOP, false);  /* Clear stop interrupt. */
335         if ( (0u != xfer->TxLen) || (0u != xfer->RxLen) ) /* The transmission was not completed but terminated. */
336         {
337             if (NULL != xfer->AbortCallback)
338             {
339                 xfer->AbortCallback(xfer);  /* Early termination of program, abort callback. */
340                 I2C1->ICR;
341                 I2C1->TXABRT;  /* Clear FIFO. */
342             }
343         }
344         else
345         {
346             if (NULL != xfer->DoneCallback)
347             {
348                 xfer->DoneCallback(xfer);  /* Transmission finish and stop, xfer done callback. */
349                 I2C1->ICR;
350                 I2C1->TXABRT;  /* Clear FIFO. */
351             }
352         }
353     }
354 }
355 
356 /* EOF. */
357 
358