WXK
2024-09-18 05e2e954bd127de378a9d1dfbb0ed95d725aad63
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
/**************************************************************************//**
 * @file     i2c.c
 * @version  V1.00
 * $Revision: 2 $
 * $Date: 16/02/2216:24 $
 * @brief    Panchip series I2C driver source file
 *
 * @note
 * Copyright (C) 2016 Panchip Technology Corp. All rights reserved.
*****************************************************************************/
#include "PanSeries.h"
#include "pan_i2c.h"
#include "pan_clk.h"
 
/**
  * @brief  Initializes the I2Cx peripheral according to the specified
  *         parameters in the I2C_InitStruct.
  *
  * @note   To use the I2C at 400 KHz (in fast mode), the PCLK1 frequency
  *         (I2C peripheral input clock) must be a multiple of 10 MHz.
  *
  * @param  I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral.
  * @param  I2C_InitStruct: pointer to a I2C_InitTypeDef structure that contains
  *         the configuration information for the specified I2C peripheral.
  * @note   This function should be called before enabling
            the I2C Peripheral.
 
  * @retval None
  */
bool I2C_Init(I2C_T* I2Cx, I2C_InitTypeDef* I2C_InitStruct)
{
    uint32_t tmpreg = 0;
    uint32_t result = 0;
    uint32_t pclk;
 
    /*get system clock frequency*/
    pclk = CLK_GetPeripheralFreq(I2Cx);
    
    /*---------------------------- I2Cx CON Configuration ------------------------*/
    /*Disable I2C */
    tmpreg = I2Cx->CON;
 
    /*restart enable*/
    tmpreg |= (I2C_CON_IC_RESTART_EN);
    
    /* slave address mode*/
    if(I2C_AcknowledgedAddress_7bit == I2C_InitStruct->I2C_AcknowledgedAddress)
    {
        tmpreg &= ~I2C_CON_IC_10BITADDR_SLAVE;
    }
    else//10-bit addr
    {
        tmpreg |= I2C_CON_IC_10BITADDR_SLAVE;
    }
 
    tmpreg &= ~(I2C_CON_SPEED);
    /*---------------------------- I2Cx HCNT/LCNT Configuration ------------------------*/
    /* Configure speed in standard mode */
    result = pclk / I2C_InitStruct->I2C_ClockSpeed;
    if (I2C_InitStruct->I2C_ClockSpeed <= 100000)
    {
        /* Standart mode speed calculate: Tlow/Thigh = 1 */
        result /= 2;
        if(result < I2Cx->FS_SPKLEN +7)
            return false;
        /*HCNT equals to LCNT*/
        I2Cx->SS_SCL_HCNT = result - I2Cx->FS_SPKLEN - 7;
        I2Cx->SS_SCL_LCNT = result - 1;
 
        tmpreg |= I2C_SPEED_STANDARD_MODE;
    }
    /* Configure speed in fast mode */
    else  if (I2C_InitStruct->I2C_ClockSpeed <= 1000000)
    {
        I2C_InitStruct->I2C_DutyCycle = I2C_InitStruct->I2C_DutyCycle % 101;
        if(result* I2C_InitStruct->I2C_DutyCycle / 100 < I2Cx->FS_SPKLEN +7)
            return false;            
        /* Set DUTY bit */
        I2Cx->FS_SCL_HCNT = result * I2C_InitStruct->I2C_DutyCycle / 100 - I2Cx->FS_SPKLEN - 7;
        I2Cx->FS_SCL_LCNT = (result * (100 - I2C_InitStruct->I2C_DutyCycle) / 100) - 1;
        tmpreg |= I2C_SPEED_FAST_MODE;
    }
    /* To use the I2C at 1 MHz (in fast mode plus ) */
    else
    {
        result /= 3;
        if(result < I2Cx->HS_SPKLEN +7)
            return false;
        /* Set DUTY bit */
        I2Cx->HS_SCL_HCNT = result - I2Cx->HS_SPKLEN - 7;
        I2Cx->HS_SCL_LCNT = (result << 1) - 1;
        tmpreg |= I2C_SPEED_HIGH_MODE;
    }
 
    I2Cx->CON = tmpreg;
 
    /*data setup time: 250ns*/
    I2Cx->SDA_SETUP = (pclk) / 4000000 + 1;
 
    /* Set I2Cx Own Address1 and acknowledged address */
    I2Cx->SAR &= ~( I2C_TAR_TAR);
    /* Get 7-bit address from I2C_OwnAddress1*/
    I2Cx->SAR |=  ((I2C_InitStruct ->I2C_OwnAddress1 )) ;
    /* Disable all interrupts to avoid unexpected cases */
    I2C_DisableAllIT(I2Cx);
    /*fifo threshold */
    I2Cx->TX_TL = I2C_TX_TL_4;
    I2Cx->RX_TL = I2C_RX_TL_4;
    return true;
}
 
 
/**
  * @brief  Configure the target address for any master transaction.
  * @param  I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral.
  * @param  Address: specifies the slave 7-bit address which will be transmitted
  * @retval None.
  */
void I2C_Set7bitAddress(I2C_T* I2Cx, uint8_t Address)
{
    uint32_t tmpreg;
     /* Check the parameters */
 
    tmpreg = I2Cx->TAR;
 
    /*7-bits address mode*/
    tmpreg &= ~(I2C_TAR_IC_10BITADDR_MASTER | I2C_TAR_SPECIAL | I2C_TAR_GC_OR_START | I2C_TAR_TAR);
 
    tmpreg |= (Address & 0x07F);
 
    /* Send the address */
    I2Cx->TAR = tmpreg;
 
}
 
/**
  * @brief  Configure the target address for any master transaction.
  * @param  I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral.
  * @param  Address: specifies the slave 10-bit address which will be transmitted
  * @retval None.
  */
void I2C_Set10bitAddress(I2C_T* I2Cx, uint16_t Address)
{
    uint32_t tmpreg;
 
    tmpreg = I2Cx->TAR;
 
    /*7-bits address mode*/
    tmpreg &= ~(I2C_TAR_IC_10BITADDR_MASTER | I2C_TAR_SPECIAL | I2C_TAR_GC_OR_START | I2C_TAR_TAR);
 
    tmpreg |= (I2C_TAR_IC_10BITADDR_MASTER | (Address & 0x03ff));
 
    /* Send the address */
    I2Cx->TAR = tmpreg;
 
}
 
/**
  * @brief  Checks whether the specified I2C flag is set or not.
  * @param  I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral.
  * @param  I2C_FLAG: specifies the flag to check.
  *          This parameter can be one of the following values:
  *          @arg I2C_FLAG_SLV_ACTIVITY
  *          @arg I2C_FLAG_MST_ACTIVITY
  *          @arg I2C_FLAG_RFF
  *          @arg I2C_FLAG_TFE
  *          @arg I2C_FLAG_TFNF
  *          @arg I2C_FLAG_ACTIVITY
  *          @arg I2C_FLAG_MST_ACTIVITY
  * @retval The new state of I2C_FLAG (SET or RESET).
  */
FlagStatus I2C_GetFlagStatus(I2C_T* I2Cx, uint32_t I2C_FLAG)
{
    FlagStatus bitstatus = RESET;
    __IO uint32_t i2cxbase = 0;
 
    /* Get the I2Cx peripheral base address */
    i2cxbase = (uint32_t)I2Cx;
 
    /* Get bit[23:0] of the flag */
    I2C_FLAG &= FLAG_MASK;
    i2cxbase += 0x70;
 
    if(((*(__IO uint32_t *)i2cxbase) & I2C_FLAG) != (uint32_t)RESET)
    {
        /* I2C_FLAG is set */
        bitstatus = SET;
    }
    else
    {
        /* I2C_FLAG is reset */
        bitstatus = RESET;
    }
 
    /* Return the I2C_FLAG status */
    return  bitstatus;
}
 
 
/**
  * @brief  Clears the I2Cx's interrupt pending bits.
  * @param  I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral.
  * @param  I2C_IT: specifies the interrupt pending bit to clear.
  *             @arg I2C_IT_RX_UNDER
  *             @arg I2C_IT_RX_OVER
  *             @arg I2C_IT_RX_FULL
  *             @arg I2C_IT_TX_OVER
  *             @arg I2C_IT_TX_EMPTY
  *             @arg I2C_IT_RD_REQ
  *             @arg I2C_IT_TX_ABRT
  *             @arg I2C_IT_RX_DONE
  *             @arg I2C_IT_ACTIVITY
  *             @arg I2C_IT_STOP_DET
  *             @arg I2C_IT_START_DET
  *             @arg I2C_IT_GEN_CALL
  *             @arg I2C_IT_MST_ON_HOLD
  * @retval None
  */
void I2C_ClearITPendingBit(I2C_T* I2Cx, uint16_t I2C_IT)
{
    uint16_t flagpos = 0;
 
    /* Get the I2C flag position */
    flagpos = (I2C_IT & IT_FLAG_MASK);
 
    /* Clear the selected I2C flag */
    if(flagpos & I2C_IT_RX_UNDER)
        (void)(I2Cx->CLR_RX_UND);
 
    if(flagpos & I2C_IT_RX_OVER)
        (void)(I2Cx->CLR_RX_OVR);
 
    if(flagpos & I2C_IT_TX_OVER)
        (void)(I2Cx->CLR_TX_OVR);
 
    if(flagpos & I2C_IT_RD_REQ)
        (void)(I2Cx->CLR_RD_REQ);
 
    if(flagpos & I2C_IT_TX_ABORT)
        (void)(I2Cx->CLR_TX_ABRT);
 
    if(flagpos & I2C_IT_RX_DONE)
        (void)(I2Cx->CLR_RX_DONE);
 
    if(flagpos & I2C_IT_ACTIVITY)
        (void)(I2Cx->CLR_ACTIVITY);
 
    if(flagpos & I2C_IT_STOP_DET)
        (void)(I2Cx->CLR_STOP_DET);
 
    if(flagpos & I2C_IT_START_DET)
        (void)(I2Cx->CLR_START_DET);
 
    if(flagpos & I2C_IT_GEN_CALL)
        (void)(I2Cx->CLR_GEN_CALL);
 
    if(flagpos & I2C_IT_MST_ON_HOLD)
        (void)(I2Cx->CLR_RESTART_DET);
    
    if(flagpos & I2C_IT_ACTIVITY)
        (void)(I2Cx->CLR_ACTIVITY);
}
 
/**
  * @brief  read data from the I2Cx peripheral.
  * @param  I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral.
  * @param  ReadBuf: cache of stored readings.
  * @param  Size: number of data read from I2C peripheral.
  * @retval none.
  */
void I2C_Read(I2C_T* I2Cx,uint8_t *ReadBuf,uint32_t Size)
{
//    uint32_t timeout = SystemCoreClock / 10000;
 
    while(Size){
        if(I2C_CON_MASTER_MODE & I2Cx->CON){
            while(!I2C_GetFlagStatus(I2Cx,I2C_FLAG_TFNF)){}
            if(Size > 1){
                I2C_SendCmd(I2Cx,I2C_CMD_RD);
            }else{
                I2C_SendCmd(I2Cx,I2C_CMD_RD|I2C_CMD_STOP);
            }
        }
        while(!I2C_GetFlagStatus(I2Cx, I2C_FLAG_RFNE)){
//            if (timeout == 0)
//                break;
//            timeout--;
        }
        *ReadBuf = (uint8_t)I2Cx->DATACMD;
        ReadBuf++;
        Size--;
    }
//    while(I2Cx->STATUS & I2C_STATUS_ACTIVITY);
}
 
/**
  * @brief  write data to the I2Cx peripheral.
  * @param  I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral.
  * @param  WriteBuf: cache of stored writings.
  * @param  Size: number of data read from I2C peripheral.
  * @retval none.
  */
void I2C_Write(I2C_T* I2Cx,uint8_t *WriteBuf,uint32_t Size)
{
    while(Size){
        while(!I2C_GetFlagStatus(I2Cx,I2C_FLAG_TFNF));
        if(Size > 1)
            I2Cx->DATACMD = ((I2C_CMD_WR << 8 ) | (*WriteBuf & 0xFF));
        else{
            if(I2C_CON_MASTER_MODE & I2Cx->CON)
                I2Cx->DATACMD = ((I2C_CMD_STOP << 8 ) | (*WriteBuf & 0xFF));
            else
                I2Cx->DATACMD = ((I2C_CMD_WR << 8 ) | (*WriteBuf & 0xFF));
        }
        WriteBuf++;
        Size--;
    }
//    while(I2Cx->STATUS & I2C_STATUS_ACTIVITY);
}
 
#ifndef __OS_SYSTEM_MODE__
void I2C_OsRead(I2C_T* I2Cx,uint8_t *ReadBuf,uint32_t Size)
{
}
#endif