Skip to content

Commit 1270f40

Browse files
committed
Add initial handling for long I2C reads.
1 parent 0c038b4 commit 1270f40

File tree

2 files changed

+72
-54
lines changed

2 files changed

+72
-54
lines changed

cores/esp32/esp32-hal-i2c.c

+70-52
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#define DR_REG_I2C_EXT_BASE_FIXED 0x60013000
3232
#define DR_REG_I2C1_EXT_BASE_FIXED 0x60027000
3333

34+
#define COMMAND_BUFFER_LENGTH 16
35+
3436
struct i2c_struct_t {
3537
i2c_dev_t * dev;
3638
#if !CONFIG_DISABLE_HAL_LOCKS
@@ -127,26 +129,25 @@ void i2cSetCmd(i2c_t * i2c, uint8_t index, uint8_t op_code, uint8_t byte_num, bo
127129
i2c->dev->command[index].op_code = op_code;
128130
}
129131

130-
void i2cResetCmd(i2c_t * i2c){
131-
int i;
132+
void i2cResetCmd(i2c_t * i2c) {
133+
uint8_t i;
132134
for(i=0;i<16;i++){
133135
i2c->dev->command[i].val = 0;
134136
}
135137
}
136138

137-
void i2cResetFiFo(i2c_t * i2c)
138-
{
139+
void i2cResetFiFo(i2c_t * i2c) {
139140
i2c->dev->fifo_conf.tx_fifo_rst = 1;
140141
i2c->dev->fifo_conf.tx_fifo_rst = 0;
141142
i2c->dev->fifo_conf.rx_fifo_rst = 1;
142143
i2c->dev->fifo_conf.rx_fifo_rst = 0;
143144
}
144145

145-
i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint8_t len, bool sendStop)
146+
i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint16_t len, bool sendStop)
146147
{
147148
int i;
148-
uint8_t index = 0;
149-
uint8_t dataLen = len + (addr_10bit?2:1);
149+
uint16_t index = 0;
150+
uint16_t dataLen = len + (addr_10bit?2:1);
150151
address = (address << 1);
151152

152153
if(i2c == NULL){
@@ -244,12 +245,25 @@ i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * dat
244245
return I2C_ERROR_OK;
245246
}
246247

247-
i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint8_t len, bool sendStop)
248+
uint8_t inc( uint8_t* index )
249+
{
250+
uint8_t i = index[ 0 ];
251+
if (++index[ 0 ] == COMMAND_BUFFER_LENGTH)
252+
{
253+
index[ 0 ] = 0;
254+
}
255+
256+
return i;
257+
}
258+
259+
i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint16_t len, bool sendStop)
248260
{
249261
address = (address << 1) | 1;
250262
uint8_t addrLen = (addr_10bit?2:1);
251-
uint8_t index = 0;
252-
uint8_t cmdIdx;
263+
uint8_t amountRead[16];
264+
uint16_t index = 0;
265+
uint8_t cmdIdx = 0, currentCmdIdx = 0, nextCmdCount;
266+
bool stopped = false, isEndNear = false;
253267
uint8_t willRead;
254268

255269
if(i2c == NULL){
@@ -269,86 +283,90 @@ i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data
269283
i2cResetCmd(i2c);
270284

271285
//CMD START
272-
i2cSetCmd(i2c, 0, I2C_CMD_RSTART, 0, false, false, false);
286+
i2cSetCmd(i2c, cmdIdx++, I2C_CMD_RSTART, 0, false, false, false);
273287

274288
//CMD WRITE ADDRESS
275289
i2c->dev->fifo_data.val = address & 0xFF;
276290
if(addr_10bit) {
277291
i2c->dev->fifo_data.val = (address >> 8) & 0xFF;
278292
}
279-
i2cSetCmd(i2c, 1, I2C_CMD_WRITE, addrLen, false, false, true);
293+
i2cSetCmd(i2c, cmdIdx++, I2C_CMD_WRITE, addrLen, false, false, true);
294+
nextCmdCount = cmdIdx;
280295

281-
while(len) {
282-
cmdIdx = (index)?0:2;
283-
willRead = (len > 32)?32:(len-1);
284-
if(cmdIdx){
285-
i2cResetFiFo(i2c);
286-
}
287-
288-
if(willRead){
289-
i2cSetCmd(i2c, cmdIdx++, I2C_CMD_READ, willRead, false, false, false);
290-
}
291-
292-
if((len - willRead) > 1) {
293-
i2cSetCmd(i2c, cmdIdx++, I2C_CMD_END, 0, false, false, false);
294-
} else {
295-
willRead++;
296-
i2cSetCmd(i2c, cmdIdx++, I2C_CMD_READ, 1, true, false, false);
297-
if(sendStop) {
298-
i2cSetCmd(i2c, cmdIdx++, I2C_CMD_STOP, 0, false, false, false);
299-
}
300-
}
301-
302-
//Clear Interrupts
303-
i2c->dev->int_clr.val = 0xFFFFFFFF;
304-
305-
//START Transmission
306-
i2c->dev->ctr.trans_start = 1;
296+
//Clear Interrupts
297+
i2c->dev->int_clr.val = 0x00001FFF;
307298

299+
//START Transmission
300+
i2c->dev->ctr.trans_start = 1;
301+
while (!stopped) {
308302
//WAIT Transmission
309303
uint32_t startAt = millis();
310304
while(1) {
311305
//have been looping for too long
312-
if((millis() - startAt)>50){
313-
log_e("Timeout! Addr: %x", address >> 1);
306+
if((millis() - startAt)>50) {
307+
log_e("Timeout! Addr: %x, index %d", (address >> 1), index);
314308
I2C_MUTEX_UNLOCK();
315309
return I2C_ERROR_BUS;
316310
}
317311

318312
//Bus failed (maybe check for this while waiting?
319313
if(i2c->dev->int_raw.arbitration_lost) {
320-
log_e("Bus Fail! Addr: %x", address >> 1);
314+
log_e("Bus Fail! Addr: %x", (address >> 1));
321315
I2C_MUTEX_UNLOCK();
322316
return I2C_ERROR_BUS;
323317
}
324318

325319
//Bus timeout
326320
if(i2c->dev->int_raw.time_out) {
327-
log_e("Bus Timeout! Addr: %x", address >> 1);
321+
log_e("Bus Timeout! Addr: %x, index %d", (address >> 1), index );
328322
I2C_MUTEX_UNLOCK();
329323
return I2C_ERROR_TIMEOUT;
330324
}
331325

332326
//Transmission did not finish and ACK_ERR is set
333327
if(i2c->dev->int_raw.ack_err) {
334328
log_w("Ack Error! Addr: %x", address >> 1);
329+
while((i2c->dev->status_reg.bus_busy) && ((millis() - startAt)<50));
335330
I2C_MUTEX_UNLOCK();
336331
return I2C_ERROR_ACK;
337332
}
338333

339-
if(i2c->dev->command[cmdIdx-1].done) {
340-
break;
334+
// Save bytes from the buffer as they arrive instead of doing them at the end of the loop since there is no
335+
// pause from an END operation in this approach.
336+
if((!isEndNear) && (nextCmdCount < 2)) {
337+
if (willRead = ((len>32)?32:len)) {
338+
if (willRead > 1) {
339+
i2cSetCmd(i2c, cmdIdx, I2C_CMD_READ, (amountRead[ inc( &cmdIdx ) ] = willRead -1), false, false, false);
340+
nextCmdCount++;
341+
}
342+
i2cSetCmd(i2c, cmdIdx, I2C_CMD_READ, (amountRead[ inc( &cmdIdx ) ] = 1), (len<=32), false, false);
343+
nextCmdCount++;
344+
len -= willRead;
345+
} else {
346+
i2cSetCmd(i2c, inc( &cmdIdx ), I2C_CMD_STOP, 0, false, false, false);
347+
isEndNear = true;
348+
nextCmdCount++;
349+
}
341350
}
342-
}
343351

344-
int i = 0;
345-
while(i<willRead) {
346-
i++;
347-
data[index++] = i2c->dev->fifo_data.val & 0xFF;
352+
if(i2c->dev->command[currentCmdIdx].done) {
353+
nextCmdCount--;
354+
if (i2c->dev->command[currentCmdIdx].op_code == I2C_CMD_READ) {
355+
while(amountRead[currentCmdIdx]>0) {
356+
data[index++] = i2c->dev->fifo_data.val & 0xFF;
357+
amountRead[currentCmdIdx]--;
358+
}
359+
i2cResetFiFo(i2c);
360+
} else if (i2c->dev->command[currentCmdIdx].op_code == I2C_CMD_STOP) {
361+
stopped = true;
362+
}
363+
inc( &currentCmdIdx );
364+
break;
365+
}
348366
}
349-
len -= willRead;
350367
}
351368
I2C_MUTEX_UNLOCK();
369+
352370
return I2C_ERROR_OK;
353371
}
354372

@@ -425,7 +443,7 @@ i2c_t * i2cInit(uint8_t i2c_num, uint16_t slave_addr, bool addr_10bit_en)
425443
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,DPORT_I2C_EXT1_CLK_EN);
426444
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT1_RST);
427445
}
428-
446+
429447
I2C_MUTEX_LOCK();
430448
i2c->dev->ctr.val = 0;
431449
i2c->dev->ctr.ms_mode = (slave_addr == 0);
@@ -434,7 +452,7 @@ i2c_t * i2cInit(uint8_t i2c_num, uint16_t slave_addr, bool addr_10bit_en)
434452
i2c->dev->ctr.clk_en = 1;
435453

436454
//the max clock number of receiving a data
437-
i2c->dev->timeout.tout = 400000;//clocks max=1048575
455+
i2c->dev->timeout.tout = 1048575;//clocks max=1048575
438456
//disable apb nonfifo access
439457
i2c->dev->fifo_conf.nonfifo_en = 0;
440458

cores/esp32/esp32-hal-i2c.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ i2c_err_t i2cDetachSCL(i2c_t * i2c, int8_t scl);
4848
i2c_err_t i2cAttachSDA(i2c_t * i2c, int8_t sda);
4949
i2c_err_t i2cDetachSDA(i2c_t * i2c, int8_t sda);
5050

51-
i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint8_t len, bool sendStop);
52-
i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint8_t len, bool sendStop);
51+
i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint16_t len, bool sendStop);
52+
i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint16_t len, bool sendStop);
5353

5454
void i2cReset(i2c_t* i2c);
5555

0 commit comments

Comments
 (0)