diff --git a/cores/esp32/esp32-hal-i2c.c b/cores/esp32/esp32-hal-i2c.c index 742194d2015..09c6caf91a4 100644 --- a/cores/esp32/esp32-hal-i2c.c +++ b/cores/esp32/esp32-hal-i2c.c @@ -64,16 +64,16 @@ enum { #define I2C_MUTEX_UNLOCK() static i2c_t _i2c_bus_array[2] = { - {(volatile i2c_dev_t *)(DR_REG_I2C_EXT_BASE_FIXED), 0,I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0}, - {(volatile i2c_dev_t *)(DR_REG_I2C1_EXT_BASE_FIXED), 1,I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0} + {(volatile i2c_dev_t *)(DR_REG_I2C_EXT_BASE_FIXED), 0,I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0,0}, + {(volatile i2c_dev_t *)(DR_REG_I2C1_EXT_BASE_FIXED), 1,I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0,0} }; #else #define I2C_MUTEX_LOCK() do {} while (xSemaphoreTake(i2c->lock, portMAX_DELAY) != pdPASS) #define I2C_MUTEX_UNLOCK() xSemaphoreGive(i2c->lock) static i2c_t _i2c_bus_array[2] = { - {(volatile i2c_dev_t *)(DR_REG_I2C_EXT_BASE_FIXED), NULL, 0,I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0}, - {(volatile i2c_dev_t *)(DR_REG_I2C1_EXT_BASE_FIXED), NULL, 1,I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0} + {(volatile i2c_dev_t *)(DR_REG_I2C_EXT_BASE_FIXED), NULL, 0,I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0,0}, + {(volatile i2c_dev_t *)(DR_REG_I2C1_EXT_BASE_FIXED), NULL, 1,I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0,0} }; #endif @@ -82,6 +82,8 @@ functional with Silicon date=0x16042000 */ 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){ + if(i2c==NULL) return I2C_ERROR_DEV; + I2C_DATA_QUEUE_t dqx; dqx.data = dataPtr; dqx.length = dataLen; @@ -100,6 +102,7 @@ if(event){// an eventGroup exist, so, initialize it } if(i2c->dq!=NULL){ // expand +//log_i("expand"); I2C_DATA_QUEUE_t* tq =(I2C_DATA_QUEUE_t*)realloc(i2c->dq,sizeof(I2C_DATA_QUEUE_t)*(i2c->queueCount +1)); if(tq!=NULL){// ok i2c->dq = tq; @@ -111,6 +114,7 @@ if(i2c->dq!=NULL){ // expand } } else { // first Time +//log_i("new"); i2c->queueCount=0; i2c->dq =(I2C_DATA_QUEUE_t*)malloc(sizeof(I2C_DATA_QUEUE_t)); if(i2c->dq!=NULL){ @@ -125,10 +129,12 @@ return I2C_ERROR_OK; } i2c_err_t i2cFreeQueue(i2c_t * i2c){ +if(i2c==NULL) return I2C_ERROR_DEV; // need to grab a MUTEX for exclusive Queue, // what out if ISR is running? i2c_err_t rc=I2C_ERROR_OK; if(i2c->dq!=NULL){ +// log_i("free"); // what about EventHandle? free(i2c->dq); i2c->dq = NULL; @@ -319,6 +325,9 @@ i2c_t * i2cInit(uint8_t i2c_num) //before this is called, pins should be detache } #endif I2C_MUTEX_LOCK(); + + i2cReleaseISR(i2c); // ISR exists, release it before disabling hardware + uint32_t old_clock = i2cGetFrequency(i2c); if(i2c_num == 0) { @@ -348,7 +357,7 @@ i2c_t * i2cInit(uint8_t i2c_num) //before this is called, pins should be detache return i2c; } - +/* unused 03/15/2018 void i2cInitFix(i2c_t * i2c){ if(i2c == NULL){ return; @@ -370,7 +379,8 @@ void i2cInitFix(i2c_t * i2c){ while ((!i2c->dev->command[2].done) && (--count > 0)); I2C_MUTEX_UNLOCK(); } - +/* + unused 03/15/2018 void i2cReset(i2c_t* i2c){ if(i2c == NULL){ return; @@ -382,6 +392,7 @@ void i2cReset(i2c_t* i2c){ periph_module_enable( moduleId ); I2C_MUTEX_UNLOCK(); } +*/ /* Stickbreaker ISR mode debug support */ @@ -615,10 +626,19 @@ log_n("Enable Core Debug Level \"Error\""); #endif } - void i2cDumpI2c(i2c_t * i2c){ log_e("i2c=%p",i2c); -log_e("dev=%p date=%p",i2c->dev,i2c->dev->date); +char levelText[8]; +switch(ARDUHAL_LOG_LEVEL){ + case 0 : sprintf(levelText,"NONE"); break; + case 1 : sprintf(levelText,"ERROR"); break; + case 2 : sprintf(levelText,"WARN"); break; + case 3 : sprintf(levelText,"INFO"); break; + case 4 : sprintf(levelText,"DEBUG"); break; + case 5 : sprintf(levelText,"VERBOSE"); break; + default : sprintf(levelText,"uk=%d",ARDUHAL_LOG_LEVEL); +} +log_e("dev=%p date=%p level=%s",i2c->dev,i2c->dev->date,levelText); #if !CONFIG_DISABLE_HAL_LOCKS log_e("lock=%p",i2c->lock); #endif @@ -810,12 +830,13 @@ static void IRAM_ATTR i2c_isr_handler_default(void* arg){ i2c_t* p_i2c = (i2c_t*) arg; // recover data uint32_t activeInt = p_i2c->dev->int_status.val&0x1FFF; -portBASE_TYPE HPTaskAwoken = pdFALSE,xResult; +portBASE_TYPE HPTaskAwoken = pdFALSE; if(p_i2c->stage==I2C_DONE){ //get Out log_e("eject int=%p, ena=%p",activeInt,p_i2c->dev->int_ena.val); p_i2c->dev->int_ena.val = 0; p_i2c->dev->int_clr.val = activeInt; //0x1FFF; + return; } while (activeInt != 0) { // Ordering of 'if(activeInt)' statements is important, don't change @@ -833,8 +854,7 @@ while (activeInt != 0) { // Ordering of 'if(activeInt)' statements is important, intBuff[intPos[p_i2c->num]][2][p_i2c->num] = xTaskGetTickCountFromISR(); // when IRQ fired #endif - uint32_t oldInt =activeInt; - + if (activeInt & I2C_TRANS_START_INT_ST_M) { // p_i2c->byteCnt=0; if(p_i2c->stage==I2C_STARTUP){ @@ -960,7 +980,6 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis) install ISR if necessary setup EventGroup handle bus busy? - do I load command[] or just pass that off to the ISR */ //log_e("procQueue i2c=%p",&i2c); *readCount = 0; //total reads accomplished in all queue elements @@ -968,11 +987,24 @@ if(i2c == NULL){ return I2C_ERROR_DEV; } if (i2c->dev->status_reg.bus_busy){ // return error, let TwoWire() handle resetting the hardware. +/* if multi master then this if should be changed to this 03/12/2018 + if(multiMaster){// try to let the bus clear by its self + uint32_t timeOutTick = millis(); + while((i2c->dev->status_reg.bus_busy)&&(millis()-timeOutTickdev->status_reg.bus_busy){ // still busy, so die + log_i("Bus busy, reinit"); + return I2C_ERROR_BUSY; + } +*/ log_i("Bus busy, reinit"); return I2C_ERROR_BUSY; } + I2C_MUTEX_LOCK(); -/* what about co-existance with SLAVE mode? +/* what about co-existence with SLAVE mode? Should I check if a slaveMode xfer is in progress and hang until it completes? if i2c->stage == I2C_RUNNING or I2C_SLAVE_ACTIVE @@ -987,16 +1019,14 @@ for(uint16_t i=0;inum] = 0; #endif -// EventGroup is used to signal transmisison completion from ISR +// EventGroup is used to signal transmission completion from ISR // not always reliable. Sometimes, the FreeRTOS scheduler is maxed out and refuses request // if that happens, this call hangs until the timeout period expires, then it continues. if(!i2c->i2c_event){ i2c->i2c_event = xEventGroupCreate(); } if(i2c->i2c_event) { - uint32_t ret=xEventGroupClearBits(i2c->i2c_event, 0xFF); - -// log_e("after clearBits(%p)=%p",i2c->i2c_event,ret); + xEventGroupClearBits(i2c->i2c_event, 0xFF); } else {// failed to create EventGroup log_e("eventCreate failed=%p",i2c->i2c_event); @@ -1032,7 +1062,7 @@ i2c->queuePos=0; i2c->byteCnt=0; uint32_t totalBytes=0; // total number of bytes to be Moved! // convert address field to required I2C format -while(i2c->queuePos < i2c->queueCount){ +while(i2c->queuePos < i2c->queueCount){ // need to push these address modes upstream, to AddQueue I2C_DATA_QUEUE_t *tdq = &i2c->dq[i2c->queuePos++]; uint16_t taddr=0; if(tdq->ctrl.addrReq ==2){ // 10bit address @@ -1073,8 +1103,8 @@ i2c->dev->int_ena.val = I2C_RXFIFO_FULL_INT_ENA; // (BIT(0)) trigger emptyRxFifo() if(!i2c->intr_handle){ // create ISR for either peripheral - log_i("create ISR"); - uint32_t ret; + // log_i("create ISR %d",i2c->num); + uint32_t ret=0xFFFFFFFF; // clear uninitialized var warning switch(i2c->num){ case 0: ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, 0, &i2c_isr_handler_default, i2c, &i2c->intr_handle); @@ -1129,15 +1159,6 @@ if(!(eBits==EVENT_DONE)&&(eBits&~(EVENT_ERROR_NAK|EVENT_ERROR_DATA_NAK|EVENT_ERR } if(eBits&EVENT_DONE){ // no gross timeout -#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG - uint32_t expected =(totalBytes*10*1000)/i2cGetFrequency(i2c); - if((tAfter-tBefore)>(expected+1)) { //used some of the timeout Period - // expected can be zero due to small packets - log_e("TimeoutRecovery: expected=%ums, actual=%ums",expected,(tAfter-tBefore)); - i2cDumpI2c(i2c); - i2cDumpInts(i2c->num); - } -#endif switch(i2c->error){ case I2C_OK : reason = I2C_ERROR_OK; @@ -1218,19 +1239,40 @@ I2C_MUTEX_UNLOCK(); return reason; } -i2c_err_t i2cReleaseISR(i2c_t * i2c){ +void i2cReleaseISR(i2c_t * i2c){ if(i2c->intr_handle){ +// log_i("Release ISR %d",i2c->num); esp_err_t error =esp_intr_free(i2c->intr_handle); -// log_e("released ISR=%d",error); + if(error!=ESP_OK) log_e("Error releasing ISR=%d",error); i2c->intr_handle=NULL; } +} + +void i2cReleaseAll(i2c_t *i2c){ // release all resources, power down peripheral +// gpio pins must be released BEFORE this function or a Glitch will appear + +I2C_MUTEX_LOCK(); + +i2cReleaseISR(i2c); + if(i2c->i2c_event){ vEventGroupDelete(i2c->i2c_event); i2c->i2c_event = NULL; } -return i2cFreeQueue(i2c); -} +i2cFreeQueue(i2c); + +// reset the I2C hardware and shut off the clock, power it down. +if(i2c->num == 0) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT0_RST); //reset hardware + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,DPORT_I2C_EXT0_CLK_EN); // shutdown hardware +} else { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT1_RST); //reset Hardware + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,DPORT_I2C_EXT1_CLK_EN); // shutdown Hardware + } + +I2C_MUTEX_UNLOCK(); +} /* todo 24Nov17 Need to think about not usings I2C_MASTER_TRAN_COMP_INT_ST to adjust queuePos. This diff --git a/cores/esp32/esp32-hal-i2c.h b/cores/esp32/esp32-hal-i2c.h index 97230622a4b..453473e5844 100644 --- a/cores/esp32/esp32-hal-i2c.h +++ b/cores/esp32/esp32-hal-i2c.h @@ -148,11 +148,12 @@ typedef struct i2c_struct_t i2c_t; i2c_t * i2cInit(uint8_t i2c_num); +/* unused, 03/18/2018 fixed with V0.2.0 //call this after you setup the bus and pins to send empty packet //required because when pins are attached, they emit pulses that lock the bus void i2cInitFix(i2c_t * i2c); - void i2cReset(i2c_t* i2c); +*/ i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed); uint32_t i2cGetFrequency(i2c_t * i2c); @@ -167,7 +168,7 @@ i2c_err_t i2cProcQueue(i2c_t *i2c, uint32_t *readCount, uint16_t timeOutMillis); i2c_err_t i2cAddQueueWrite(i2c_t *i2c, uint16_t i2cDeviceAddr, uint8_t *dataPtr, uint16_t dataLen, bool SendStop, EventGroupHandle_t event); i2c_err_t i2cAddQueueRead(i2c_t *i2c, uint16_t i2cDeviceAddr, uint8_t *dataPtr, uint16_t dataLen, bool SendStop, EventGroupHandle_t event); i2c_err_t i2cFreeQueue(i2c_t *i2c); -i2c_err_t i2cReleaseISR(i2c_t *i2c); +void i2cReleaseAll(i2c_t *i2c); // free ISR, Free DQ, Power off peripheral clock. Must call i2cInit(),i2cSetFrequency() to recover //stickbreaker debug support void i2cDumpInts(uint8_t num); void i2cDumpI2c(i2c_t *i2c); diff --git a/docs/stickbreaker/ESP32DE_16.jpg b/docs/stickbreaker/ESP32DE_16.jpg new file mode 100644 index 00000000000..de609647183 Binary files /dev/null and b/docs/stickbreaker/ESP32DE_16.jpg differ diff --git a/docs/stickbreaker/ESP32DE_17.jpg b/docs/stickbreaker/ESP32DE_17.jpg new file mode 100644 index 00000000000..044b5e80f44 Binary files /dev/null and b/docs/stickbreaker/ESP32DE_17.jpg differ diff --git a/docs/stickbreaker/ESP32DE_18.jpg b/docs/stickbreaker/ESP32DE_18.jpg new file mode 100644 index 00000000000..4dbc4622373 Binary files /dev/null and b/docs/stickbreaker/ESP32DE_18.jpg differ diff --git a/docs/stickbreaker/README.md b/docs/stickbreaker/README.md new file mode 100644 index 00000000000..fb2a0a915bf --- /dev/null +++ b/docs/stickbreaker/README.md @@ -0,0 +1,6 @@ +# Stickbreaker Branch specific info. + +content: +* [ESP32DE_17.jpg](https://github.com/stickbreaker/arduino-esp32/blob/master/docs/stickbreaker/ESP32DE_17.jpg): Original Signal glitch on GPIO attach to peripheral +* [ESP32DE_16.jpg](https://github.com/stickbreaker/arduino-esp32/blob/master/docs/stickbreaker/ESP32DE_16.jpg): After changes suggested by @ESP32DE, over 50% reduction in glitch duration +* [ESP32DE_18.jpg](https://github.com/stickbreaker/arduino-esp32/blob/master/docs/stickbreaker/ESP32DE_18.jpg): Complete glitch prevention after additional experimentation by @stickbreaker diff --git a/libraries/Wire/docs/README.md b/libraries/Wire/docs/README.md index 1633c17ee1f..ec490dad2ab 100644 --- a/libraries/Wire/docs/README.md +++ b/libraries/Wire/docs/README.md @@ -100,7 +100,7 @@ Wire.write(highByte(addr)); Wire.write(lowByte(addr)); uint8_t count=Wire.transact(len); // transact() does both Wire.endTransmission(false); and Wire.requestFrom(ID,len,true); -if(Wire.lastError != 0){ // complete/partial read failure +if(Wire.lastError() != 0){ // complete/partial read failure Serial.printf("Bad Stuff!! Read Failed lastError=%d\n",Wire.lastError()); } // some of the read may have executed @@ -118,13 +118,13 @@ Most were caused by incorrect coding of ReSTART operations, but, a Valid TimeOut The current library signals this occurence by returning I2C_ERROR_OK and a dataLength of 0(zero) back through the `Wire.requestFrom()` call. -### Alpha +### Beta -This **APLHA** release should be compiled with ESP32 Dev Module as its target, and -Set the "core debug level" to 'error' +This **BETA** release can be compiled with ESP32 Dev Module as its target. Selecting this board allow Core Debug Level to be selected. Setting the "core debug level" to 'error' will route verbose debug out Serial (uart0) when an i2c error occurs. -There is MINIMAL to NO ERROR detection, BUS, BUSY. because I have not encounter any of them! +This version V0.2.0 14MAR2018 includes code to handle `BUS_BUSY` conditions. This status is usually indicative of a hardware bus glitch. The most common way for a `BUS_BUSY` condition to be created, is when the i2c peripheral has detected a low going spike on SDA and intrepreted it as another i2c MASTER device acquiring the bus. It will wait FORE EVER for the other 'Master' to complete it's transaction. Since this was a temporary signal glitch, not a secondary Master preforming operations, the only way to clear the `BUS_BUSY` condition is to reset the i2c peripheral. So, when a `BUS_BUSY` conditions is detected, a hardware reset is performed. +This works great, as long as, there is not ACTUALLY another Master on the bus. If this Library is used in a Multi-Master i2c configuration, it will FAIL with continuous `ARBITRATION` failures, `BUS_BUSY` errors. Chuck. - \ No newline at end of file + diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index c2faa2d5c3d..d504d977c7c 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -50,27 +50,49 @@ TwoWire::TwoWire(uint8_t bus_num) ,_dump(false) {} +TwoWire::~TwoWire(){ +flush(); +i2cDetachSCL(i2c,scl); // detach pins before resetting I2C perpherial +i2cDetachSDA(i2c,sda); // else a glitch will appear on the i2c bus +if(i2c){ + i2cReleaseAll(i2c); + i2c=NULL; + } +} + void TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency) { - if(sdaPin < 0) { - if(num == 0) { - sdaPin = SDA; - } else { - return; - } + if(sdaPin < 0) { // default param passed + if(num == 0) { + if(sda==-1) sdaPin = SDA; //use Default Pin + else sdaPin = sda; // reuse prior pin + } + else { + if(sda==-1) { + log_e("no Default SDA Pin for Second Peripheral"); + return; //no Default pin for Second Peripheral + } + else sdaPin = sda; // reuse prior pin + } } - if(sclPin < 0) { - if(num == 0) { - sclPin = SCL; - } else { - return; + if(sclPin < 0) { // default param passed + if(num == 0) { + if(scl==-1) sclPin = SCL; // use Default pin + else sclPin = scl; // reuse prior pin + } + else { + if(scl==-1){ + log_e("no Default SCL Pin for Second Peripheral"); + return; //no Default pin for Second Peripheral } + else sclPin = scl; // reuse prior pin + } } - - if(!initHardware(sdaPin, sclPin, frequency)) return; - flush(); + if(!initHardware(sdaPin, sclPin, frequency)) return; + + flush(); } @@ -87,8 +109,6 @@ void TwoWire::setClock(uint32_t frequency) i2cSetFrequency(i2c, frequency); } -/*@StickBreaker common handler for processing the queued commands -*/ bool TwoWire::initHardware(int sdaPin, int sclPin, uint32_t frequency){ i2cDetachSCL(i2c,scl); // detach pins before resetting I2C perpherial @@ -97,11 +117,19 @@ bool TwoWire::initHardware(int sdaPin, int sclPin, uint32_t frequency){ if(i2c == NULL) { return false; } - + + if(frequency==0) {// don't change existing frequency + frequency = i2cGetFrequency(i2c); + } + if(frequency==0) frequency = 100000L; // default to 100khz + i2cSetFrequency(i2c, frequency); sda = sdaPin; scl = sclPin; + +// 03/15/2018 What about MultiMaster? How can I be polite and still catch glitches? + // 03/10/2018 test I2C bus before attach. // if the bus is not 'clear' try the recommended recovery sequence, START, 9 Clocks, STOP digitalWrite(sda,HIGH); @@ -110,7 +138,7 @@ bool TwoWire::initHardware(int sdaPin, int sclPin, uint32_t frequency){ pinMode(scl,PULLUP|OPEN_DRAIN|OUTPUT|INPUT); if(!digitalRead(sda)||!digitalRead(scl)){ // bus in busy state - // Serial.printf("invalid state sda=%d, scl=%d\n",digitalRead(sda),digitalRead(scl)); + log_e("invalid state sda=%d, scl=%d\n",digitalRead(sda),digitalRead(scl)); digitalWrite(sda,HIGH); digitalWrite(scl,HIGH); delayMicroseconds(5); @@ -128,13 +156,15 @@ bool TwoWire::initHardware(int sdaPin, int sclPin, uint32_t frequency){ i2cAttachSCL(i2c, scl); if(!digitalRead(sda)||!digitalRead(scl)){ // bus in busy state -// Serial.println("Bus Invalid State, TwoWire() Can't init"); + log_e("Bus Invalid State, TwoWire() Can't init"); return false; // bus is busy } return true; } +/*@StickBreaker common handler for processing the queued commands +*/ i2c_err_t TwoWire::processQueue(uint32_t * readCount){ last_error=i2cProcQueue(i2c,readCount,_timeOutMillis); 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 */ i2c_err_t TwoWire::writeTransmission(uint16_t address, uint8_t *buff, uint16_t size, bool sendStop){ // will destroy any partially created beginTransaction() - +log_i("i2c=%p",i2c); last_error=i2cAddQueueWrite(i2c,address,buff,size,sendStop,NULL); if(last_error==I2C_ERROR_OK){ //queued @@ -466,12 +496,5 @@ void TwoWire::flush(void) i2cFreeQueue(i2c); // cleanup } -void TwoWire::reset(void) -{ - i2cReleaseISR(i2c); // remove ISR from Interrupt chain,Delete EventGroup,Free Heap memory - i2cReset( i2c ); - i2c = NULL; - begin( sda, scl ); -} TwoWire Wire = TwoWire(0); diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index 04c53505b4e..09c2ac6d4bb 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -30,7 +30,7 @@ #include "freertos/queue.h" #include "Stream.h" -#define STICKBREAKER +#define STICKBREAKER "V0.2.3" #define I2C_BUFFER_LENGTH 128 typedef void(*user_onRequest)(void); typedef void(*user_onReceive)(uint8_t*, int); @@ -69,8 +69,11 @@ class TwoWire: public Stream public: TwoWire(uint8_t bus_num); - void begin(int sda=-1, int scl=-1, uint32_t frequency=100000); - void setClock(uint32_t); + ~TwoWire(); + void begin(int sda=-1, int scl=-1, uint32_t frequency=0); + //defaults bus:0 sda=SDA, scl=SCL, frequency =100khz via variant pins_arduino.h + // bus:1 unspecified, emits Log_E() + void setClock(uint32_t); // change bus clock without initing hardware void beginTransmission(uint16_t); uint8_t endTransmission(bool); uint8_t requestFrom(uint16_t address, uint8_t size, bool sendStop); @@ -87,7 +90,7 @@ class TwoWire: public Stream bool getDump(){return _dump;} void dumpInts(); void dumpI2C(){i2cDumpI2c(i2c);} - size_t getClock(); + size_t getClock(); // current bus clock rate in hz void setTimeOut(uint16_t timeOutMillis); uint16_t getTimeOut(); // @@ -113,8 +116,6 @@ class TwoWire: public Stream int peek(void); void flush(void); - void reset(void); - inline size_t write(const char * s) { return write((uint8_t*) s, strlen(s)); @@ -139,4 +140,9 @@ class TwoWire: public Stream extern TwoWire Wire; + +/* +V0.2.2 13APR2018 preserve custom SCL,SDA,Frequency when no parameters passed to begin() +V0.2.1 15MAR2018 Hardware reset, Glitch prevention, adding destructor for second i2c testing +*/ #endif