Skip to content

Commit d8d8c28

Browse files
authored
Merge pull request #5452 from 0xc0170/fix_i2c_onsemi
ONSEMI: Fix I2C issues
2 parents b76b3f7 + 36d335b commit d8d8c28

File tree

3 files changed

+23
-31
lines changed

3 files changed

+23
-31
lines changed

targets/TARGET_ONSEMI/TARGET_NCS36510/i2c.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
#define I2C_SPEED_400K_AT_8MHZ (uint8_t)0x03
4949
#define I2C_SPEED_400K_AT_16MHZ (uint8_t)0x08
5050

51-
5251
/* I2C commands */
5352
#define I2C_CMD_NULL 0x00
5453
#define I2C_CMD_WDAT0 0x10
@@ -93,7 +92,10 @@
9392
#define I2C_API_STATUS_SUCCESS 0
9493
#define PAD_REG_ADRS_BYTE_SIZE 4
9594

96-
#define SEND_COMMAND(cmd) while(!I2C_FIFO_EMPTY); wait_us(1); obj->membase->CMD_REG = cmd;
95+
// The wait_us(0) command is needed so the I2C state machines have enough
96+
// time for data to settle across all clock domain crossings in their
97+
// synchronizers, both directions.
98+
#define SEND_COMMAND(cmd) wait_us(0); obj->membase->CMD_REG = cmd; wait_us(0);
9799

98100
/** Init I2C device.
99101
* @details
@@ -158,4 +160,4 @@ extern int32_t fI2cReadB(i2c_t *d, char *buf, int len);
158160
*/
159161
extern int32_t fI2cWriteB(i2c_t *d, const char *buf, int len);
160162

161-
#endif /* I2C_H_ */
163+
#endif /* I2C_H_ */

targets/TARGET_ONSEMI/TARGET_NCS36510/i2c_api.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,7 @@ int i2c_byte_write(i2c_t *obj, int data)
169169
return Count;
170170
}
171171

172-
while(obj->membase->STATUS.WORD & I2C_STATUS_CMD_FIFO_OFL_BIT); /* Wait till command overflow ends */
173-
174-
if(obj->membase->STATUS.WORD & I2C_STATUS_BUS_ERR_BIT) {
172+
if(I2C_BUS_ERR_CHECK) {
175173
/* Bus error means NAK received */
176174
return 0;
177175
} else {
@@ -180,4 +178,4 @@ int i2c_byte_write(i2c_t *obj, int data)
180178
}
181179
}
182180

183-
#endif /* DEVICE_I2C */
181+
#endif /* DEVICE_I2C */

targets/TARGET_ONSEMI/TARGET_NCS36510/ncs36510_i2c.c

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@
6565
/* See i2c.h for details */
6666
void fI2cInit(i2c_t *obj,PinName sda,PinName scl)
6767
{
68-
uint32_t clockDivisor;
6968
/* determine the I2C to use */
7069
I2CName i2c_sda = (I2CName)pinmap_peripheral(sda, PinMap_I2C_SDA);
7170
I2CName i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL);
@@ -93,9 +92,7 @@ void fI2cInit(i2c_t *obj,PinName sda,PinName scl)
9392
obj->membase->CR.BITS.I2C_APB_CD_EN = True;
9493

9594
/* set default baud rate at 100k */
96-
clockDivisor = ((fClockGetPeriphClockfrequency() / 100000) >> 2) - 2;
97-
obj->membase->CR.BITS.CD_VAL = (clockDivisor & I2C_CLOCKDIVEDER_VAL_MASK);
98-
obj->membase->PRE_SCALE_REG = (clockDivisor & I2C_APB_CLK_DIVIDER_VAL_MASK) >> 5; /**< Zero pre-scale value not allowed */
95+
fI2cFrequency(obj, 100000);
9996

10097
/* Cross bar setting */
10198
pinmap_pinout(sda, PinMap_I2C_SDA);
@@ -110,8 +107,8 @@ void fI2cInit(i2c_t *obj,PinName sda,PinName scl)
110107
PadReg_t *padRegScl = (PadReg_t*)(PADREG_BASE + (scl * PAD_REG_ADRS_BYTE_SIZE));
111108

112109
CLOCK_ENABLE(CLOCK_PAD);
113-
padRegSda->PADIO0.BITS.POWER = 1; /* sda: Drive strength */
114-
padRegScl->PADIO0.BITS.POWER = 1; /* scl: Drive strength */
110+
padRegSda->PADIO0.BITS.POWER = 3; /* sda: Drive strength */
111+
padRegScl->PADIO0.BITS.POWER = 3; /* scl: Drive strength */
115112
CLOCK_DISABLE(CLOCK_PAD);
116113

117114
CLOCK_ENABLE(CLOCK_GPIO);
@@ -160,7 +157,10 @@ int32_t fI2cReadB(i2c_t *obj, char *buf, int len)
160157
int32_t read = 0;
161158

162159
while (read < len) {
163-
/* Send read command */
160+
161+
while(FIFO_OFL_CHECK); /* Wait till command overflow ends */
162+
163+
/* Send read command */
164164
SEND_COMMAND(I2C_CMD_RDAT8);
165165
while(!RD_DATA_READY) {
166166
if (I2C_BUS_ERR_CHECK) {
@@ -170,16 +170,16 @@ int32_t fI2cReadB(i2c_t *obj, char *buf, int len)
170170
}
171171
buf[read++] = obj->membase->RD_FIFO_REG; /**< Reading 'read FIFO register' will clear status register */
172172

173-
if(!(read>=len)) { /* No ACK will be generated for the last read, upper level I2C protocol should generate */
174-
SEND_COMMAND(I2C_CMD_WDAT0); /* TODO based on requirement generate ACK or NACK Based on the requirement. */
173+
if(!(read>=len)) {
174+
SEND_COMMAND(I2C_CMD_WDAT0);
175175
} else {
176176
/* No ack */
177177
SEND_COMMAND(I2C_CMD_WDAT1);
178178
}
179179

180180
/* check for FIFO underflow */
181181
if(I2C_UFL_CHECK) {
182-
return I2C_ERROR_NO_SLAVE; /* TODO No error available for this in i2c_api.h */
182+
return I2C_EVENT_ERROR;
183183
}
184184
if(I2C_BUS_ERR_CHECK) {
185185
/* Bus error */
@@ -196,44 +196,36 @@ int32_t fI2cWriteB(i2c_t *obj, const char *buf, int len)
196196
int32_t write = 0;
197197

198198
while (write < len) {
199-
/* Send write command */
200-
SEND_COMMAND(I2C_CMD_WDAT8);
199+
200+
while(FIFO_OFL_CHECK); /* Wait till command overflow ends */
201201

202202
if(buf[write] == I2C_CMD_RDAT8) {
203203
/* SW work around to counter FSM issue. If the only command in the CMD FIFO is the WDAT8 command (data of 0x13)
204204
then as the command is read out (i.e. the FIFO goes empty), the WDAT8 command will be misinterpreted as a
205205
RDAT8 command by the data FSM; resulting in an I2C bus error (NACK instead of an ACK). */
206206
/* Send 0x13 bit wise */
207207
SEND_COMMAND(I2C_CMD_WDAT0);
208-
209208
SEND_COMMAND(I2C_CMD_WDAT0);
210-
211209
SEND_COMMAND(I2C_CMD_WDAT0);
212-
213210
SEND_COMMAND(I2C_CMD_WDAT1);
214-
215211
SEND_COMMAND(I2C_CMD_WDAT0);
216-
217212
SEND_COMMAND(I2C_CMD_WDAT0);
218-
219213
SEND_COMMAND(I2C_CMD_WDAT1);
220-
221214
SEND_COMMAND(I2C_CMD_WDAT1);
215+
write++;
222216
} else {
223217
/* Send data */
218+
SEND_COMMAND(I2C_CMD_WDAT8);
224219
SEND_COMMAND(buf[write++]);
225220
}
226-
SEND_COMMAND(I2C_CMD_VRFY_ACK); /* TODO Verify ACK based on requirement, Do we need? */
221+
SEND_COMMAND(I2C_CMD_VRFY_ACK);
227222

228223
if (I2C_BUS_ERR_CHECK) {
229224
/* Bus error */
230225
return I2C_ERROR_BUS_BUSY;
231226
}
232-
233-
while(FIFO_OFL_CHECK); /* Wait till command overflow ends */
234227
}
235-
236228
return write;
237229
}
238230

239-
#endif /* DEVICE_I2C */
231+
#endif /* DEVICE_I2C */

0 commit comments

Comments
 (0)