From 1f782bd12fbd64e909b5b1ad897177229b9b59e3 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 21 Dec 2019 11:11:27 -0600 Subject: [PATCH 1/6] change bus clock (busywait) to be programmable [issue 2524], remove unused slave STOP function --- cores/esp8266/core_esp8266_si2c.cpp | 104 +++++----------------------- 1 file changed, 19 insertions(+), 85 deletions(-) diff --git a/cores/esp8266/core_esp8266_si2c.cpp b/cores/esp8266/core_esp8266_si2c.cpp index 858cdda09a..267ccde2f0 100644 --- a/cores/esp8266/core_esp8266_si2c.cpp +++ b/cores/esp8266/core_esp8266_si2c.cpp @@ -63,7 +63,7 @@ class Twi { private: unsigned int preferred_si2c_clock = 100000; - unsigned char twi_dcount = 18; + uint32_t twi_dcount = 18; unsigned char twi_sda = 0; unsigned char twi_scl = 0; unsigned char twi_addr = 0; @@ -112,7 +112,7 @@ class Twi bool _slaveEnabled = false; // Internal use functions - void ICACHE_RAM_ATTR busywait(unsigned char v); + void ICACHE_RAM_ATTR busywait(unsigned int v); bool write_start(void); bool write_stop(void); bool write_bit(bool bit); @@ -148,7 +148,6 @@ class Twi void attachSlaveRxEvent(void (*function)(uint8_t*, size_t)); void attachSlaveTxEvent(void (*function)(void)); void ICACHE_RAM_ATTR reply(uint8_t ack); - void ICACHE_RAM_ATTR stop(void); void ICACHE_RAM_ATTR releaseBus(void); void enableSlave(); }; @@ -161,65 +160,22 @@ static Twi twi; void Twi::setClock(unsigned int freq) { - preferred_si2c_clock = freq; + preferred_si2c_clock = freq; + #if F_CPU == FCPU80 - if (freq <= 50000) - { - twi_dcount = 38; //about 50KHz - } - else if (freq <= 100000) - { - twi_dcount = 19; //about 100KHz - } - else if (freq <= 200000) - { - twi_dcount = 8; //about 200KHz - } - else if (freq <= 300000) - { - twi_dcount = 3; //about 300KHz - } - else if (freq <= 400000) - { - twi_dcount = 1; //about 400KHz - } - else - { - twi_dcount = 1; //about 400KHz - } + + if (freq > 400000) + freq = 400000; + twi_dcount = (500000000 / freq); // half-cycle period in ns + twi_dcount = (1000*(twi_dcount - 1120)) / 62500; // (half cycle - overhead) / busywait loop time + #else - if (freq <= 50000) - { - twi_dcount = 64; //about 50KHz - } - else if (freq <= 100000) - { - twi_dcount = 32; //about 100KHz - } - else if (freq <= 200000) - { - twi_dcount = 14; //about 200KHz - } - else if (freq <= 300000) - { - twi_dcount = 8; //about 300KHz - } - else if (freq <= 400000) - { - twi_dcount = 5; //about 400KHz - } - else if (freq <= 500000) - { - twi_dcount = 3; //about 500KHz - } - else if (freq <= 600000) - { - twi_dcount = 2; //about 600KHz - } - else - { - twi_dcount = 1; //about 700KHz - } + + if (freq > 800000) + freq = 800000; + twi_dcount = (500000000 / freq); // half-cycle period in ns + twi_dcount = (1000*(twi_dcount - 560)) / 31250; // (half cycle - overhead) / busywait loop time + #endif } @@ -262,18 +218,13 @@ void Twi::enableSlave() } } -void ICACHE_RAM_ATTR Twi::busywait(unsigned char v) + void ICACHE_RAM_ATTR Twi::busywait(unsigned int v) { unsigned int i; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" - unsigned int reg; - for (i = 0; i < v; i++) + for (i = 0; i < v; i++) // loop time is 5 machine cycles: 31.25ns @ 160MHz, 62.5ns @ 80MHz { - reg = GPI; + asm("nop"); // minimum element to keep GCC from optimizing this function out. } - (void)reg; -#pragma GCC diagnostic pop } bool Twi::write_start(void) @@ -529,17 +480,6 @@ void ICACHE_RAM_ATTR Twi::reply(uint8_t ack) } } -void ICACHE_RAM_ATTR Twi::stop(void) -{ - // send stop condition - //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); - SCL_HIGH(twi.twi_scl); // _BV(TWINT) - twi_ack = 1; // _BV(TWEA) - busywait(5); // Maybe this should be here - SDA_HIGH(twi.twi_sda); // _BV(TWSTO) - // update twi state - twi_state = TWI_READY; -} void ICACHE_RAM_ATTR Twi::releaseBus(void) { @@ -657,7 +597,6 @@ void ICACHE_RAM_ATTR Twi::onTwipEvent(uint8_t status) break; case TW_BUS_ERROR: // bus error, illegal stop/start twi_error = TW_BUS_ERROR; - stop(); break; } } @@ -1018,11 +957,6 @@ extern "C" { return twi.setAddress(a); } - void twi_stop(void) - { - twi.stop(); - } - void twi_setClock(unsigned int freq) { twi.setClock(freq); From a931e1d28aca42b72dda2af29c3b50ffab52ac9f Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 21 Dec 2019 11:34:57 -0600 Subject: [PATCH 2/6] change bus clock (busywait) to be programmable [issue 2524], remove unused slave STOP function --- cores/esp8266/core_esp8266_si2c.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/esp8266/core_esp8266_si2c.cpp b/cores/esp8266/core_esp8266_si2c.cpp index 267ccde2f0..e9a519b645 100644 --- a/cores/esp8266/core_esp8266_si2c.cpp +++ b/cores/esp8266/core_esp8266_si2c.cpp @@ -265,7 +265,7 @@ bool Twi::write_bit(bool bit) { SDA_LOW(twi_sda); } - busywait(twi_dcount + 1); + busywait(twi_dcount); SCL_HIGH(twi_scl); WAIT_CLOCK_STRETCH(); busywait(twi_dcount); @@ -276,7 +276,7 @@ bool Twi::read_bit(void) { SCL_LOW(twi_scl); SDA_HIGH(twi_sda); - busywait(twi_dcount + 2); + busywait(twi_dcount); SCL_HIGH(twi_scl); WAIT_CLOCK_STRETCH(); bool bit = SDA_READ(twi_sda); From 0d2b1309c1c509026edf2e0b69c1890f93ac0db8 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 21 Dec 2019 18:08:38 -0600 Subject: [PATCH 3/6] change bus clock (busywait) to be programmable [issue 2524], remove unused slave STOP function --- cores/esp8266/core_esp8266_si2c.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cores/esp8266/core_esp8266_si2c.cpp b/cores/esp8266/core_esp8266_si2c.cpp index e9a519b645..e89814d1f5 100644 --- a/cores/esp8266/core_esp8266_si2c.cpp +++ b/cores/esp8266/core_esp8266_si2c.cpp @@ -225,6 +225,11 @@ void Twi::enableSlave() { asm("nop"); // minimum element to keep GCC from optimizing this function out. } + +// { +// esp8266::polledTimeout::oneShotFastNs timeout(v); +// while(!timeout) { // +// } } bool Twi::write_start(void) @@ -265,7 +270,7 @@ bool Twi::write_bit(bool bit) { SDA_LOW(twi_sda); } - busywait(twi_dcount); + busywait(twi_dcount + 1); SCL_HIGH(twi_scl); WAIT_CLOCK_STRETCH(); busywait(twi_dcount); @@ -276,7 +281,7 @@ bool Twi::read_bit(void) { SCL_LOW(twi_scl); SDA_HIGH(twi_sda); - busywait(twi_dcount); + busywait(twi_dcount + 2); SCL_HIGH(twi_scl); WAIT_CLOCK_STRETCH(); bool bit = SDA_READ(twi_sda); From 387ca510cf3530e7fcececa5659f2f6fd70fc597 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sun, 22 Dec 2019 05:35:28 -0600 Subject: [PATCH 4/6] correct for underflow < 233Hz --- cores/esp8266/core_esp8266_si2c.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cores/esp8266/core_esp8266_si2c.cpp b/cores/esp8266/core_esp8266_si2c.cpp index e89814d1f5..51e6907825 100644 --- a/cores/esp8266/core_esp8266_si2c.cpp +++ b/cores/esp8266/core_esp8266_si2c.cpp @@ -160,6 +160,9 @@ static Twi twi; void Twi::setClock(unsigned int freq) { + if (freq < 250) // minimum freq 250Hz to prevent overflow @ 232Hz + freq = 250; + preferred_si2c_clock = freq; #if F_CPU == FCPU80 @@ -225,11 +228,6 @@ void Twi::enableSlave() { asm("nop"); // minimum element to keep GCC from optimizing this function out. } - -// { -// esp8266::polledTimeout::oneShotFastNs timeout(v); -// while(!timeout) { // -// } } bool Twi::write_start(void) From b22de4dae9647b5cb1c52382d82cac77173bd91f Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Mon, 23 Dec 2019 09:50:26 -0600 Subject: [PATCH 5/6] change bus clock (busywait) to be programmable [issue 2524], convert tabs to spaces --- cores/esp8266/core_esp8266_si2c.cpp | 54 ++++++++++++++--------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/cores/esp8266/core_esp8266_si2c.cpp b/cores/esp8266/core_esp8266_si2c.cpp index 51e6907825..9ae022fea7 100644 --- a/cores/esp8266/core_esp8266_si2c.cpp +++ b/cores/esp8266/core_esp8266_si2c.cpp @@ -40,8 +40,8 @@ extern "C" { { GPEC = (1 << twi_sda); } - static inline __attribute__((always_inline)) bool SDA_READ(const int twi_sda) - { + static inline __attribute__((always_inline)) bool SDA_READ(const int twi_sda) + { return (GPI & (1 << twi_sda)) != 0; } static inline __attribute__((always_inline)) void SCL_LOW(const int twi_scl) @@ -52,8 +52,8 @@ extern "C" { { GPEC = (1 << twi_scl); } - static inline __attribute__((always_inline)) bool SCL_READ(const int twi_scl) - { + static inline __attribute__((always_inline)) bool SCL_READ(const int twi_scl) + { return (GPI & (1 << twi_scl)) != 0; } @@ -160,22 +160,22 @@ static Twi twi; void Twi::setClock(unsigned int freq) { - if (freq < 250) // minimum freq 250Hz to prevent overflow @ 232Hz - freq = 250; - - preferred_si2c_clock = freq; + if (freq < 250) // minimum freq 250Hz to prevent overflow @ 232Hz + freq = 250; + + preferred_si2c_clock = freq; #if F_CPU == FCPU80 if (freq > 400000) - freq = 400000; + freq = 400000; twi_dcount = (500000000 / freq); // half-cycle period in ns twi_dcount = (1000*(twi_dcount - 1120)) / 62500; // (half cycle - overhead) / busywait loop time - + #else - if (freq > 800000) - freq = 800000; + if (freq > 800000) + freq = 800000; twi_dcount = (500000000 / freq); // half-cycle period in ns twi_dcount = (1000*(twi_dcount - 560)) / 31250; // (half cycle - overhead) / busywait loop time @@ -226,7 +226,7 @@ void Twi::enableSlave() unsigned int i; for (i = 0; i < v; i++) // loop time is 5 machine cycles: 31.25ns @ 160MHz, 62.5ns @ 80MHz { - asm("nop"); // minimum element to keep GCC from optimizing this function out. + asm("nop"); // minimum element to keep GCC from optimizing this function out. } } @@ -472,14 +472,14 @@ void ICACHE_RAM_ATTR Twi::reply(uint8_t ack) if (ack) { //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); - SCL_HIGH(twi.twi_scl); // _BV(TWINT) - twi_ack = 1; // _BV(TWEA) + SCL_HIGH(twi.twi_scl); // _BV(TWINT) + twi_ack = 1; // _BV(TWEA) } else { //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); - SCL_HIGH(twi.twi_scl); // _BV(TWINT) - twi_ack = 0; // ~_BV(TWEA) + SCL_HIGH(twi.twi_scl); // _BV(TWINT) + twi_ack = 0; // ~_BV(TWEA) } } @@ -488,8 +488,8 @@ void ICACHE_RAM_ATTR Twi::releaseBus(void) { // release bus //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); - SCL_HIGH(twi.twi_scl); // _BV(TWINT) - twi_ack = 1; // _BV(TWEA) + SCL_HIGH(twi.twi_scl); // _BV(TWINT) + twi_ack = 1; // _BV(TWEA) SDA_HIGH(twi.twi_sda); // update twi state @@ -660,11 +660,11 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void) unsigned int scl; // Store bool return in int to reduce final code size. - + sda = SDA_READ(twi.twi_sda); scl = SCL_READ(twi.twi_scl); - twi.twip_status = 0xF8; // reset TWI status + twi.twip_status = 0xF8; // reset TWI status int twip_state_mask = S2M(twi.twip_state); IFSTATE(S2M(TWIP_START) | S2M(TWIP_REP_START) | S2M(TWIP_SLA_W) | S2M(TWIP_READ)) @@ -739,7 +739,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void) } else { - SCL_LOW(twi.twi_scl); // clock stretching + SCL_LOW(twi.twi_scl); // clock stretching SDA_HIGH(twi.twi_sda); twi.twip_mode = TWIPM_ADDRESSED; if (!(twi.twi_data & 0x01)) @@ -757,7 +757,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void) } else { - SCL_LOW(twi.twi_scl); // clock stretching + SCL_LOW(twi.twi_scl); // clock stretching SDA_HIGH(twi.twi_sda); if (!twi.twi_ack) { @@ -835,7 +835,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void) } else { - SCL_LOW(twi.twi_scl); // clock stretching + SCL_LOW(twi.twi_scl); // clock stretching if (twi.twi_ack && twi.twi_ack_rec) { twi.onTwipEvent(TW_ST_DATA_ACK); @@ -881,7 +881,7 @@ void ICACHE_RAM_ATTR Twi::onSdaChange(void) else IFSTATE(S2M(TWIP_START) | S2M(TWIP_REP_START) | S2M(TWIP_SEND_ACK) | S2M(TWIP_WAIT_ACK) | S2M(TWIP_SLA_R) | S2M(TWIP_REC_ACK) | S2M(TWIP_READ_ACK) | S2M(TWIP_RWAIT_ACK) | S2M(TWIP_WRITE)) { // START or STOP - SDA_HIGH(twi.twi_sda); // Should not be necessary + SDA_HIGH(twi.twi_sda); // Should not be necessary twi.onTwipEvent(TW_BUS_ERROR); twi.twip_mode = TWIPM_WAIT; twi.twip_state = TWIP_BUS_ERR; @@ -891,7 +891,7 @@ void ICACHE_RAM_ATTR Twi::onSdaChange(void) if (sda) { // STOP - SCL_LOW(twi.twi_scl); // clock stretching + SCL_LOW(twi.twi_scl); // generates a low SCL pulse after STOP ets_timer_disarm(&twi.timer); twi.twip_state = TWIP_IDLE; twi.twip_mode = TWIPM_IDLE; @@ -925,7 +925,7 @@ void ICACHE_RAM_ATTR Twi::onSdaChange(void) else { // during first bit in byte transfer - ok - SCL_LOW(twi.twi_scl); // clock stretching + SCL_LOW(twi.twi_scl); // clock stretching twi.onTwipEvent(TW_SR_STOP); if (sda) { From 9cf109546fc0d198c5d91005745dde80d2d8b611 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 28 Dec 2019 12:17:20 -0600 Subject: [PATCH 6/6] updated minimum I2C speed for calculated bus clock --- cores/esp8266/core_esp8266_si2c.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/esp8266/core_esp8266_si2c.cpp b/cores/esp8266/core_esp8266_si2c.cpp index 9ae022fea7..dff91ce0fb 100644 --- a/cores/esp8266/core_esp8266_si2c.cpp +++ b/cores/esp8266/core_esp8266_si2c.cpp @@ -160,8 +160,8 @@ static Twi twi; void Twi::setClock(unsigned int freq) { - if (freq < 250) // minimum freq 250Hz to prevent overflow @ 232Hz - freq = 250; + if (freq < 1000) // minimum freq 1000Hz to minimize slave timeouts and WDT resets + freq = 1000; preferred_si2c_clock = freq;