Skip to content

Commit 6f3540c

Browse files
committed
Fix I2C issues
1. I2C active. 2. 7-bit address assert error. 3. Master Repeat Start.
1 parent 5667847 commit 6f3540c

File tree

1 file changed

+65
-57
lines changed
  • hal/targets/hal/TARGET_NUVOTON/TARGET_NUC472

1 file changed

+65
-57
lines changed

hal/targets/hal/TARGET_NUVOTON/TARGET_NUC472/i2c_api.c

Lines changed: 65 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@
3131
#if NU_I2C_DEBUG
3232
struct i2c_s MY_I2C;
3333
struct i2c_s MY_I2C_2;
34-
char MY_STATUS[64];
35-
int MY_STATUS_POS = 0;
36-
uint32_t MY_TIMEOUT;
37-
uint32_t MY_ELAPSED;
38-
uint32_t MY_T1;
39-
uint32_t MY_T2;
34+
char MY_I2C_STATUS[64];
35+
int MY_I2C_STATUS_POS = 0;
36+
uint32_t MY_I2C_TIMEOUT;
37+
uint32_t MY_I2C_ELAPSED;
38+
uint32_t MY_I2C_T1;
39+
uint32_t MY_I2C_T2;
4040
#endif
4141

4242
struct nu_i2c_var {
@@ -163,12 +163,12 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl)
163163

164164
int i2c_start(i2c_t *obj)
165165
{
166-
return i2c_do_trsn(obj, I2C_CTL_STA_Msk | I2C_CTL_SI_Msk, 1) ? 0 : I2C_ERROR_BUS_BUSY;
166+
return i2c_do_trsn(obj, I2C_CTL_STA_Msk | I2C_CTL_SI_Msk, 1);
167167
}
168168

169169
int i2c_stop(i2c_t *obj)
170170
{
171-
return i2c_do_trsn(obj, I2C_CTL_STO_Msk | I2C_CTL_SI_Msk, 1) ? 0 : I2C_ERROR_BUS_BUSY;
171+
return i2c_do_trsn(obj, I2C_CTL_STO_Msk | I2C_CTL_SI_Msk, 1);
172172
}
173173

174174
void i2c_frequency(i2c_t *obj, int hz)
@@ -362,10 +362,10 @@ int i2c_allow_powerdown(void)
362362
while (modinit_mask) {
363363
int i2c_idx = nu_ctz(modinit_mask);
364364
const struct nu_modinit_s *modinit = i2c_modinit_tab + i2c_idx;
365-
if (modinit->modname != NC) {
366-
I2C_T *i2c_base = (I2C_T *) NU_MODBASE(modinit->modname);
365+
struct nu_i2c_var *var = (struct nu_i2c_var *) modinit->var;
366+
if (var->obj) {
367367
// Disallow entering power-down mode if I2C transfer is enabled.
368-
if (i2c_base->CTL & I2C_CTL_INTEN_Msk) {
368+
if (i2c_active(var->obj)) {
369369
return 0;
370370
}
371371
}
@@ -435,21 +435,21 @@ static int i2c_do_trsn(i2c_t *obj, uint32_t i2c_ctl, int sync)
435435
#endif
436436
}
437437
else {
438-
#if 0
439-
// Avoid duplicate Start/Stop.
438+
#if 1
439+
// NOTE: Avoid duplicate Start/Stop. Otherwise, we may meet strange error.
440440
uint32_t status = I2C_GET_STATUS(i2c_base);
441441

442442
switch (status) {
443443
case 0x08: // Start
444444
case 0x10: // Master Repeat Start
445-
if (status & I2C_CTL_STA_Msk) {
445+
if (i2c_ctl & I2C_CTL_STA_Msk) {
446446
return 0;
447447
}
448448
else {
449449
break;
450450
}
451451
case 0xF8: // Bus Released
452-
if (status & (I2C_CTL_STA_Msk | I2C_CTL_STO_Msk) == I2C_CTL_STO_Msk) {
452+
if (i2c_ctl & (I2C_CTL_STA_Msk | I2C_CTL_STO_Msk) == I2C_CTL_STO_Msk) {
453453
return 0;
454454
}
455455
else {
@@ -469,7 +469,7 @@ static int i2c_do_trsn(i2c_t *obj, uint32_t i2c_ctl, int sync)
469469

470470
i2c_enable_int(obj);
471471

472-
return err ? 0 : 1;
472+
return err;
473473
}
474474

475475
static int i2c_poll_status_timeout(i2c_t *obj, int (*is_status)(i2c_t *obj), uint32_t timeout)
@@ -488,10 +488,10 @@ static int i2c_poll_status_timeout(i2c_t *obj, int (*is_status)(i2c_t *obj), uin
488488
elapsed = (t2 > t1) ? (t2 - t1) : ((uint64_t) t2 + 0xFFFFFFFF - t1 + 1);
489489
if (elapsed >= timeout) {
490490
#if NU_I2C_DEBUG
491-
MY_T1 = t1;
492-
MY_T2 = t2;
493-
MY_ELAPSED = elapsed;
494-
MY_TIMEOUT = timeout;
491+
MY_I2C_T1 = t1;
492+
MY_I2C_T2 = t2;
493+
MY_I2C_ELAPSED = elapsed;
494+
MY_I2C_TIMEOUT = timeout;
495495
MY_I2C_2 = obj->i2c;
496496
while (1);
497497
#endif
@@ -536,10 +536,10 @@ static int i2c_poll_tran_heatbeat_timeout(i2c_t *obj, uint32_t timeout)
536536
if (elapsed >= timeout) { // Transfer idle
537537
#if NU_I2C_DEBUG
538538
MY_I2C = obj->i2c;
539-
MY_T1 = t1;
540-
MY_T2 = t2;
541-
MY_ELAPSED = elapsed;
542-
MY_TIMEOUT = timeout;
539+
MY_I2C_T1 = t1;
540+
MY_I2C_T2 = t2;
541+
MY_I2C_ELAPSED = elapsed;
542+
MY_I2C_TIMEOUT = timeout;
543543
MY_I2C_2 = obj->i2c;
544544
while (1);
545545
#endif
@@ -631,12 +631,12 @@ static void i2c_irq(i2c_t *obj)
631631

632632
status = I2C_GET_STATUS(i2c_base);
633633
#if NU_I2C_DEBUG
634-
if (MY_STATUS_POS < (sizeof (MY_STATUS) / sizeof (MY_STATUS[0]))) {
635-
MY_STATUS[MY_STATUS_POS ++] = status;
634+
if (MY_I2C_STATUS_POS < (sizeof (MY_I2C_STATUS) / sizeof (MY_I2C_STATUS[0]))) {
635+
MY_I2C_STATUS[MY_I2C_STATUS_POS ++] = status;
636636
}
637637
else {
638-
memset(MY_STATUS, 0x00, sizeof (MY_STATUS));
639-
MY_STATUS_POS = 0;
638+
memset(MY_I2C_STATUS, 0x00, sizeof (MY_I2C_STATUS));
639+
MY_I2C_STATUS_POS = 0;
640640
}
641641
#endif
642642

@@ -657,16 +657,8 @@ static void i2c_irq(i2c_t *obj)
657657
i2c_disable_int(obj);
658658
break;
659659
}
660-
661-
// NOTE: Error on the sequence below. Also on other inbetween transfers.
662-
// Cause is unknown. Replace Repeat Start or Stop/Start with Stop for workaround.
663-
// (1) Send wrt addr
664-
// (2) Send data
665-
// (3) Repeat Start
666-
// (4) Send rd addr
667-
// (5) Read data failed. Get Master Transmit Address ACK after Send rd addr.
668-
// Go Master Stop.
669-
i2c_fsm_reset(obj, I2C_CTL_STO_Msk | I2C_CTL_SI_Msk);
660+
// Go Master Repeat Start
661+
i2c_fsm_reset(obj, I2C_CTL_STA_Msk | I2C_CTL_SI_Msk);
670662
}
671663
}
672664
else {
@@ -675,16 +667,17 @@ static void i2c_irq(i2c_t *obj)
675667
break;
676668
case 0x30: // Master Transmit Data NACK
677669
case 0x20: // Master Transmit Address NACK
678-
// Go Master Stop.
679-
i2c_fsm_reset(obj, I2C_CTL_STO_Msk | I2C_CTL_SI_Msk);
670+
// Go Master Repeat Start
671+
i2c_fsm_reset(obj, I2C_CTL_STA_Msk | I2C_CTL_SI_Msk);
680672
break;
681673
case 0x38: // Master Arbitration Lost
682674
i2c_fsm_reset(obj, I2C_CTL_SI_Msk | I2C_CTL_AA_Msk);
683675
break;
684676

685677
case 0x48: // Master Receive Address NACK
686678
// Go Master Stop.
687-
i2c_fsm_reset(obj, I2C_CTL_STO_Msk | I2C_CTL_SI_Msk);
679+
// Go Master Repeat Start
680+
i2c_fsm_reset(obj, I2C_CTL_STA_Msk | I2C_CTL_SI_Msk);
688681
break;
689682
case 0x40: // Master Receive Address ACK
690683
case 0x50: // Master Receive Data ACK
@@ -702,8 +695,8 @@ static void i2c_irq(i2c_t *obj)
702695
while (1);
703696
}
704697
#endif
705-
// Go Master Stop.
706-
i2c_fsm_reset(obj, I2C_CTL_STO_Msk | I2C_CTL_SI_Msk);
698+
// Go Master Repeat Start
699+
i2c_fsm_reset(obj, I2C_CTL_STA_Msk | I2C_CTL_SI_Msk);
707700
}
708701
else {
709702
uint32_t i2c_ctl = I2C_CTL_SI_Msk | I2C_CTL_AA_Msk;
@@ -875,8 +868,8 @@ static void i2c_fsm_reset(i2c_t *obj, uint32_t i2c_ctl)
875868

876869
void i2c_transfer_asynch(i2c_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint32_t address, uint32_t stop, uint32_t handler, uint32_t event, DMAUsage hint)
877870
{
878-
// NOTE: NUC472 I2C only supports 7-bit slave address.
879-
MBED_ASSERT((address & 0xFFFFFF80) == 0);
871+
// NOTE: NUC472 I2C only supports 7-bit slave address. The mbed I2C address passed in is shifted left by 1 bit (7-bit addr << 1).
872+
MBED_ASSERT((address & 0xFFFFFF00) == 0);
880873

881874
// NOTE: First transmit and then receive.
882875

@@ -913,7 +906,7 @@ uint32_t i2c_irq_handler_asynch(i2c_t *obj)
913906
else {
914907
event = I2C_EVENT_TRANSFER_COMPLETE;
915908
if (obj->i2c.stop) {
916-
i2c_stop(obj);
909+
I2C_SET_CONTROL_REG(i2c_base, I2C_CTL_STO_Msk | I2C_CTL_SI_Msk);
917910
}
918911
}
919912
break;
@@ -927,27 +920,36 @@ uint32_t i2c_irq_handler_asynch(i2c_t *obj)
927920
I2C_SET_CONTROL_REG(i2c_base, I2C_CTL_SI_Msk);
928921
}
929922
else if (obj->rx_buff.buffer && obj->rx_buff.pos < obj->rx_buff.length) {
930-
i2c_start(obj);
923+
I2C_SET_CONTROL_REG(i2c_base, I2C_CTL_STA_Msk | I2C_CTL_SI_Msk);
931924
}
932925
else {
933926
event = I2C_EVENT_TRANSFER_COMPLETE;
934927
if (obj->i2c.stop) {
935-
i2c_stop(obj);
928+
I2C_SET_CONTROL_REG(i2c_base, I2C_CTL_STO_Msk | I2C_CTL_SI_Msk);
936929
}
937930
}
938931
break;
939932

940933
case 0x20: // Master Transmit Address NACK
941934
event = I2C_EVENT_ERROR_NO_SLAVE;
942935
if (obj->i2c.stop) {
943-
i2c_stop(obj);
936+
I2C_SET_CONTROL_REG(i2c_base, I2C_CTL_STO_Msk | I2C_CTL_SI_Msk);
944937
}
945938
break;
946939

947940
case 0x30: // Master Transmit Data NACK
948-
event = I2C_EVENT_TRANSFER_EARLY_NACK;
949-
if (obj->i2c.stop) {
950-
i2c_stop(obj);
941+
if (obj->tx_buff.buffer && obj->tx_buff.pos < obj->tx_buff.length) {
942+
event = I2C_EVENT_TRANSFER_EARLY_NACK;
943+
I2C_SET_CONTROL_REG(i2c_base, I2C_CTL_STO_Msk | I2C_CTL_SI_Msk);
944+
}
945+
else if (obj->rx_buff.buffer && obj->rx_buff.pos < obj->rx_buff.length) {
946+
I2C_SET_CONTROL_REG(i2c_base, I2C_CTL_STA_Msk | I2C_CTL_SI_Msk);
947+
}
948+
else {
949+
event = I2C_EVENT_TRANSFER_COMPLETE;
950+
if (obj->i2c.stop) {
951+
I2C_SET_CONTROL_REG(i2c_base, I2C_CTL_STO_Msk | I2C_CTL_SI_Msk);
952+
}
951953
}
952954
break;
953955

@@ -968,7 +970,7 @@ uint32_t i2c_irq_handler_asynch(i2c_t *obj)
968970
case 0x48: // Master Receive Address NACK
969971
event = I2C_EVENT_ERROR_NO_SLAVE;
970972
if (obj->i2c.stop) {
971-
i2c_stop(obj);
973+
I2C_SET_CONTROL_REG(i2c_base, I2C_CTL_STO_Msk | I2C_CTL_SI_Msk);
972974
}
973975
break;
974976

@@ -988,7 +990,7 @@ uint32_t i2c_irq_handler_asynch(i2c_t *obj)
988990
default:
989991
event = I2C_EVENT_ERROR;
990992
if (obj->i2c.stop) {
991-
i2c_stop(obj);
993+
I2C_SET_CONTROL_REG(i2c_base, I2C_CTL_STO_Msk | I2C_CTL_SI_Msk);
992994
}
993995
}
994996

@@ -1000,9 +1002,15 @@ uint32_t i2c_irq_handler_asynch(i2c_t *obj)
10001002
}
10011003

10021004
uint8_t i2c_active(i2c_t *obj)
1003-
{
1004-
I2C_T *i2c_base = (I2C_T *) NU_MODBASE(obj->i2c.i2c);
1005-
return !! (i2c_base->CTL & I2C_CTL_INTEN_Msk);
1005+
{
1006+
const struct nu_modinit_s *modinit = get_modinit(obj->i2c.i2c, i2c_modinit_tab);
1007+
MBED_ASSERT(modinit != NULL);
1008+
MBED_ASSERT(modinit->modname == obj->i2c.i2c);
1009+
1010+
// Vector will be changed for async transfer. Use it to judge if async transfer is on-going.
1011+
uint32_t vec = NVIC_GetVector(modinit->irq_n);
1012+
struct nu_i2c_var *var = (struct nu_i2c_var *) modinit->var;
1013+
return (vec && vec != var->vec);
10061014
}
10071015

10081016
void i2c_abort_asynch(i2c_t *obj)

0 commit comments

Comments
 (0)