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"
};
// 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
class Twi
@ -95,37 +121,12 @@ private:
unsigned char read_byte(bool nack);
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
inline void WAIT_CLOCK_STRETCH()
{
esp8266::polledTimeout::oneShotFastUs timeout(twi_clockStretchLimit);
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
yield();
@ -146,9 +147,9 @@ public:
uint8_t transmit(const uint8_t* data, uint8_t length);
void attachSlaveRxEvent(void (*function)(uint8_t*, size_t));
void attachSlaveTxEvent(void (*function)(void));
inline void ICACHE_RAM_ATTR reply(uint8_t ack);
inline void ICACHE_RAM_ATTR stop(void);
inline void ICACHE_RAM_ATTR releaseBus(void);
void ICACHE_RAM_ATTR reply(uint8_t ack);
void ICACHE_RAM_ATTR stop(void);
void ICACHE_RAM_ATTR releaseBus(void);
void enableSlave();
};
@ -277,44 +278,44 @@ void ICACHE_RAM_ATTR Twi::busywait(unsigned char v)
bool Twi::write_start(void)
{
SCL_HIGH();
SDA_HIGH();
if (!SDA_READ())
SCL_HIGH(twi_scl);
SDA_HIGH(twi_sda);
if (!SDA_READ(twi_sda))
{
return false;
}
busywait(twi_dcount);
SDA_LOW();
SDA_LOW(twi_sda);
busywait(twi_dcount);
return true;
}
bool Twi::write_stop(void)
{
SCL_LOW();
SDA_LOW();
SCL_LOW(twi_scl);
SDA_LOW(twi_sda);
busywait(twi_dcount);
SCL_HIGH();
SCL_HIGH(twi_scl);
WAIT_CLOCK_STRETCH();
busywait(twi_dcount);
SDA_HIGH();
SDA_HIGH(twi_sda);
busywait(twi_dcount);
return true;
}
bool Twi::write_bit(bool bit)
{
SCL_LOW();
SCL_LOW(twi_scl);
if (bit)
{
SDA_HIGH();
SDA_HIGH(twi_sda);
}
else
{
SDA_LOW();
SDA_LOW(twi_sda);
}
busywait(twi_dcount + 1);
SCL_HIGH();
SCL_HIGH(twi_scl);
WAIT_CLOCK_STRETCH();
busywait(twi_dcount);
return true;
@ -322,12 +323,12 @@ bool Twi::write_bit(bool bit)
bool Twi::read_bit(void)
{
SCL_LOW();
SDA_HIGH();
SCL_LOW(twi_scl);
SDA_HIGH(twi_sda);
busywait(twi_dcount + 2);
SCL_HIGH();
SCL_HIGH(twi_scl);
WAIT_CLOCK_STRETCH();
bool bit = SDA_READ();
bool bit = SDA_READ(twi_sda);
busywait(twi_dcount);
return bit;
}
@ -392,7 +393,7 @@ unsigned char Twi::writeTo(unsigned char address, unsigned char * buf, unsigned
// busywait(twi_dcount);
}
i = 0;
while (!SDA_READ() && (i++) < 10)
while (!SDA_READ(twi_sda) && (i++) < 10)
{
twi_scl_valley();
busywait(twi_dcount);
@ -431,7 +432,7 @@ unsigned char Twi::readFrom(unsigned char address, unsigned char* buf, unsigned
// busywait(twi_dcount);
}
i = 0;
while (!SDA_READ() && (i++) < 10)
while (!SDA_READ(twi_sda) && (i++) < 10)
{
twi_scl_valley();
busywait(twi_dcount);
@ -439,24 +440,32 @@ unsigned char Twi::readFrom(unsigned char address, unsigned char* buf, unsigned
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()
{
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
}
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();
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
}
}
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.
}
@ -500,42 +509,45 @@ void Twi::attachSlaveTxEvent(void (*function)(void))
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
if (ack)
{
//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)
}
else
{
//TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);
SCL_HIGH(); // _BV(TWINT)
SCL_HIGH(twi.twi_scl); // _BV(TWINT)
twi_ack = 0; // ~_BV(TWEA)
}
}
inline void ICACHE_RAM_ATTR Twi::stop(void)
void ICACHE_RAM_ATTR Twi::stop(void)
{
// send stop condition
//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)
busywait(5); // Maybe this should be here
SDA_HIGH(); // _BV(TWSTO)
SDA_HIGH(twi.twi_sda); // _BV(TWSTO)
// update twi state
twi_state = TWI_READY;
}
inline void ICACHE_RAM_ATTR Twi::releaseBus(void)
void ICACHE_RAM_ATTR Twi::releaseBus(void)
{
// release bus
//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)
SDA_HIGH();
SDA_HIGH(twi.twi_sda);
// update twi state
twi_state = TWI_READY;
@ -616,11 +628,11 @@ void ICACHE_RAM_ATTR Twi::onTwipEvent(uint8_t status)
bitCount--;
if (twi_data & 0x80)
{
SDA_HIGH();
SDA_HIGH(twi.twi_sda);
}
else
{
SDA_LOW();
SDA_LOW(twi.twi_sda);
}
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)unused;
@ -714,8 +718,9 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
unsigned int scl;
// 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
@ -758,7 +763,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
}
else
{
twi.SDA_LOW();
SDA_LOW(twi.twi_sda);
}
}
else
@ -769,7 +774,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
}
else
{
twi.SDA_LOW();
SDA_LOW(twi.twi_sda);
}
}
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)
{
twi.SDA_HIGH();
SDA_HIGH(twi.twi_sda);
twi.twip_state = TWIP_WAIT_STOP;
}
else
{
twi.SCL_LOW(); // clock stretching
twi.SDA_HIGH();
SCL_LOW(twi.twi_scl); // clock stretching
SDA_HIGH(twi.twi_sda);
twi.twip_mode = TWIPM_ADDRESSED;
if (!(twi.twi_data & 0x01))
{
@ -810,8 +815,8 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
}
else
{
twi.SCL_LOW(); // clock stretching
twi.SDA_HIGH();
SCL_LOW(twi.twi_scl); // clock stretching
SDA_HIGH(twi.twi_sda);
if (!twi.twi_ack)
{
twi.onTwipEvent(TW_SR_DATA_NACK);
@ -838,11 +843,11 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
twi.bitCount--;
if (twi.twi_data & 0x80)
{
twi.SDA_HIGH();
SDA_HIGH(twi.twi_sda);
}
else
{
twi.SDA_LOW();
SDA_LOW(twi.twi_sda);
}
twi.twi_data <<= 1;
@ -864,7 +869,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
}
else
{
twi.SDA_HIGH();
SDA_HIGH(twi.twi_sda);
twi.twip_state = TWIP_READ_ACK;
}
}
@ -888,7 +893,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
}
else
{
twi.SCL_LOW(); // clock stretching
SCL_LOW(twi.twi_scl); // clock stretching
if (twi.twi_ack && twi.twi_ack_rec)
{
twi.onTwipEvent(TW_ST_DATA_ACK);
@ -911,8 +916,8 @@ void ICACHE_RAM_ATTR Twi::onSdaChange(void)
unsigned int scl;
// 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);
int twip_state_mask = S2M(twi.twip_state);
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))
{
// 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.twip_mode = TWIPM_WAIT;
twi.twip_state = TWIP_BUS_ERR;
@ -944,11 +949,11 @@ void ICACHE_RAM_ATTR Twi::onSdaChange(void)
if (sda)
{
// STOP
twi.SCL_LOW(); // clock stretching
SCL_LOW(twi.twi_scl); // clock stretching
ets_timer_disarm(&twi.timer);
twi.twip_state = TWIP_IDLE;
twi.twip_mode = TWIPM_IDLE;
twi.SCL_HIGH();
SCL_HIGH(twi.twi_scl);
}
else
{
@ -978,7 +983,7 @@ void ICACHE_RAM_ATTR Twi::onSdaChange(void)
else
{
// during first bit in byte transfer - ok
twi.SCL_LOW(); // clock stretching
SCL_LOW(twi.twi_scl); // clock stretching
twi.onTwipEvent(TW_SR_STOP);
if (sda)
{