Skip to content

Commit dd0ac4b

Browse files
authored
Support for Wire Destructor
These changes allow both i2c peripherals to be use, if a TwoWire() object is destroyed, the associated peripheral is reset and powered down.
1 parent c571e1b commit dd0ac4b

File tree

2 files changed

+57
-15
lines changed

2 files changed

+57
-15
lines changed

cores/esp32/esp32-hal-i2c.c

+54-13
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ functional with Silicon date=0x16042000
8282
*/
8383
static i2c_err_t i2cAddQueue(i2c_t * i2c,uint8_t mode, uint16_t i2cDeviceAddr, uint8_t *dataPtr, uint16_t dataLen,bool sendStop, EventGroupHandle_t event){
8484

85+
if(i2c==NULL) return I2C_ERROR_DEV;
86+
8587
I2C_DATA_QUEUE_t dqx;
8688
dqx.data = dataPtr;
8789
dqx.length = dataLen;
@@ -100,6 +102,7 @@ if(event){// an eventGroup exist, so, initialize it
100102
}
101103

102104
if(i2c->dq!=NULL){ // expand
105+
//log_i("expand");
103106
I2C_DATA_QUEUE_t* tq =(I2C_DATA_QUEUE_t*)realloc(i2c->dq,sizeof(I2C_DATA_QUEUE_t)*(i2c->queueCount +1));
104107
if(tq!=NULL){// ok
105108
i2c->dq = tq;
@@ -111,6 +114,7 @@ if(i2c->dq!=NULL){ // expand
111114
}
112115
}
113116
else { // first Time
117+
//log_i("new");
114118
i2c->queueCount=0;
115119
i2c->dq =(I2C_DATA_QUEUE_t*)malloc(sizeof(I2C_DATA_QUEUE_t));
116120
if(i2c->dq!=NULL){
@@ -125,10 +129,12 @@ return I2C_ERROR_OK;
125129
}
126130

127131
i2c_err_t i2cFreeQueue(i2c_t * i2c){
132+
if(i2c==NULL) return I2C_ERROR_DEV;
128133
// need to grab a MUTEX for exclusive Queue,
129134
// what out if ISR is running?
130135
i2c_err_t rc=I2C_ERROR_OK;
131136
if(i2c->dq!=NULL){
137+
// log_i("free");
132138
// what about EventHandle?
133139
free(i2c->dq);
134140
i2c->dq = NULL;
@@ -319,6 +325,9 @@ i2c_t * i2cInit(uint8_t i2c_num) //before this is called, pins should be detache
319325
}
320326
#endif
321327
I2C_MUTEX_LOCK();
328+
329+
i2cReleaseISR(i2c); // ISR exists, release it before disabling hardware
330+
322331
uint32_t old_clock = i2cGetFrequency(i2c);
323332

324333
if(i2c_num == 0) {
@@ -348,7 +357,7 @@ i2c_t * i2cInit(uint8_t i2c_num) //before this is called, pins should be detache
348357

349358
return i2c;
350359
}
351-
360+
/* unused 03/15/2018
352361
void i2cInitFix(i2c_t * i2c){
353362
if(i2c == NULL){
354363
return;
@@ -370,7 +379,8 @@ void i2cInitFix(i2c_t * i2c){
370379
while ((!i2c->dev->command[2].done) && (--count > 0));
371380
I2C_MUTEX_UNLOCK();
372381
}
373-
382+
/*
383+
unused 03/15/2018
374384
void i2cReset(i2c_t* i2c){
375385
if(i2c == NULL){
376386
return;
@@ -382,6 +392,7 @@ void i2cReset(i2c_t* i2c){
382392
periph_module_enable( moduleId );
383393
I2C_MUTEX_UNLOCK();
384394
}
395+
*/
385396

386397
/* Stickbreaker ISR mode debug support
387398
*/
@@ -615,7 +626,6 @@ log_n("Enable Core Debug Level \"Error\"");
615626
#endif
616627
}
617628

618-
619629
void i2cDumpI2c(i2c_t * i2c){
620630
log_e("i2c=%p",i2c);
621631
log_e("dev=%p date=%p",i2c->dev,i2c->dev->date);
@@ -960,19 +970,31 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
960970
install ISR if necessary
961971
setup EventGroup
962972
handle bus busy?
963-
do I load command[] or just pass that off to the ISR
964973
*/
965974
//log_e("procQueue i2c=%p",&i2c);
966975
*readCount = 0; //total reads accomplished in all queue elements
967976
if(i2c == NULL){
968977
return I2C_ERROR_DEV;
969978
}
970979
if (i2c->dev->status_reg.bus_busy){ // return error, let TwoWire() handle resetting the hardware.
980+
/* if multi master then this if should be changed to this 03/12/2018
981+
if(multiMaster){// try to let the bus clear by its self
982+
uint32_t timeOutTick = millis();
983+
while((i2c->dev->status_reg.bus_busy)&&(millis()-timeOutTick<timeOutMillis())){
984+
delay(2); // allow task switch
985+
}
986+
}
987+
if(i2c->dev->status_reg.bus_busy){ // still busy, so die
988+
log_i("Bus busy, reinit");
989+
return I2C_ERROR_BUSY;
990+
}
991+
*/
971992
log_i("Bus busy, reinit");
972993
return I2C_ERROR_BUSY;
973994
}
995+
974996
I2C_MUTEX_LOCK();
975-
/* what about co-existance with SLAVE mode?
997+
/* what about co-existence with SLAVE mode?
976998
Should I check if a slaveMode xfer is in progress and hang
977999
until it completes?
9781000
if i2c->stage == I2C_RUNNING or I2C_SLAVE_ACTIVE
@@ -987,16 +1009,14 @@ for(uint16_t i=0;i<INTBUFFMAX;i++){
9871009
}
9881010
intPos[i2c->num] = 0;
9891011
#endif
990-
// EventGroup is used to signal transmisison completion from ISR
1012+
// EventGroup is used to signal transmission completion from ISR
9911013
// not always reliable. Sometimes, the FreeRTOS scheduler is maxed out and refuses request
9921014
// if that happens, this call hangs until the timeout period expires, then it continues.
9931015
if(!i2c->i2c_event){
9941016
i2c->i2c_event = xEventGroupCreate();
9951017
}
9961018
if(i2c->i2c_event) {
9971019
uint32_t ret=xEventGroupClearBits(i2c->i2c_event, 0xFF);
998-
999-
// log_e("after clearBits(%p)=%p",i2c->i2c_event,ret);
10001020
}
10011021
else {// failed to create EventGroup
10021022
log_e("eventCreate failed=%p",i2c->i2c_event);
@@ -1032,7 +1052,7 @@ i2c->queuePos=0;
10321052
i2c->byteCnt=0;
10331053
uint32_t totalBytes=0; // total number of bytes to be Moved!
10341054
// convert address field to required I2C format
1035-
while(i2c->queuePos < i2c->queueCount){
1055+
while(i2c->queuePos < i2c->queueCount){ // need to push these address modes upstream, to AddQueue
10361056
I2C_DATA_QUEUE_t *tdq = &i2c->dq[i2c->queuePos++];
10371057
uint16_t taddr=0;
10381058
if(tdq->ctrl.addrReq ==2){ // 10bit address
@@ -1073,7 +1093,7 @@ i2c->dev->int_ena.val =
10731093
I2C_RXFIFO_FULL_INT_ENA; // (BIT(0)) trigger emptyRxFifo()
10741094

10751095
if(!i2c->intr_handle){ // create ISR for either peripheral
1076-
log_i("create ISR");
1096+
// log_i("create ISR %d",i2c->num);
10771097
uint32_t ret;
10781098
switch(i2c->num){
10791099
case 0:
@@ -1218,19 +1238,40 @@ I2C_MUTEX_UNLOCK();
12181238
return reason;
12191239
}
12201240

1221-
i2c_err_t i2cReleaseISR(i2c_t * i2c){
1241+
void i2cReleaseISR(i2c_t * i2c){
12221242
if(i2c->intr_handle){
1243+
// log_i("Release ISR %d",i2c->num);
12231244
esp_err_t error =esp_intr_free(i2c->intr_handle);
12241245
// log_e("released ISR=%d",error);
12251246
i2c->intr_handle=NULL;
12261247
}
1248+
}
1249+
1250+
void i2cReleaseAll(i2c_t *i2c){ // release all resources, power down peripheral
1251+
// gpio pins must be released BEFORE this function or a Glitch will appear
1252+
1253+
I2C_MUTEX_LOCK();
1254+
1255+
i2cReleaseISR(i2c);
1256+
12271257
if(i2c->i2c_event){
12281258
vEventGroupDelete(i2c->i2c_event);
12291259
i2c->i2c_event = NULL;
12301260
}
1231-
return i2cFreeQueue(i2c);
1232-
}
12331261

1262+
i2cFreeQueue(i2c);
1263+
1264+
// reset the I2C hardware and shut off the clock, power it down.
1265+
if(i2c->num == 0) {
1266+
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT0_RST); //reset hardware
1267+
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,DPORT_I2C_EXT0_CLK_EN); // shutdown hardware
1268+
} else {
1269+
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT1_RST); //reset Hardware
1270+
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,DPORT_I2C_EXT1_CLK_EN); // shutdown Hardware
1271+
}
1272+
1273+
I2C_MUTEX_UNLOCK();
1274+
}
12341275
/* todo
12351276
24Nov17
12361277
Need to think about not usings I2C_MASTER_TRAN_COMP_INT_ST to adjust queuePos. This

cores/esp32/esp32-hal-i2c.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,12 @@ typedef struct i2c_struct_t i2c_t;
148148

149149
i2c_t * i2cInit(uint8_t i2c_num);
150150

151+
/* unused, 03/18/2018 fixed with V0.2.0
151152
//call this after you setup the bus and pins to send empty packet
152153
//required because when pins are attached, they emit pulses that lock the bus
153154
void i2cInitFix(i2c_t * i2c);
154-
155155
void i2cReset(i2c_t* i2c);
156+
*/
156157

157158
i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed);
158159
uint32_t i2cGetFrequency(i2c_t * i2c);
@@ -167,7 +168,7 @@ i2c_err_t i2cProcQueue(i2c_t *i2c, uint32_t *readCount, uint16_t timeOutMillis);
167168
i2c_err_t i2cAddQueueWrite(i2c_t *i2c, uint16_t i2cDeviceAddr, uint8_t *dataPtr, uint16_t dataLen, bool SendStop, EventGroupHandle_t event);
168169
i2c_err_t i2cAddQueueRead(i2c_t *i2c, uint16_t i2cDeviceAddr, uint8_t *dataPtr, uint16_t dataLen, bool SendStop, EventGroupHandle_t event);
169170
i2c_err_t i2cFreeQueue(i2c_t *i2c);
170-
i2c_err_t i2cReleaseISR(i2c_t *i2c);
171+
void i2cReleaseAll(i2c_t *i2c); // free ISR, Free DQ, Power off peripheral clock. Must call i2cInit(),i2cSetFrequency() to recover
171172
//stickbreaker debug support
172173
void i2cDumpInts(uint8_t num);
173174
void i2cDumpI2c(i2c_t *i2c);

0 commit comments

Comments
 (0)