• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 ASR Microelectronics (Shanghai) Co., Ltd. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <stdio.h>
17 #include <string.h>
18 #include "duet_cm4.h"
19 #include "duet.h"
20 #include "duet_timer.h"
21 #include "duet_pinmux.h"
22 #include "duet_dma.h"
23 #include "duet_i2c.h"
24 
25 // duet_i2c_slv_callback_t g_duet_i2c_slv_callback_handler[DUET_I2C_NUM];
26 duet_timer_dev_t g_duet_timer1;
27 volatile int g_duet_i2c_timeout = 0;
28 duet_i2c_priv_cfg_t duet_i2c_priv_cfg = {
29     .speed_mode = I2C_MODE_STANDARD,
30     .fifo_mode = I2C_MST_FIFO_MODE_ENABLE,
31     .dma_mode = I2C_DMA_ENABLE,
32 };
I2C0_IRQHandler(void)33 void I2C0_IRQHandler(void)
34 {
35     duet_intrpt_enter();
36     if ((I2C0->SR) & I2C_STATUS_TRANS_DONE) {
37         //        printf("I2C0 trans done interrupt\n");
38         I2C0->CR &= (~I2C_CR_SEND_STOP);
39         I2C0->SR |= I2C_STATUS_TRANS_DONE;
40     }
41     if ((I2C0->SR) & I2C_STATUS_SLAVE_ADDR_DET) {
42         printf("I2C0 slave addr det\n");
43         I2C0->SR |= I2C_STATUS_SLAVE_ADDR_DET;
44     }
45     if ((I2C0->SR) & I2C_STATUS_RX_FIFO_FULL) {
46         printf("I2C0 I2C_STATUS_RX_FIFO_FULL\n");
47         I2C0->SR |= I2C_STATUS_RX_FIFO_FULL;
48     }
49 }
50 
I2C1_IRQHandler(void)51 void I2C1_IRQHandler(void)
52 {
53     duet_intrpt_enter();
54 
55     if ((I2C1->SR) & I2C_STATUS_TRANS_DONE) {
56         printf("I2C1 trans done interrupt\n");
57         I2C1->SR |= I2C_STATUS_TRANS_DONE;
58     }
59     if ((I2C1->SR) & I2C_STATUS_SLAVE_ADDR_DET) {
60         printf("I2C1 slave addr det\n");
61         I2C1->SR |= I2C_STATUS_SLAVE_ADDR_DET;
62     }
63     if ((I2C1->SR) & I2C_STATUS_RX_FIFO_HALF_FULL) {
64         printf("I2C1 RX_FIFO_HALF_FULL\n");
65         I2C1->SR |= I2C_STATUS_RX_FIFO_HALF_FULL;
66     }
67 }
68 
i2c_get_flag_status(I2C_TypeDef * I2Cx,uint32_t I2C_flag)69 ITstatus i2c_get_flag_status(I2C_TypeDef *I2Cx, uint32_t I2C_flag)
70 {
71     if (I2C_flag == I2C_STATUS_TX_FIFO_EMPTY) {
72         if (I2Cx->WFIFO_WPTR != I2Cx->WFIFO_RPTR) {
73             return RESET;
74         } else {
75             return SET;
76         }
77     } else if (I2C_flag == I2C_STATUS_TX_FIFO_FULL) {
78         if ((I2Cx->WFIFO_WPTR > I2Cx->WFIFO_RPTR) ? (I2Cx->WFIFO_WPTR - I2Cx->WFIFO_RPTR) :
79              (I2Cx->WFIFO_RPTR - I2Cx->WFIFO_WPTR) != I2C_TX_FIFO_DEPTH) {
80             return RESET;
81         } else {
82             return SET;
83         }
84     } else {
85         if (I2Cx->SR & I2C_flag) {
86             return SET;
87         } else {
88             return RESET;
89         }
90     }
91 }
92 
duet_i2c_reset(I2C_TypeDef * I2Cx)93 int32_t duet_i2c_reset(I2C_TypeDef *I2Cx)
94 {
95     /* check unit busy */
96     int32_t temp = I2C_WAIT_FOREVER;
97     while (i2c_get_flag_status(I2Cx, I2C_STATUS_UNIT_BUSY)) {
98         temp --;
99     }
100 
101     if (temp) {
102         I2Cx->CR &= I2C_UNIT_RESET; // clear rest of CR
103         I2Cx->CR |= I2C_UNIT_RESET;  // set RESET bit
104         I2Cx->SR = 0;
105         I2Cx->CR &= ~I2C_UNIT_RESET; // clear RESET bit
106     } else {
107         return EIO;
108     }
109 
110     return 0;
111 }
112 
duet_i2c_interrupt_config(I2C_TypeDef * I2Cx,uint32_t I2C_interrupt_en,int8_t new_state)113 void duet_i2c_interrupt_config(I2C_TypeDef *I2Cx, uint32_t I2C_interrupt_en, int8_t new_state)
114 {
115     if (new_state == ENABLE) {
116         I2Cx->CR |= I2C_interrupt_en;
117     } else {
118         I2Cx->CR &= ~I2C_interrupt_en;
119     }
120 }
121 
122 /**
123  * Initialises an I2C interface
124  * Prepares an I2C hardware interface for communication as a master or slave
125  *
126  * @param[in]  i2c  the device for which the i2c port should be initialised
127  *
128  * @return  0 : on success, EIO : if an error occurred during initialisation
129  */
duet_i2c_init(duet_i2c_dev_t * i2c)130 int32_t duet_i2c_init(duet_i2c_dev_t *i2c)
131 {
132     I2C_TypeDef *I2Cx;
133     uint32_t reg_val;
134 
135     if (NULL == i2c) {
136         return EIO;
137     }
138     if (I2C_DEVICE0 == i2c->port) { // I2C_DEVICE0
139         I2Cx = I2C0;
140     } else if (I2C_DEVICE1 == i2c->port) { // I2C_DEVICE1
141         I2Cx = I2C1;
142     } else {
143         return EIO;
144     }
145 
146     // pinmux config
147     if (I2C_DEVICE0 == i2c->port) { // I2C_DEVICE0, set PAD2,3 for i2c0 func 4.
148 #if I2C0_PAD_GROUP0_ENABLE
149         duet_pinmux_config(PAD2, PF_I2C0);
150         duet_pinmux_config(PAD3, PF_I2C0);
151 #endif
152 #if I2C0_PAD_GROUP1_ENABLE
153         duet_pinmux_config(PAD20, PF_I2C0);
154         duet_pinmux_config(PAD21, PF_I2C0);
155 #endif
156     } else {
157 #if I2C1_PAD_GROUP0_ENABLE
158         duet_pinmux_config(PAD8, PF_I2C1);
159         duet_pinmux_config(PAD9, PF_I2C1);
160 #endif
161 #if I2C1_PAD_GROUP1_ENABLE
162         duet_pinmux_config(PAD22, PF_I2C1);
163         duet_pinmux_config(PAD23, PF_I2C1);
164 #endif
165     }
166 
167     // I2C clock enable
168     if (I2C_DEVICE0 == i2c->port) {
169         reg_val = REG_RD(PERI_CLK_EN_REG1);
170         REG_WR(PERI_CLK_EN_REG1, (reg_val | (I2C0_BUS_CLOCK_ENABLE | I2C0_PERI_CLOCK_ENABLE)));
171     } else {
172         reg_val = REG_RD(PERI_CLK_EN_REG1);
173         REG_WR(PERI_CLK_EN_REG1, (reg_val | (I2C1_BUS_CLOCK_ENABLE | I2C1_PERI_CLOCK_ENABLE)));
174     }
175 
176     // I2C IRQ enable
177     if (I2C_DEVICE0 == i2c->port) {
178         reg_val = REG_RD(DUTE_IRQ_EN_REG);
179         REG_WR(DUTE_IRQ_EN_REG, (reg_val | I2C0_IRQ_ENABLE));
180     } else {
181         reg_val = REG_RD(DUTE_IRQ_EN_REG);
182         REG_WR(DUTE_IRQ_EN_REG, (reg_val | I2C1_IRQ_ENABLE));
183     }
184 
185     /* reset unit */
186     duet_i2c_reset(I2Cx);
187 
188     switch (i2c->config.freq) {
189         case I2C_STANDARD_SPEED:
190             duet_i2c_priv_cfg.speed_mode = I2C_MODE_STANDARD;
191             break;
192         case I2C_FAST_SPEED:
193             duet_i2c_priv_cfg.speed_mode = I2C_MODE_FAST;
194             break;
195         case I2C_HIGH_SPEED:
196             duet_i2c_priv_cfg.speed_mode = I2C_MODE_HIGH_SPEED_0;
197             break;
198         default:
199             break;
200     }
201 
202     if (i2c->config.mode == I2C_MASTER) {
203         I2Cx->SAR = i2c->config.dev_addr; // set unit address as slave
204 
205         I2Cx->CR &= ~I2C_MODE_SET_MASK; // reset speed mode to 0
206         I2Cx->CR |= (duet_i2c_priv_cfg.speed_mode << I2C_MODE_SET_POS); // set speed mode
207         I2Cx->LCR = 0;
208         I2Cx->LCR = (((I2C_CLK / I2C_STANDARD_SPEED - 8) / 2) | (((I2C_CLK / I2C_FAST_SPEED - 8) / 2 - 1) << 9) | (((
209                          I2C_CLK / I2C_HIGH_SPEED - 9) / 2) << 18) | (((I2C_CLK / I2C_HIGH_SPEED - 9) / 2) << 27)); // set divider
210         // set wait count value to adjust clock for standart and fast mode
211         I2Cx->WCR = (((I2C_CLK / I2C_FAST_SPEED - 8) / 2 - 1) / 3);
212         I2Cx->CR |= duet_i2c_priv_cfg.fifo_mode;  // set FIFO mode
213 
214         I2Cx->CR |= I2C_UNIT_ENABLE | I2C_SCL_ENABLE; // scl driving enable & unit enable
215 
216         duet_i2c_interrupt_config(I2Cx, I2C_INTERRUPT_SLAVE_ADDR_DET_EN | I2C_INTERRUPT_TRANS_DONE_EN |
217                                   I2C_INTERRUPT_RX_FIFO_FULL_EN | I2C_INTERRUPT_BUS_ERROR_DET_EN \
218                                   | I2C_INTERRUPT_MASTER_STOP_DET_EN, ENABLE); // master
219     } else {
220         /* i2c as slave */
221         I2Cx->SAR = i2c->config.dev_addr; // set unit address as slave
222         I2Cx->CR &= ~I2C_MODE_SET_MASK; // reset speed mode to 0
223         I2Cx->CR |= (duet_i2c_priv_cfg.speed_mode << I2C_MODE_SET_POS); // set speed mode
224         //            I2Cx->CR |= pI2C_InitStrcut->i2c_mst_fifo_mode;  // FIFO mode is not for slave mode, so this has no effect
225         I2Cx->CR |= I2C_INTERRUPT_SLAVE_ADDR_DET_EN | I2C_INTERRUPT_RX_FIFO_FULL_EN | I2C_INTERRUPT_RX_BUFER_FULL_EN |
226                     I2C_INTERRUPT_SLAVE_STOP_DET_EN | I2C_INTERRUPT_TRANS_DONE_EN | I2C_INTERRUPT_TX_BUFFER_EMPTY_EN; // master read
227         I2Cx->CR |= I2C_UNIT_ENABLE; // unit enable
228 
229         duet_i2c_interrupt_config(I2Cx, I2C_INTERRUPT_SLAVE_ADDR_DET_EN | I2C_INTERRUPT_RX_FIFO_FULL_EN |
230                                   I2C_INTERRUPT_RX_BUFER_FULL_EN | I2C_INTERRUPT_SLAVE_STOP_DET_EN \
231                                   | I2C_INTERRUPT_TRANS_DONE_EN | I2C_INTERRUPT_TX_BUFFER_EMPTY_EN, ENABLE); // slave
232     }
233     if (duet_i2c_priv_cfg.dma_mode == I2C_DMA_ENABLE) {
234         I2Cx->CR |= I2C_DMA_ENABLE;
235     }
236 
237     // I2C interrupt enable should be put before I2C enable
238     if (I2C_DEVICE0 == i2c->port) { // I2C_DEVICE0
239         NVIC_EnableIRQ(I2C0_IRQn); // enable I2C0 interrupt
240     } else {
241         NVIC_EnableIRQ(I2C1_IRQn); // enable I2C1 interrupt
242     }
243 
244     /* check the bus busy after unit enable */
245     if (i2c_get_flag_status(I2Cx, I2C_STATUS_BUS_BUSY)) {
246         return EIO;
247     } else {
248         return 0;
249     }
250 }
251 
duet_timer1_irq_handler(void * arg)252 void duet_timer1_irq_handler(void *arg)
253 {
254     g_duet_i2c_timeout = 1;
255 }
256 
duet_i2c_master_send(duet_i2c_dev_t * i2c,uint16_t dev_addr,const uint8_t * data,uint16_t size,uint32_t timeout)257 int32_t duet_i2c_master_send(duet_i2c_dev_t *i2c, uint16_t dev_addr, const uint8_t *data, uint16_t size,
258                              uint32_t timeout)
259 {
260     int32_t ret = 0;
261     I2C_TypeDef *I2Cx;
262     uint16_t temp;
263 
264     if (NULL == i2c) {
265         return -EI2CNUMERR;
266     }
267 
268     if (I2C_DEVICE0 == i2c->port) { // I2C_DEVICE0
269         I2Cx = I2C0;
270     } else if (I2C_DEVICE1 == i2c->port) { // I2C_DEVICE1
271         I2Cx = I2C1;
272     } else {
273         return -EI2CNUMERR;
274     }
275 
276     if (0xFFFFFFFF != timeout) {
277         g_duet_timer1.port = DUET_TIMER1_INDEX;
278         g_duet_timer1.config.reload_mode = TIMER_RELOAD_MANU;
279         g_duet_timer1.config.cb = duet_timer1_irq_handler;
280         g_duet_timer1.config.arg = NULL;
281 
282         g_duet_timer1.config.period = timeout * 1000; // us
283 
284         duet_timer_init(&g_duet_timer1);
285         g_duet_i2c_timeout = 0;
286         duet_timer_start(&g_duet_timer1);
287     }
288     // set TXBEGIN bit before starting another transfer
289     I2Cx->CR |= I2C_TRANS_BEGIN;
290 
291     // send slave address first
292     I2Cx->WFIFO = (((uint8_t)(dev_addr & 0x00FF)) << 1) | I2C_WRITE | I2C_SEND_START | I2C_TB;
293 
294     // send write cmd
295     while (1) {
296         //wait till tx fifo is empty to avoid overflowing tx fifo
297         while (!i2c_get_flag_status(I2Cx, I2C_STATUS_TX_FIFO_EMPTY)) {
298             if (g_duet_i2c_timeout) {
299                 g_duet_i2c_timeout = 0;
300                 ret = -ETIMEOUT;
301                 goto EXIT;
302             }
303         }
304 
305         if (size > I2C_TX_FIFO_DEPTH) {
306             // send 8 bytes
307             for (temp = 0; temp < I2C_TX_FIFO_DEPTH; temp++) {
308                 if (g_duet_i2c_timeout) {
309                     g_duet_i2c_timeout = 0;
310                     ret = -ETIMEOUT;
311                     goto EXIT;
312                 }
313 
314                 if (i2c_get_flag_status(I2Cx, I2C_STATUS_BUS_ERROR_DET)) {
315                     ret = -EBUSERR; // bus error
316                     goto EXIT;
317                 } else {
318                     I2Cx->WFIFO = (*data++) | I2C_TB;
319                 }
320             }
321             size -= I2C_TX_FIFO_DEPTH;
322         } else {
323             // send remaining bytes
324             for (temp = 0; temp < size; temp++) {
325                 if (g_duet_i2c_timeout) {
326                     g_duet_i2c_timeout = 0;
327                     ret = -ETIMEOUT;
328                     goto EXIT;
329                 }
330 
331                 if (i2c_get_flag_status(I2Cx, I2C_STATUS_BUS_ERROR_DET)) {
332                     ret =  -EBUSERR; // bus error
333                     goto EXIT;
334                 } else {
335                     if (temp == size - 1) {
336                         I2Cx->WFIFO = (*data) | I2C_SEND_STOP | I2C_TB;
337                         ret = I2C_SUCCESS; // success
338                         goto EXIT;
339                     } else {
340                         I2Cx->WFIFO = (*data++) | I2C_TB;
341                     }
342                 }
343             }
344         }
345     }
346     ret = -ENOENT;
347 
348 EXIT:
349     if (0xFFFFFFFF != timeout) {
350         duet_timer_finalize(&g_duet_timer1);
351     }
352     return ret;
353 }
354 
duet_i2c_master_recv(duet_i2c_dev_t * i2c,uint16_t dev_addr,uint8_t * data,uint16_t size,uint32_t timeout)355 int32_t duet_i2c_master_recv(duet_i2c_dev_t *i2c, uint16_t dev_addr, uint8_t *data, uint16_t size, uint32_t timeout)
356 {
357     I2C_TypeDef *I2Cx;
358     uint16_t i = 0;
359     int32_t ret;
360 
361     if (NULL == i2c) {
362         return -EI2CNUMERR;
363     }
364 
365     if (I2C_DEVICE0 == i2c->port) { // I2C_DEVICE0
366         I2Cx = I2C0;
367     } else if (I2C_DEVICE1 == i2c->port) { // I2C_DEVICE1
368         I2Cx = I2C1;
369     } else {
370         return -EI2CNUMERR;
371     }
372 
373     if (0xFFFFFFFF != timeout) {
374         g_duet_timer1.port = DUET_TIMER1_INDEX;
375         g_duet_timer1.config.reload_mode = TIMER_RELOAD_MANU;
376         g_duet_timer1.config.cb = duet_timer1_irq_handler;
377         g_duet_timer1.config.arg = NULL;
378 
379         g_duet_timer1.config.period = timeout * 1000; // us
380 
381         duet_timer_init(&g_duet_timer1);
382         g_duet_i2c_timeout = 0;
383         duet_timer_start(&g_duet_timer1);
384     }
385 
386     // set TXBEGIN bit before starting another transfer
387     I2Cx->CR |= I2C_TRANS_BEGIN;
388 
389     // send slave address first
390     I2Cx->WFIFO = (dev_addr << 1) | I2C_READ | I2C_SEND_START | I2C_TB;
391     while (i < size) {
392         if (g_duet_i2c_timeout) {
393             g_duet_i2c_timeout = 0;
394             ret = -ETIMEOUT;
395             goto EXIT;
396         }
397         while (!i2c_get_flag_status(I2Cx, I2C_STATUS_TX_FIFO_EMPTY)) {
398             if (g_duet_i2c_timeout) {
399                 g_duet_i2c_timeout = 0;
400                 ret = -ETIMEOUT;
401                 goto EXIT;
402             }
403         }
404         if ((size - 1) == i) {
405             I2Cx->WFIFO = I2C_SEND_STOP | I2C_SEND_NACK | I2C_TB;
406         } else {
407             I2Cx->WFIFO = I2C_TB;
408         }
409 
410         while (!(I2Cx->RFIFO_STATUS & 0xF0)) {
411             if (g_duet_i2c_timeout) {
412                 g_duet_i2c_timeout = 0;
413                 ret = -ETIMEOUT;
414                 goto EXIT;
415             }
416         }
417         *(data + i) = I2Cx->RFIFO & 0xFF;
418         i++;
419     }
420 
421 EXIT:
422     if (0xFFFFFFFF != timeout) {
423         duet_timer_finalize(&g_duet_timer1);
424     }
425     return ret;
426 }
427 
duet_i2c_master_repeated_write_read(I2C_TypeDef * I2Cx,uint8_t slave_addr,const uint8_t * pwdata,uint8_t * rdata,uint32_t wlen,uint32_t rlen)428 int8_t duet_i2c_master_repeated_write_read(I2C_TypeDef *I2Cx, uint8_t slave_addr, const uint8_t *pwdata, uint8_t *rdata,
429         uint32_t wlen, uint32_t rlen)
430 {
431     /**** master write ****/
432 
433     uint8_t temp;
434     uint8_t i = 0;
435 
436     // set TXBEGIN bit before starting another transfer
437     I2Cx->CR |= I2C_TRANS_BEGIN;
438 
439     // send slave address first
440     I2Cx->WFIFO = (slave_addr << 1) | I2C_WRITE | I2C_SEND_START | I2C_TB;
441 
442     // send write cmd
443     while (1) {
444         //wait till tx fifo is empty to avoid overflowing tx fifo
445         while (!i2c_get_flag_status(I2Cx, I2C_STATUS_TX_FIFO_EMPTY));
446 
447         if (wlen > I2C_TX_FIFO_DEPTH) {
448             // send 8 bytes
449             for (temp = 0; temp < I2C_TX_FIFO_DEPTH; temp++) {
450                 if (i2c_get_flag_status(I2Cx, I2C_STATUS_BUS_ERROR_DET)) {
451                     return EIO;    // bus error
452                 } else {
453                     I2Cx->WFIFO = (*pwdata++) | I2C_TB;
454                 }
455             }
456             wlen -= I2C_TX_FIFO_DEPTH;
457         } else {
458             // send remaining bytes
459             for (temp = 0; temp < wlen; temp++) {
460                 if (i2c_get_flag_status(I2Cx, I2C_STATUS_BUS_ERROR_DET)) {
461                     return EIO;    // bus error
462                 } else {
463                     if (temp == wlen - 1) {
464                         I2Cx->WFIFO = (*pwdata) | I2C_TB;   // no need to send STOP for repeated read
465                         break; // write completed
466                     } else {
467                         I2Cx->WFIFO = (*pwdata++) | I2C_TB;
468                     }
469                 }
470             }
471             break;
472         }
473     }
474 
475     /**** master read ****/
476     while (!i2c_get_flag_status(I2Cx, I2C_STATUS_TX_FIFO_EMPTY));
477 
478     // send slave address first
479     I2Cx->WFIFO = (slave_addr << 1) | I2C_READ | I2C_SEND_START | I2C_TB;
480     while (i < rlen) {
481         while (!i2c_get_flag_status(I2Cx, I2C_STATUS_TX_FIFO_EMPTY));
482         if ((rlen - 1) == i) {
483             I2Cx->WFIFO = I2C_SEND_STOP | I2C_SEND_NACK | I2C_TB;
484             while (!i2c_get_flag_status(I2Cx, I2C_STATUS_TX_FIFO_EMPTY));
485         } else {
486             I2Cx->WFIFO = I2C_TB;
487         }
488 
489         while (!(I2Cx->RFIFO_STATUS & 0xF0));
490         *(rdata + i) = I2Cx->RFIFO & 0xFF;
491         i++;
492     }
493 
494     return 0;
495 }
496 
497 /* program memory of a slave device  via I2C */
duet_i2c_mem_write(duet_i2c_dev_t * i2c,uint16_t dev_addr,uint16_t mem_addr,uint16_t mem_addr_size,const uint8_t * data,uint16_t len,uint32_t timeout)498 int32_t duet_i2c_mem_write(duet_i2c_dev_t *i2c, uint16_t dev_addr, uint16_t mem_addr, \
499                            uint16_t mem_addr_size, const uint8_t *data, uint16_t len, \
500                            uint32_t timeout)
501 {
502     I2C_TypeDef *I2Cx;
503     uint8_t temp;
504     int8_t i;
505     int32_t ret = 0;
506 
507     if (NULL == i2c) {
508         ret = -EI2CNUMERR;
509         goto EXIT;
510     }
511 
512     if (I2C_DEVICE0 == i2c->port) { // I2C_DEVICE0
513         I2Cx = I2C0;
514     } else if (I2C_DEVICE1 == i2c->port) { // I2C_DEVICE1
515         I2Cx = I2C1;
516     } else {
517         ret = -EI2CNUMERR;
518         goto EXIT;
519     }
520 
521     if (0xFFFFFFFF != timeout) {
522         g_duet_timer1.port = DUET_TIMER1_INDEX;
523         g_duet_timer1.config.reload_mode = TIMER_RELOAD_MANU;
524         g_duet_timer1.config.cb = duet_timer1_irq_handler;
525         g_duet_timer1.config.arg = NULL;
526 
527         g_duet_timer1.config.period = timeout * 1000; // us
528 
529         duet_timer_init(&g_duet_timer1);
530         g_duet_i2c_timeout = 0;
531         duet_timer_start(&g_duet_timer1);
532     }
533 
534     // set TXBEGIN bit before starting another transfer
535     I2Cx->CR |= I2C_TRANS_BEGIN;
536 
537     // send slave address first
538     i2c_write_byte(I2Cx, ((uint8_t)dev_addr << 1) | I2C_WRITE | I2C_SEND_START | I2C_TB);
539 
540     // send memory address
541     for (i = 0; i < mem_addr_size; i++) {
542         i2c_write_byte(I2Cx, ((mem_addr >> (8 * i)) & 0xff) | I2C_WRITE | I2C_TB);
543     }
544 
545     // send write cmd
546     while (1) {
547         if (g_duet_i2c_timeout) {
548             g_duet_i2c_timeout = 0;
549             ret = -ETIMEOUT;
550             goto EXIT;
551         }
552         //wait till tx fifo is empty to avoid overflowing tx fifo
553         while (!i2c_get_flag_status(I2Cx, I2C_STATUS_TX_FIFO_EMPTY)) {
554             if (g_duet_i2c_timeout) {
555                 g_duet_i2c_timeout = 0;
556                 ret = -ETIMEOUT;
557                 goto EXIT;
558             }
559         }
560 
561         if (len > I2C_TX_FIFO_DEPTH) {
562             // send 8 bytes
563             for (temp = 0; temp < I2C_TX_FIFO_DEPTH; temp++) {
564                 if (g_duet_i2c_timeout) {
565                     g_duet_i2c_timeout = 0;
566                     ret = -ETIMEOUT;
567                     goto EXIT;
568                 }
569 
570                 if (i2c_get_flag_status(I2Cx, I2C_STATUS_BUS_ERROR_DET)) {
571                     ret = -EBUSERR; // bus error
572                     goto EXIT;
573                 } else {
574                     i2c_write_byte(I2Cx, (*data++) | I2C_TB);
575                 }
576             }
577             len -= I2C_TX_FIFO_DEPTH;
578         } else {
579             // send remaining bytes
580             for (temp = 0; temp < len; temp++) {
581                 if (g_duet_i2c_timeout) {
582                     g_duet_i2c_timeout = 0;
583                     ret = -ETIMEOUT;
584                     goto EXIT;
585                 }
586 
587                 if (i2c_get_flag_status(I2Cx, I2C_STATUS_BUS_ERROR_DET)) {
588                     ret = -EBUSERR; // bus error
589                     goto EXIT;
590                 } else {
591                     if (temp == len - 1) {
592                         I2Cx->WFIFO = (*data) | I2C_SEND_STOP | I2C_TB;
593                         ret = I2C_SUCCESS; // success
594                         goto EXIT;
595                     } else {
596                         i2c_write_byte(I2Cx, (*data++) | I2C_TB);
597                     }
598                 }
599             }
600         }
601     }
602 
603 EXIT:
604     if (0xFFFFFFFF != timeout) {
605         duet_timer_finalize(&g_duet_timer1);
606     }
607     return ret;
608 }
609 
duet_i2c_mem_read(duet_i2c_dev_t * i2c,uint16_t dev_addr,uint16_t mem_addr,uint16_t mem_addr_size,uint8_t * data,uint16_t size,uint32_t timeout)610 int32_t duet_i2c_mem_read(duet_i2c_dev_t *i2c, uint16_t dev_addr, uint16_t mem_addr,
611                           uint16_t mem_addr_size, uint8_t *data, uint16_t size,
612                           uint32_t timeout)
613 {
614     I2C_TypeDef *I2Cx;
615     int16_t i;
616     int32_t ret = 0;
617 
618     if (NULL == i2c) {
619         return -EI2CNUMERR;
620     }
621 
622     if (I2C_DEVICE0 == i2c->port) { // I2C_DEVICE0
623         I2Cx = I2C0;
624     } else if (I2C_DEVICE1 == i2c->port) { // I2C_DEVICE1
625         I2Cx = I2C1;
626     } else {
627         return -EI2CNUMERR;
628     }
629 
630     if (0xFFFFFFFF != timeout) {
631         g_duet_timer1.port = DUET_TIMER1_INDEX;
632         g_duet_timer1.config.reload_mode = TIMER_RELOAD_MANU;
633         g_duet_timer1.config.cb = duet_timer1_irq_handler;
634         g_duet_timer1.config.arg = NULL;
635 
636         g_duet_timer1.config.period = timeout * 1000; // us
637 
638         duet_timer_init(&g_duet_timer1);
639         g_duet_i2c_timeout = 0;
640         duet_timer_start(&g_duet_timer1);
641     }
642 
643     // set TXBEGIN bit before starting another transfer
644     I2Cx->CR |= I2C_TRANS_BEGIN;
645 
646     // send slave address first
647     i2c_write_byte(I2Cx, ((uint8_t)dev_addr << 1) | I2C_WRITE | I2C_SEND_START | I2C_TB);
648 
649     // send memory address
650     for (i = 0; i < mem_addr_size; i++) {
651         if (g_duet_i2c_timeout) {
652             g_duet_i2c_timeout = 0;
653             ret = -ETIMEOUT;
654             goto EXIT;
655         }
656         i2c_write_byte(I2Cx, ((mem_addr >> (8 * i)) & 0xff) | I2C_WRITE | I2C_TB);
657     }
658     /**** master read ****/
659     while (!i2c_get_flag_status(I2Cx, I2C_STATUS_TX_FIFO_EMPTY));
660 
661     // send slave address first
662     i2c_write_byte(I2Cx, (dev_addr << 1) | I2C_READ | I2C_SEND_START | I2C_TB);
663 
664     i = 0;
665     // send read cmd
666     while (i < size) {
667         //wait till tx fifo is empty to avoid overflowing tx fifo
668         while (!i2c_get_flag_status(I2Cx, I2C_STATUS_TX_FIFO_EMPTY));
669 
670         if (g_duet_i2c_timeout) {
671             g_duet_i2c_timeout = 0;
672             ret = -ETIMEOUT;
673             goto EXIT;
674         }
675 
676         if (i2c_get_flag_status(I2Cx, I2C_STATUS_BUS_ERROR_DET)) {
677             ret = -EBUSERR; // bus error
678             goto EXIT;
679         } else {
680             if (i == size - 1) {
681                 i2c_write_byte(I2Cx, I2C_SEND_STOP | I2C_SEND_NACK | I2C_TB);
682                 while (!i2c_get_flag_status(I2Cx, I2C_STATUS_TX_FIFO_EMPTY));
683                 ret = I2C_SUCCESS;
684                 while (!(I2Cx->RFIFO_STATUS & 0xF0)) {
685                     if (g_duet_i2c_timeout) {
686                         g_duet_i2c_timeout = 0;
687                         ret = -ETIMEOUT;
688                         goto EXIT;
689                     }
690                 }
691                 *(data + i) = I2Cx->RFIFO & 0xFF;
692                 goto EXIT;
693             } else {
694                 i2c_write_byte(I2Cx, I2C_TB);
695             }
696         }
697 
698         while (!(I2Cx->RFIFO_STATUS & 0xF0)) {
699             if (g_duet_i2c_timeout) {
700                 g_duet_i2c_timeout = 0;
701                 ret = -ETIMEOUT;
702                 goto EXIT;
703             }
704         }
705         *(data + i) = I2Cx->RFIFO & 0xFF;
706         i++;
707 
708     }
709 EXIT:
710     if (0xFFFFFFFF != timeout) {
711         duet_timer_finalize(&g_duet_timer1);
712     }
713     return ret;
714 }
715 
716 /**
717  * Deinitialises an I2C device
718  *
719  * @param[in]  i2c  the i2c device
720  *
721  * @return  0 : on success, EIO : if an error occurred during deinitialisation
722  */
duet_i2c_finalize(duet_i2c_dev_t * i2c)723 int32_t duet_i2c_finalize(duet_i2c_dev_t *i2c)
724 {
725     I2C_TypeDef *I2Cx;
726     uint32_t reg_val;
727 
728     if (NULL == i2c) {
729         return EIO;
730     }
731     if (I2C_DEVICE0 == i2c->port) { // I2C_DEVICE0
732         I2Cx = I2C0;
733     } else if (I2C_DEVICE1 == i2c->port) { // I2C_DEVICE1
734         I2Cx = I2C1;
735     } else {
736         return EIO;
737     }
738 
739     I2Cx = I2Cx;
740     // disable i2c cm4 irq
741     if (I2C_DEVICE0 == i2c->port) { // I2C_DEVICE0
742         NVIC_DisableIRQ(I2C0_IRQn); // disable I2C0 interrupt
743     } else {
744         NVIC_DisableIRQ(I2C1_IRQn); // disable I2C1 interrupt
745     }
746 
747     // I2C IRQ disable
748     if (I2C_DEVICE0 == i2c->port) {
749         reg_val = REG_RD(DUTE_IRQ_DIS_REG);
750         REG_WR(DUTE_IRQ_DIS_REG, (reg_val | I2C0_IRQ_DISABLE));
751     } else {
752         reg_val = REG_RD(DUTE_IRQ_DIS_REG);
753         REG_WR(DUTE_IRQ_DIS_REG, (reg_val | I2C1_IRQ_DISABLE));
754     }
755 
756     // i2c clk disable
757     if (I2C_DEVICE0 == i2c->port) { // I2C_DEVICE0
758         // I2C0 clock disable
759         reg_val = REG_RD(PERI_CLK_DIS_REG1);
760         REG_WR(PERI_CLK_DIS_REG1, (reg_val & ((I2C0_BUS_CLOCK_DISABLE | I2C0_PERI_CLOCK_DISABLE))));
761     } else { // I2C_DEVICE1
762         // I2C1 clock disable
763         reg_val = REG_RD(PERI_CLK_DIS_REG1);
764         REG_WR(PERI_CLK_DIS_REG1, (reg_val & ((I2C1_BUS_CLOCK_DISABLE | I2C1_PERI_CLOCK_DISABLE))));
765     }
766     // callback function pointer clear
767     // g_duet_i2c_slv_callback_handler[i2c->port].tx_func = NULL;
768     // g_duet_i2c_slv_callback_handler[i2c->port].rx_func = NULL;
769 
770     return 0;
771 }
772 
duet_i2c_master_dma_send(uint8_t iic_idx,uint32_t * data,uint16_t len)773 void duet_i2c_master_dma_send(uint8_t iic_idx, uint32_t *data, uint16_t len)
774 {
775     uint8_t dma_chan = 0;
776     I2C_TypeDef *I2Cx = 0;
777     if (iic_idx == 0) {
778         dma_chan = 12;
779         I2Cx = I2C0;
780     }
781     // malloc for channel descriptor
782     Chan_Cfg_TypeDef *pChan_Cfg_Align = duet_dma_ctrl_block_init();
783     Chan_Ctl_Data_TypeDef ch_ctl_data;
784     Chan_Cfg_TypeDef ch_cfg;
785 
786     ch_ctl_data.cycle_ctl = DMA_OP_MODE_BASIC; // DMA_OP_MODE_AUTO_REQ;
787     ch_ctl_data.n_minus_1 = len - 1;
788     ch_ctl_data.R_pow = 0;
789     ch_ctl_data.src_inc = DMA_SRC_ADDR_INC_WORD;
790     ch_ctl_data.dst_inc = DMA_DST_ADDR_INC_FIX;
791     ch_ctl_data.src_size = DMA_SRC_DATA_WIDTH_WORD;
792     ch_ctl_data.dst_size = DMA_DST_DATA_WIDTH_WORD;
793 
794     ch_cfg.chan_ctr = ch_ctl_data;
795     ch_cfg.chan_src_end_ptr = (uint32_t)(data + len - 1);
796     ch_cfg.chan_dst_end_ptr = (uint32_t) & (I2Cx->WFIFO);
797 
798     (pChan_Cfg_Align + dma_chan)->chan_ctr = ch_cfg.chan_ctr;
799     (pChan_Cfg_Align + dma_chan)->chan_src_end_ptr = ch_cfg.chan_src_end_ptr;
800     (pChan_Cfg_Align + dma_chan)->chan_dst_end_ptr = ch_cfg.chan_dst_end_ptr;
801 
802     //    NVIC_EnableIRQ(DMA_IRQn);
803     // set dma_wationreq to high for I2C single req, handshake rule 16
804     // DMA_WAIT_ON_REQ |= (1<<dma_chan);
805     DMA->CFG |= 0x1; // dma enable
806     DMA_INT_MASK |= (1 << dma_chan); // dma interrupt unmask, write 1
807     // set channel to use primary data struct only for basic/auto-request type
808     DMA->CHAN_PRI_ALT_CLR |= (1 << dma_chan);
809     DMA->CTL_BASE_PTR = (uint32_t)pChan_Cfg_Align;
810     // set channel useburst bit to diasble sreq from generating dma request
811     //        DMA->CHAN_USE_BURST_SET |= (1<<dma_chan);
812     DMA->CHAN_EN_CLR |= ~(1 << dma_chan); // disable other channels
813     DMA->CHAN_EN_SET |= (1 << dma_chan); // enable channel 6
814 }
815 
duet_i2c_master_dma_recv(uint8_t iic_idx,uint32_t * data,uint16_t len)816 void duet_i2c_master_dma_recv(uint8_t iic_idx, uint32_t *data, uint16_t len)
817 {
818     uint8_t dma_chan = 13;  // i2c0 rx using dma channel 10
819 
820     // malloc for channel descriptor
821     Chan_Cfg_TypeDef *pChan_Cfg_Align = duet_dma_ctrl_block_init();
822 
823     Chan_Ctl_Data_TypeDef ch1_ctl_data;
824     Chan_Cfg_TypeDef ch1_cfg;
825 
826     ch1_ctl_data.cycle_ctl = DMA_OP_MODE_BASIC; // DMA_OP_MODE_AUTO_REQ;
827     ch1_ctl_data.n_minus_1 = len - 1;
828     ch1_ctl_data.R_pow = 0;
829     ch1_ctl_data.src_inc = DMA_SRC_ADDR_INC_FIX;
830     ch1_ctl_data.dst_inc = DMA_SRC_ADDR_INC_WORD;
831     ch1_ctl_data.src_size = DMA_SRC_DATA_WIDTH_WORD;
832     ch1_ctl_data.dst_size = DMA_DST_DATA_WIDTH_WORD;
833 
834     ch1_cfg.chan_ctr = ch1_ctl_data;
835     ch1_cfg.chan_src_end_ptr = (uint32_t) & (I2C0->RFIFO);
836     ch1_cfg.chan_dst_end_ptr = (uint32_t)(data + len - 1);
837 
838     memcpy((char *)(pChan_Cfg_Align + dma_chan), (char *)(&ch1_cfg), sizeof(Chan_Cfg_TypeDef));
839 
840     // set dma_wationreq to high for I2C single req, handshake rule 16
841     //    DMA_WAIT_ON_REQ |= (1<<dma_chan);
842 
843     DMA->CFG |= 0x1; // dma enable
844 
845     // set chan1 to use primary data struct only
846     DMA->CHAN_PRI_ALT_CLR |= (1 << dma_chan);
847 
848     DMA->CTL_BASE_PTR = (uint32_t)pChan_Cfg_Align;
849 
850     DMA->CHAN_EN_CLR |= ~(1 << dma_chan); // disable other channels
851     DMA->CHAN_EN_SET |= (1 << dma_chan); // enable channel
852 
853     //        free(pChan_Cfg);
854 }
855