Skip to content

Commit 9ec4389

Browse files
committed
implement thread-safe i2c
1 parent 50b060a commit 9ec4389

File tree

2 files changed

+96
-32
lines changed

2 files changed

+96
-32
lines changed

cores/esp32/esp32-hal-i2c.c

+94-26
Original file line numberDiff line numberDiff line change
@@ -15,51 +15,85 @@
1515
#include "esp32-hal-i2c.h"
1616
#include "freertos/FreeRTOS.h"
1717
#include "freertos/task.h"
18+
#include "freertos/semphr.h"
1819
#include "rom/ets_sys.h"
1920
#include "soc/i2c_reg.h"
2021
#include "soc/dport_reg.h"
2122

22-
#define I2C_DEV(i) (volatile i2c_dev_t *)((i)?DR_REG_I2C1_EXT_BASE:DR_REG_I2C_EXT_BASE)
23-
//#define I2C_DEV(i) ((i2c_dev_t *)(REG_I2C_BASE(i)))
2423
#define I2C_SCL_IDX(p) ((p==0)?I2CEXT0_SCL_OUT_IDX:((p==1)?I2CEXT1_SCL_OUT_IDX:0))
2524
#define I2C_SDA_IDX(p) ((p==0)?I2CEXT0_SDA_OUT_IDX:((p==1)?I2CEXT1_SDA_OUT_IDX:0))
2625

26+
27+
struct i2c_struct_t {
28+
i2c_dev_t * dev;
29+
xSemaphoreHandle lock;
30+
uint8_t num;
31+
};
32+
33+
enum {
34+
I2C_CMD_RSTART,
35+
I2C_CMD_WRITE,
36+
I2C_CMD_READ,
37+
I2C_CMD_STOP,
38+
I2C_CMD_END
39+
};
40+
41+
#define I2C_MUTEX_LOCK() do {} while (xSemaphoreTake(i2c->lock, portMAX_DELAY) != pdPASS)
42+
#define I2C_MUTEX_UNLOCK() xSemaphoreGive(i2c->lock)
43+
44+
static i2c_t _i2c_bus_array[2] = {
45+
{(volatile i2c_dev_t *)(DR_REG_I2C_EXT_BASE), NULL, 0},
46+
{(volatile i2c_dev_t *)(DR_REG_I2C1_EXT_BASE), NULL, 1}
47+
};
48+
2749
void i2cAttachSCL(i2c_t * i2c, int8_t scl)
2850
{
51+
if(i2c == NULL){
52+
return;
53+
}
54+
I2C_MUTEX_LOCK();
2955
pinMode(scl, OUTPUT);
3056
pinMatrixOutAttach(scl, I2C_SCL_IDX(i2c->num), false, false);
3157
pinMatrixInAttach(scl, I2C_SCL_IDX(i2c->num), false);
58+
I2C_MUTEX_UNLOCK();
3259
}
3360

3461
void i2cDetachSCL(i2c_t * i2c, int8_t scl)
3562
{
63+
if(i2c == NULL){
64+
return;
65+
}
66+
I2C_MUTEX_LOCK();
3667
pinMatrixOutDetach(scl, false, false);
3768
pinMatrixInDetach(I2C_SCL_IDX(i2c->num), false, false);
3869
pinMode(scl, INPUT);
70+
I2C_MUTEX_UNLOCK();
3971
}
4072

4173
void i2cAttachSDA(i2c_t * i2c, int8_t sda)
4274
{
75+
if(i2c == NULL){
76+
return;
77+
}
78+
I2C_MUTEX_LOCK();
4379
pinMode(sda, OUTPUT_OPEN_DRAIN);
4480
pinMatrixOutAttach(sda, I2C_SDA_IDX(i2c->num), false, false);
4581
pinMatrixInAttach(sda, I2C_SDA_IDX(i2c->num), false);
82+
I2C_MUTEX_UNLOCK();
4683
}
4784

4885
void i2cDetachSDA(i2c_t * i2c, int8_t sda)
4986
{
87+
if(i2c == NULL){
88+
return;
89+
}
90+
I2C_MUTEX_LOCK();
5091
pinMatrixOutDetach(sda, false, false);
5192
pinMatrixInDetach(I2C_SDA_IDX(i2c->num), false, false);
5293
pinMode(sda, INPUT);
94+
I2C_MUTEX_UNLOCK();
5395
}
5496

55-
enum {
56-
I2C_CMD_RSTART,
57-
I2C_CMD_WRITE,
58-
I2C_CMD_READ,
59-
I2C_CMD_STOP,
60-
I2C_CMD_END
61-
};
62-
6397
/*
6498
* index - command index (0 to 15)
6599
* op_code - is the command
@@ -78,13 +112,27 @@ void i2cSetCmd(i2c_t * i2c, uint8_t index, uint8_t op_code, uint8_t byte_num, bo
78112
i2c->dev->command[index].op_code = op_code;
79113
}
80114

115+
void i2cResetFiFo(i2c_t * i2c)
116+
{
117+
i2c->dev->fifo_conf.tx_fifo_rst = 1;
118+
i2c->dev->fifo_conf.tx_fifo_rst = 0;
119+
i2c->dev->fifo_conf.rx_fifo_rst = 1;
120+
i2c->dev->fifo_conf.rx_fifo_rst = 0;
121+
}
122+
81123
int i2cWrite(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint8_t len, bool sendStop)
82124
{
83125
int i;
84126
uint8_t index = 0;
85127
uint8_t dataLen = len + (addr_10bit?2:1);
86128
address = (address << 1);
87129

130+
if(i2c == NULL){
131+
return 4;
132+
}
133+
134+
I2C_MUTEX_LOCK();
135+
88136
while(dataLen) {
89137
uint8_t willSend = (dataLen > 32)?32:dataLen;
90138
uint8_t dataSend = willSend;
@@ -129,18 +177,21 @@ int i2cWrite(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uin
129177
//Bus failed (maybe check for this while waiting?
130178
if(i2c->dev->int_raw.arbitration_lost) {
131179
//log_e("Bus Fail! Addr: %x", address >> 1);
180+
I2C_MUTEX_UNLOCK();
132181
return 4;
133182
}
134183

135184
//Bus timeout
136185
if(i2c->dev->int_raw.time_out) {
137186
//log_e("Bus Timeout! Addr: %x", address >> 1);
187+
I2C_MUTEX_UNLOCK();
138188
return 3;
139189
}
140190

141191
//Transmission did not finish and ACK_ERR is set
142192
if(i2c->dev->int_raw.ack_err) {
143193
//log_e("Ack Error! Addr: %x", address >> 1);
194+
I2C_MUTEX_UNLOCK();
144195
return 1;
145196
}
146197

@@ -152,6 +203,7 @@ int i2cWrite(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uin
152203
}
153204

154205
}
206+
I2C_MUTEX_UNLOCK();
155207
return 0;
156208
}
157209

@@ -163,6 +215,12 @@ int i2cRead(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint
163215
uint8_t cmdIdx;
164216
uint8_t willRead;
165217

218+
if(i2c == NULL){
219+
return 4;
220+
}
221+
222+
I2C_MUTEX_LOCK();
223+
166224
i2cResetFiFo(i2c);
167225

168226
//CMD START
@@ -204,18 +262,21 @@ int i2cRead(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint
204262
//Bus failed (maybe check for this while waiting?
205263
if(i2c->dev->int_raw.arbitration_lost) {
206264
//log_e("Bus Fail! Addr: %x", address >> 1);
265+
I2C_MUTEX_UNLOCK();
207266
return -4;
208267
}
209268

210269
//Bus timeout
211270
if(i2c->dev->int_raw.time_out) {
212271
//log_e("Bus Timeout! Addr: %x", address >> 1);
272+
I2C_MUTEX_UNLOCK();
213273
return -3;
214274
}
215275

216276
//Transmission did not finish and ACK_ERR is set
217277
if(i2c->dev->int_raw.ack_err) {
218278
//log_e("Ack Error! Addr: %x", address >> 1);
279+
I2C_MUTEX_UNLOCK();
219280
return -1;
220281
}
221282
if(i2c->dev->ctr.trans_start || i2c->dev->status_reg.bus_busy || !(i2c->dev->int_raw.trans_complete) || !(i2c->dev->command[cmdIdx-1].done)) {
@@ -232,22 +293,19 @@ int i2cRead(i2c_t * i2c, uint16_t address, bool addr_10bit, uint8_t * data, uint
232293
}
233294
len -= willRead;
234295
}
296+
I2C_MUTEX_UNLOCK();
235297
return 0;
236298
}
237299

238-
void i2cResetFiFo(i2c_t * i2c)
239-
{
240-
//TX FIFO
241-
i2c->dev->fifo_conf.tx_fifo_rst = 1;
242-
i2c->dev->fifo_conf.tx_fifo_rst = 0;
243-
//RX FIFO
244-
i2c->dev->fifo_conf.rx_fifo_rst = 1;
245-
i2c->dev->fifo_conf.rx_fifo_rst = 0;
246-
}
247-
248300
void i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed)
249301
{
250302
uint32_t period = (APB_CLK_FREQ/clk_speed) / 2;
303+
304+
if(i2c == NULL){
305+
return;
306+
}
307+
308+
I2C_MUTEX_LOCK();
251309
i2c->dev->scl_low_period.scl_low_period = period;
252310
i2c->dev->scl_high_period.period = period;
253311

@@ -259,10 +317,15 @@ void i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed)
259317

260318
i2c->dev->sda_hold.time = 25;
261319
i2c->dev->sda_sample.time = 25;
320+
I2C_MUTEX_UNLOCK();
262321
}
263322

264323
uint32_t i2cGetFrequency(i2c_t * i2c)
265324
{
325+
if(i2c == NULL){
326+
return 0;
327+
}
328+
266329
return APB_CLK_FREQ/(i2c->dev->scl_low_period.scl_low_period+i2c->dev->scl_high_period.period);
267330
}
268331

@@ -274,18 +337,23 @@ uint32_t i2cGetFrequency(i2c_t * i2c)
274337

275338
i2c_t * i2cInit(uint8_t i2c_num, uint16_t slave_addr, bool addr_10bit_en)
276339
{
277-
i2c_t* i2c = (i2c_t*) malloc(sizeof(i2c_t));
278-
if(i2c == 0) {
340+
if(i2c_num > 1){
279341
return NULL;
280342
}
281343

282-
i2c->num = i2c_num;
283-
i2c->dev = I2C_DEV(i2c_num);
344+
i2c_t * i2c = &_i2c_bus_array[i2c_num];
345+
346+
if(i2c->lock == NULL){
347+
i2c->lock = xSemaphoreCreateMutex();
348+
if(i2c->lock == NULL) {
349+
return NULL;
350+
}
351+
}
284352

285-
if(i2c->num == 0) {
353+
if(i2c_num == 0) {
286354
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,DPORT_I2C_EXT0_CLK_EN);
287355
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT0_RST);
288-
} else if(i2c->num == 1) {
356+
} else {
289357
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,DPORT_I2C_EXT1_CLK_EN);
290358
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT1_RST);
291359
}

cores/esp32/esp32-hal-i2c.h

+2-6
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,14 @@ extern "C" {
2222
#include "esp32-hal.h"
2323
#include "soc/i2c_struct.h"
2424

25-
typedef struct {
26-
i2c_dev_t * dev;
27-
uint8_t num;
28-
} i2c_t;
25+
struct i2c_struct_t;
26+
typedef struct i2c_struct_t i2c_t;
2927

3028
i2c_t * i2cInit(uint8_t i2c_num, uint16_t slave_addr, bool addr_10bit_en);
3129

3230
void i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed);
3331
uint32_t i2cGetFrequency(i2c_t * i2c);
3432

35-
void i2cResetFiFo(i2c_t * i2c);
36-
3733
void i2cAttachSCL(i2c_t * i2c, int8_t scl);
3834
void i2cDetachSCL(i2c_t * i2c, int8_t scl);
3935
void i2cAttachSDA(i2c_t * i2c, int8_t sda);

0 commit comments

Comments
 (0)