Skip to content

Commit fc33cc0

Browse files
authored
Merge pull request #27 from stickbreaker/Wire-Destructor
Create Destructor for Wire Class. Preserve Custom SCL, SDA across `Wire.begin()` default calls.
2 parents fbb85f6 + 68185a0 commit fc33cc0

File tree

4 files changed

+119
-48
lines changed

4 files changed

+119
-48
lines changed

cores/esp32/esp32-hal-i2c.c

Lines changed: 54 additions & 13 deletions
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

Lines changed: 3 additions & 2 deletions
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);

libraries/Wire/src/Wire.cpp

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -50,27 +50,49 @@ TwoWire::TwoWire(uint8_t bus_num)
5050
,_dump(false)
5151
{}
5252

53+
TwoWire::~TwoWire(){
54+
flush();
55+
i2cDetachSCL(i2c,scl); // detach pins before resetting I2C perpherial
56+
i2cDetachSDA(i2c,sda); // else a glitch will appear on the i2c bus
57+
if(i2c){
58+
i2cReleaseAll(i2c);
59+
i2c=NULL;
60+
}
61+
}
62+
5363
void TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency)
5464
{
55-
if(sdaPin < 0) {
56-
if(num == 0) {
57-
sdaPin = SDA;
58-
} else {
59-
return;
60-
}
65+
if(sdaPin < 0) { // default param passed
66+
if(num == 0) {
67+
if(sda==-1) sdaPin = SDA; //use Default Pin
68+
else sdaPin = sda; // reuse prior pin
69+
}
70+
else {
71+
if(sda==-1) {
72+
log_e("no Default SDA Pin for Second Peripheral");
73+
return; //no Default pin for Second Peripheral
74+
}
75+
else sdaPin = sda; // reuse prior pin
76+
}
6177
}
6278

63-
if(sclPin < 0) {
64-
if(num == 0) {
65-
sclPin = SCL;
66-
} else {
67-
return;
79+
if(sclPin < 0) { // default param passed
80+
if(num == 0) {
81+
if(scl==-1) sclPin = SCL; // use Default pin
82+
else sclPin = scl; // reuse prior pin
83+
}
84+
else {
85+
if(scl==-1){
86+
log_e("no Default SCL Pin for Second Peripheral");
87+
return; //no Default pin for Second Peripheral
6888
}
89+
else sclPin = scl; // reuse prior pin
90+
}
6991
}
70-
71-
if(!initHardware(sdaPin, sclPin, frequency)) return;
7292

73-
flush();
93+
if(!initHardware(sdaPin, sclPin, frequency)) return;
94+
95+
flush();
7496

7597
}
7698

@@ -87,8 +109,6 @@ void TwoWire::setClock(uint32_t frequency)
87109
i2cSetFrequency(i2c, frequency);
88110
}
89111

90-
/*@StickBreaker common handler for processing the queued commands
91-
*/
92112
bool TwoWire::initHardware(int sdaPin, int sclPin, uint32_t frequency){
93113

94114
i2cDetachSCL(i2c,scl); // detach pins before resetting I2C perpherial
@@ -97,11 +117,19 @@ bool TwoWire::initHardware(int sdaPin, int sclPin, uint32_t frequency){
97117
if(i2c == NULL) {
98118
return false;
99119
}
100-
120+
121+
if(frequency==0) {// don't change existing frequency
122+
frequency = i2cGetFrequency(i2c);
123+
}
124+
if(frequency==0) frequency = 100000L; // default to 100khz
125+
101126
i2cSetFrequency(i2c, frequency);
102127

103128
sda = sdaPin;
104129
scl = sclPin;
130+
131+
// 03/15/2018 What about MultiMaster? How can I be polite and still catch glitches?
132+
105133
// 03/10/2018 test I2C bus before attach.
106134
// if the bus is not 'clear' try the recommended recovery sequence, START, 9 Clocks, STOP
107135
digitalWrite(sda,HIGH);
@@ -110,7 +138,7 @@ bool TwoWire::initHardware(int sdaPin, int sclPin, uint32_t frequency){
110138
pinMode(scl,PULLUP|OPEN_DRAIN|OUTPUT|INPUT);
111139

112140
if(!digitalRead(sda)||!digitalRead(scl)){ // bus in busy state
113-
// Serial.printf("invalid state sda=%d, scl=%d\n",digitalRead(sda),digitalRead(scl));
141+
log_e("invalid state sda=%d, scl=%d\n",digitalRead(sda),digitalRead(scl));
114142
digitalWrite(sda,HIGH);
115143
digitalWrite(scl,HIGH);
116144
delayMicroseconds(5);
@@ -128,13 +156,15 @@ bool TwoWire::initHardware(int sdaPin, int sclPin, uint32_t frequency){
128156
i2cAttachSCL(i2c, scl);
129157

130158
if(!digitalRead(sda)||!digitalRead(scl)){ // bus in busy state
131-
// Serial.println("Bus Invalid State, TwoWire() Can't init");
159+
log_e("Bus Invalid State, TwoWire() Can't init");
132160
return false; // bus is busy
133161
}
134162

135163
return true;
136164
}
137165

166+
/*@StickBreaker common handler for processing the queued commands
167+
*/
138168
i2c_err_t TwoWire::processQueue(uint32_t * readCount){
139169
last_error=i2cProcQueue(i2c,readCount,_timeOutMillis);
140170
if(last_error==I2C_ERROR_BUSY){ // try to clear the bus
@@ -199,7 +229,7 @@ uint16_t TwoWire::requestFrom(uint16_t address, uint8_t * readBuff, uint16_t siz
199229
*/
200230
i2c_err_t TwoWire::writeTransmission(uint16_t address, uint8_t *buff, uint16_t size, bool sendStop){
201231
// will destroy any partially created beginTransaction()
202-
232+
log_i("i2c=%p",i2c);
203233
last_error=i2cAddQueueWrite(i2c,address,buff,size,sendStop,NULL);
204234

205235
if(last_error==I2C_ERROR_OK){ //queued
@@ -466,12 +496,5 @@ void TwoWire::flush(void)
466496
i2cFreeQueue(i2c); // cleanup
467497
}
468498

469-
void TwoWire::reset(void)
470-
{
471-
i2cReleaseISR(i2c); // remove ISR from Interrupt chain,Delete EventGroup,Free Heap memory
472-
i2cReset( i2c );
473-
i2c = NULL;
474-
begin( sda, scl );
475-
}
476499

477500
TwoWire Wire = TwoWire(0);

0 commit comments

Comments
 (0)