1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-07-18 23:03:34 +03:00

change to make inline helpers truly inline [issue 6875] (#6898)

* change to make inline helpers truly inline [issue 6875]

* pulled the inline helpers out of the TWI class [issue 6875]

* removed some inlines causing issues [issue 6875]

* removed 2 more inlines from slave timeout section [issue 6875]

* removed 2 more inline attributes on public functions, moved twi_scl_valley up into the master section [issue 6875]
This commit is contained in:
StanJ
2019-12-15 11:38:33 -06:00
committed by Develo
parent 1d052834a4
commit 5612738636

View File

@ -31,6 +31,32 @@ extern "C" {
#include "ets_sys.h" #include "ets_sys.h"
}; };
// Inline helpers
static inline __attribute__((always_inline)) void SDA_LOW(const int twi_sda)
{
GPES = (1 << twi_sda);
}
static inline __attribute__((always_inline)) void SDA_HIGH(const int twi_sda)
{
GPEC = (1 << 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)
{
GPES = (1 << twi_scl);
}
static inline __attribute__((always_inline)) void SCL_HIGH(const int twi_scl)
{
GPEC = (1 << twi_scl);
}
static inline __attribute__((always_inline)) bool SCL_READ(const int twi_scl)
{
return (GPI & (1 << twi_scl)) != 0;
}
// Implement as a class to reduce code size by allowing access to many global variables with a single base pointer // Implement as a class to reduce code size by allowing access to many global variables with a single base pointer
class Twi class Twi
@ -95,37 +121,12 @@ private:
unsigned char read_byte(bool nack); unsigned char read_byte(bool nack);
void ICACHE_RAM_ATTR onTwipEvent(uint8_t status); void ICACHE_RAM_ATTR onTwipEvent(uint8_t status);
// Inline helpers
inline void SDA_LOW()
{
GPES = (1 << twi_sda);
}
inline void SDA_HIGH()
{
GPEC = (1 << twi_sda);
}
inline bool SDA_READ()
{
return (GPI & (1 << twi_sda)) != 0;
}
inline void SCL_LOW()
{
GPES = (1 << twi_scl);
}
inline void SCL_HIGH()
{
GPEC = (1 << twi_scl);
}
inline bool SCL_READ()
{
return (GPI & (1 << twi_scl)) != 0;
}
// Handle the case where a slave needs to stretch the clock with a time-limited busy wait // Handle the case where a slave needs to stretch the clock with a time-limited busy wait
inline void WAIT_CLOCK_STRETCH() inline void WAIT_CLOCK_STRETCH()
{ {
esp8266::polledTimeout::oneShotFastUs timeout(twi_clockStretchLimit); esp8266::polledTimeout::oneShotFastUs timeout(twi_clockStretchLimit);
esp8266::polledTimeout::periodicFastUs yieldTimeout(5000); esp8266::polledTimeout::periodicFastUs yieldTimeout(5000);
while(!timeout && !SCL_READ()) // outer loop is stretch duration up to stretch limit while(!timeout && !SCL_READ(twi_scl)) // outer loop is stretch duration up to stretch limit
{ {
if (yieldTimeout) // inner loop yields every 5ms if (yieldTimeout) // inner loop yields every 5ms
yield(); yield();
@ -146,9 +147,9 @@ public:
uint8_t transmit(const uint8_t* data, uint8_t length); uint8_t transmit(const uint8_t* data, uint8_t length);
void attachSlaveRxEvent(void (*function)(uint8_t*, size_t)); void attachSlaveRxEvent(void (*function)(uint8_t*, size_t));
void attachSlaveTxEvent(void (*function)(void)); void attachSlaveTxEvent(void (*function)(void));
inline void ICACHE_RAM_ATTR reply(uint8_t ack); void ICACHE_RAM_ATTR reply(uint8_t ack);
inline void ICACHE_RAM_ATTR stop(void); void ICACHE_RAM_ATTR stop(void);
inline void ICACHE_RAM_ATTR releaseBus(void); void ICACHE_RAM_ATTR releaseBus(void);
void enableSlave(); void enableSlave();
}; };
@ -277,44 +278,44 @@ void ICACHE_RAM_ATTR Twi::busywait(unsigned char v)
bool Twi::write_start(void) bool Twi::write_start(void)
{ {
SCL_HIGH(); SCL_HIGH(twi_scl);
SDA_HIGH(); SDA_HIGH(twi_sda);
if (!SDA_READ()) if (!SDA_READ(twi_sda))
{ {
return false; return false;
} }
busywait(twi_dcount); busywait(twi_dcount);
SDA_LOW(); SDA_LOW(twi_sda);
busywait(twi_dcount); busywait(twi_dcount);
return true; return true;
} }
bool Twi::write_stop(void) bool Twi::write_stop(void)
{ {
SCL_LOW(); SCL_LOW(twi_scl);
SDA_LOW(); SDA_LOW(twi_sda);
busywait(twi_dcount); busywait(twi_dcount);
SCL_HIGH(); SCL_HIGH(twi_scl);
WAIT_CLOCK_STRETCH(); WAIT_CLOCK_STRETCH();
busywait(twi_dcount); busywait(twi_dcount);
SDA_HIGH(); SDA_HIGH(twi_sda);
busywait(twi_dcount); busywait(twi_dcount);
return true; return true;
} }
bool Twi::write_bit(bool bit) bool Twi::write_bit(bool bit)
{ {
SCL_LOW(); SCL_LOW(twi_scl);
if (bit) if (bit)
{ {
SDA_HIGH(); SDA_HIGH(twi_sda);
} }
else else
{ {
SDA_LOW(); SDA_LOW(twi_sda);
} }
busywait(twi_dcount + 1); busywait(twi_dcount + 1);
SCL_HIGH(); SCL_HIGH(twi_scl);
WAIT_CLOCK_STRETCH(); WAIT_CLOCK_STRETCH();
busywait(twi_dcount); busywait(twi_dcount);
return true; return true;
@ -322,12 +323,12 @@ bool Twi::write_bit(bool bit)
bool Twi::read_bit(void) bool Twi::read_bit(void)
{ {
SCL_LOW(); SCL_LOW(twi_scl);
SDA_HIGH(); SDA_HIGH(twi_sda);
busywait(twi_dcount + 2); busywait(twi_dcount + 2);
SCL_HIGH(); SCL_HIGH(twi_scl);
WAIT_CLOCK_STRETCH(); WAIT_CLOCK_STRETCH();
bool bit = SDA_READ(); bool bit = SDA_READ(twi_sda);
busywait(twi_dcount); busywait(twi_dcount);
return bit; return bit;
} }
@ -392,7 +393,7 @@ unsigned char Twi::writeTo(unsigned char address, unsigned char * buf, unsigned
// busywait(twi_dcount); // busywait(twi_dcount);
} }
i = 0; i = 0;
while (!SDA_READ() && (i++) < 10) while (!SDA_READ(twi_sda) && (i++) < 10)
{ {
twi_scl_valley(); twi_scl_valley();
busywait(twi_dcount); busywait(twi_dcount);
@ -431,7 +432,7 @@ unsigned char Twi::readFrom(unsigned char address, unsigned char* buf, unsigned
// busywait(twi_dcount); // busywait(twi_dcount);
} }
i = 0; i = 0;
while (!SDA_READ() && (i++) < 10) while (!SDA_READ(twi_sda) && (i++) < 10)
{ {
twi_scl_valley(); twi_scl_valley();
busywait(twi_dcount); busywait(twi_dcount);
@ -439,24 +440,32 @@ unsigned char Twi::readFrom(unsigned char address, unsigned char* buf, unsigned
return 0; return 0;
} }
void Twi::twi_scl_valley(void)
{
SCL_LOW(twi_scl);
busywait(twi_dcount);
SCL_HIGH(twi_scl);
WAIT_CLOCK_STRETCH();
}
uint8_t Twi::status() uint8_t Twi::status()
{ {
WAIT_CLOCK_STRETCH(); // wait for a slow slave to finish WAIT_CLOCK_STRETCH(); // wait for a slow slave to finish
if (!SCL_READ()) if (!SCL_READ(twi_scl))
{ {
return I2C_SCL_HELD_LOW; // SCL held low by another device, no procedure available to recover return I2C_SCL_HELD_LOW; // SCL held low by another device, no procedure available to recover
} }
int clockCount = 20; int clockCount = 20;
while (!SDA_READ() && clockCount-- > 0) // if SDA low, read the bits slaves have to sent to a max while (!SDA_READ(twi_sda) && clockCount-- > 0) // if SDA low, read the bits slaves have to sent to a max
{ {
read_bit(); read_bit();
if (!SCL_READ()) if (!SCL_READ(twi_scl))
{ {
return I2C_SCL_HELD_LOW_AFTER_READ; // I2C bus error. SCL held low beyond slave clock stretch time return I2C_SCL_HELD_LOW_AFTER_READ; // I2C bus error. SCL held low beyond slave clock stretch time
} }
} }
if (!SDA_READ()) if (!SDA_READ(twi_sda))
{ {
return I2C_SDA_HELD_LOW; // I2C bus error. SDA line held low by slave/another_master after n bits. return I2C_SDA_HELD_LOW; // I2C bus error. SDA line held low by slave/another_master after n bits.
} }
@ -500,42 +509,45 @@ void Twi::attachSlaveTxEvent(void (*function)(void))
twi_onSlaveTransmit = function; twi_onSlaveTransmit = function;
} }
inline void ICACHE_RAM_ATTR Twi::reply(uint8_t ack) // DO NOT INLINE, inlining reply() in combination with compiler optimizations causes function breakup into
// parts and the ICACHE_RAM_ATTR isn't propagated correctly to all parts, which of course causes crashes.
// TODO: test with gcc 9.x and if it still fails, disable optimization with -fdisable-ipa-fnsplit
void ICACHE_RAM_ATTR Twi::reply(uint8_t ack)
{ {
// transmit master read ready signal, with or without ack // transmit master read ready signal, with or without ack
if (ack) if (ack)
{ {
//TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);
SCL_HIGH(); // _BV(TWINT) SCL_HIGH(twi.twi_scl); // _BV(TWINT)
twi_ack = 1; // _BV(TWEA) twi_ack = 1; // _BV(TWEA)
} }
else else
{ {
//TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);
SCL_HIGH(); // _BV(TWINT) SCL_HIGH(twi.twi_scl); // _BV(TWINT)
twi_ack = 0; // ~_BV(TWEA) twi_ack = 0; // ~_BV(TWEA)
} }
} }
inline void ICACHE_RAM_ATTR Twi::stop(void) void ICACHE_RAM_ATTR Twi::stop(void)
{ {
// send stop condition // send stop condition
//TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO);
SCL_HIGH(); // _BV(TWINT) SCL_HIGH(twi.twi_scl); // _BV(TWINT)
twi_ack = 1; // _BV(TWEA) twi_ack = 1; // _BV(TWEA)
busywait(5); // Maybe this should be here busywait(5); // Maybe this should be here
SDA_HIGH(); // _BV(TWSTO) SDA_HIGH(twi.twi_sda); // _BV(TWSTO)
// update twi state // update twi state
twi_state = TWI_READY; twi_state = TWI_READY;
} }
inline void ICACHE_RAM_ATTR Twi::releaseBus(void) void ICACHE_RAM_ATTR Twi::releaseBus(void)
{ {
// release bus // release bus
//TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT);
SCL_HIGH(); // _BV(TWINT) SCL_HIGH(twi.twi_scl); // _BV(TWINT)
twi_ack = 1; // _BV(TWEA) twi_ack = 1; // _BV(TWEA)
SDA_HIGH(); SDA_HIGH(twi.twi_sda);
// update twi state // update twi state
twi_state = TWI_READY; twi_state = TWI_READY;
@ -616,11 +628,11 @@ void ICACHE_RAM_ATTR Twi::onTwipEvent(uint8_t status)
bitCount--; bitCount--;
if (twi_data & 0x80) if (twi_data & 0x80)
{ {
SDA_HIGH(); SDA_HIGH(twi.twi_sda);
} }
else else
{ {
SDA_LOW(); SDA_LOW(twi.twi_sda);
} }
twi_data <<= 1; twi_data <<= 1;
@ -650,14 +662,6 @@ void ICACHE_RAM_ATTR Twi::onTwipEvent(uint8_t status)
} }
} }
void Twi::twi_scl_valley(void)
{
SCL_LOW();
busywait(twi_dcount);
SCL_HIGH();
WAIT_CLOCK_STRETCH();
}
void ICACHE_RAM_ATTR Twi::onTimer(void *unused) void ICACHE_RAM_ATTR Twi::onTimer(void *unused)
{ {
(void)unused; (void)unused;
@ -714,8 +718,9 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
unsigned int scl; unsigned int scl;
// Store bool return in int to reduce final code size. // Store bool return in int to reduce final code size.
sda = twi.SDA_READ();
scl = twi.SCL_READ(); 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
@ -758,7 +763,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
} }
else else
{ {
twi.SDA_LOW(); SDA_LOW(twi.twi_sda);
} }
} }
else else
@ -769,7 +774,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
} }
else else
{ {
twi.SDA_LOW(); SDA_LOW(twi.twi_sda);
} }
} }
twi.twip_state = TWIP_WAIT_ACK; twi.twip_state = TWIP_WAIT_ACK;
@ -787,13 +792,13 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
{ {
if ((twi.twi_data & 0xFE) != twi.twi_addr) if ((twi.twi_data & 0xFE) != twi.twi_addr)
{ {
twi.SDA_HIGH(); SDA_HIGH(twi.twi_sda);
twi.twip_state = TWIP_WAIT_STOP; twi.twip_state = TWIP_WAIT_STOP;
} }
else else
{ {
twi.SCL_LOW(); // clock stretching SCL_LOW(twi.twi_scl); // clock stretching
twi.SDA_HIGH(); SDA_HIGH(twi.twi_sda);
twi.twip_mode = TWIPM_ADDRESSED; twi.twip_mode = TWIPM_ADDRESSED;
if (!(twi.twi_data & 0x01)) if (!(twi.twi_data & 0x01))
{ {
@ -810,8 +815,8 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
} }
else else
{ {
twi.SCL_LOW(); // clock stretching SCL_LOW(twi.twi_scl); // clock stretching
twi.SDA_HIGH(); SDA_HIGH(twi.twi_sda);
if (!twi.twi_ack) if (!twi.twi_ack)
{ {
twi.onTwipEvent(TW_SR_DATA_NACK); twi.onTwipEvent(TW_SR_DATA_NACK);
@ -838,11 +843,11 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
twi.bitCount--; twi.bitCount--;
if (twi.twi_data & 0x80) if (twi.twi_data & 0x80)
{ {
twi.SDA_HIGH(); SDA_HIGH(twi.twi_sda);
} }
else else
{ {
twi.SDA_LOW(); SDA_LOW(twi.twi_sda);
} }
twi.twi_data <<= 1; twi.twi_data <<= 1;
@ -864,7 +869,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
} }
else else
{ {
twi.SDA_HIGH(); SDA_HIGH(twi.twi_sda);
twi.twip_state = TWIP_READ_ACK; twi.twip_state = TWIP_READ_ACK;
} }
} }
@ -888,7 +893,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
} }
else else
{ {
twi.SCL_LOW(); // clock stretching SCL_LOW(twi.twi_scl); // clock stretching
if (twi.twi_ack && twi.twi_ack_rec) if (twi.twi_ack && twi.twi_ack_rec)
{ {
twi.onTwipEvent(TW_ST_DATA_ACK); twi.onTwipEvent(TW_ST_DATA_ACK);
@ -911,8 +916,8 @@ void ICACHE_RAM_ATTR Twi::onSdaChange(void)
unsigned int scl; unsigned int scl;
// Store bool return in int to reduce final code size. // Store bool return in int to reduce final code size.
sda = twi.SDA_READ(); sda = SDA_READ(twi.twi_sda);
scl = twi.SCL_READ(); scl = SCL_READ(twi.twi_scl);
int twip_state_mask = S2M(twi.twip_state); int twip_state_mask = S2M(twi.twip_state);
if (scl) /* !DATA */ if (scl) /* !DATA */
@ -934,7 +939,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)) 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 // START or STOP
twi.SDA_HIGH(); // Should not be necessary SDA_HIGH(twi.twi_sda); // Should not be necessary
twi.onTwipEvent(TW_BUS_ERROR); twi.onTwipEvent(TW_BUS_ERROR);
twi.twip_mode = TWIPM_WAIT; twi.twip_mode = TWIPM_WAIT;
twi.twip_state = TWIP_BUS_ERR; twi.twip_state = TWIP_BUS_ERR;
@ -944,11 +949,11 @@ void ICACHE_RAM_ATTR Twi::onSdaChange(void)
if (sda) if (sda)
{ {
// STOP // STOP
twi.SCL_LOW(); // clock stretching SCL_LOW(twi.twi_scl); // clock stretching
ets_timer_disarm(&twi.timer); ets_timer_disarm(&twi.timer);
twi.twip_state = TWIP_IDLE; twi.twip_state = TWIP_IDLE;
twi.twip_mode = TWIPM_IDLE; twi.twip_mode = TWIPM_IDLE;
twi.SCL_HIGH(); SCL_HIGH(twi.twi_scl);
} }
else else
{ {
@ -978,7 +983,7 @@ void ICACHE_RAM_ATTR Twi::onSdaChange(void)
else else
{ {
// during first bit in byte transfer - ok // during first bit in byte transfer - ok
twi.SCL_LOW(); // clock stretching SCL_LOW(twi.twi_scl); // clock stretching
twi.onTwipEvent(TW_SR_STOP); twi.onTwipEvent(TW_SR_STOP);
if (sda) if (sda)
{ {