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