mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-21 10:26:06 +03:00
Issue2524 allow clocks below 100KHz (#6934)
* change bus clock (busywait) to be programmable [issue 2524], remove unused slave STOP function * change bus clock (busywait) to be programmable [issue 2524], remove unused slave STOP function * change bus clock (busywait) to be programmable [issue 2524], remove unused slave STOP function * correct for underflow < 233Hz * change bus clock (busywait) to be programmable [issue 2524], convert tabs to spaces * updated minimum I2C speed for calculated bus clock
This commit is contained in:
parent
809e5c967a
commit
3197d2ac4e
@ -40,8 +40,8 @@ extern "C" {
|
|||||||
{
|
{
|
||||||
GPEC = (1 << twi_sda);
|
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;
|
return (GPI & (1 << twi_sda)) != 0;
|
||||||
}
|
}
|
||||||
static inline __attribute__((always_inline)) void SCL_LOW(const int twi_scl)
|
static inline __attribute__((always_inline)) void SCL_LOW(const int twi_scl)
|
||||||
@ -52,8 +52,8 @@ extern "C" {
|
|||||||
{
|
{
|
||||||
GPEC = (1 << twi_scl);
|
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;
|
return (GPI & (1 << twi_scl)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ class Twi
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
unsigned int preferred_si2c_clock = 100000;
|
unsigned int preferred_si2c_clock = 100000;
|
||||||
unsigned char twi_dcount = 18;
|
uint32_t twi_dcount = 18;
|
||||||
unsigned char twi_sda = 0;
|
unsigned char twi_sda = 0;
|
||||||
unsigned char twi_scl = 0;
|
unsigned char twi_scl = 0;
|
||||||
unsigned char twi_addr = 0;
|
unsigned char twi_addr = 0;
|
||||||
@ -112,7 +112,7 @@ private:
|
|||||||
bool _slaveEnabled = false;
|
bool _slaveEnabled = false;
|
||||||
|
|
||||||
// Internal use functions
|
// 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_start(void);
|
||||||
bool write_stop(void);
|
bool write_stop(void);
|
||||||
bool write_bit(bool bit);
|
bool write_bit(bool bit);
|
||||||
@ -148,7 +148,6 @@ public:
|
|||||||
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));
|
||||||
void ICACHE_RAM_ATTR reply(uint8_t ack);
|
void ICACHE_RAM_ATTR reply(uint8_t ack);
|
||||||
void ICACHE_RAM_ATTR stop(void);
|
|
||||||
void ICACHE_RAM_ATTR releaseBus(void);
|
void ICACHE_RAM_ATTR releaseBus(void);
|
||||||
void enableSlave();
|
void enableSlave();
|
||||||
};
|
};
|
||||||
@ -161,65 +160,25 @@ static Twi twi;
|
|||||||
|
|
||||||
void Twi::setClock(unsigned int freq)
|
void Twi::setClock(unsigned int freq)
|
||||||
{
|
{
|
||||||
|
if (freq < 1000) // minimum freq 1000Hz to minimize slave timeouts and WDT resets
|
||||||
|
freq = 1000;
|
||||||
|
|
||||||
preferred_si2c_clock = freq;
|
preferred_si2c_clock = freq;
|
||||||
|
|
||||||
#if F_CPU == FCPU80
|
#if F_CPU == FCPU80
|
||||||
if (freq <= 50000)
|
|
||||||
{
|
if (freq > 400000)
|
||||||
twi_dcount = 38; //about 50KHz
|
freq = 400000;
|
||||||
}
|
twi_dcount = (500000000 / freq); // half-cycle period in ns
|
||||||
else if (freq <= 100000)
|
twi_dcount = (1000*(twi_dcount - 1120)) / 62500; // (half cycle - overhead) / busywait loop time
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
if (freq <= 50000)
|
|
||||||
{
|
if (freq > 800000)
|
||||||
twi_dcount = 64; //about 50KHz
|
freq = 800000;
|
||||||
}
|
twi_dcount = (500000000 / freq); // half-cycle period in ns
|
||||||
else if (freq <= 100000)
|
twi_dcount = (1000*(twi_dcount - 560)) / 31250; // (half cycle - overhead) / busywait loop time
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,18 +221,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;
|
unsigned int i;
|
||||||
#pragma GCC diagnostic push
|
for (i = 0; i < v; i++) // loop time is 5 machine cycles: 31.25ns @ 160MHz, 62.5ns @ 80MHz
|
||||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
|
||||||
unsigned int reg;
|
|
||||||
for (i = 0; i < v; i++)
|
|
||||||
{
|
{
|
||||||
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)
|
bool Twi::write_start(void)
|
||||||
@ -518,35 +472,24 @@ void ICACHE_RAM_ATTR Twi::reply(uint8_t 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(twi.twi_scl); // _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(twi.twi_scl); // _BV(TWINT)
|
SCL_HIGH(twi.twi_scl); // _BV(TWINT)
|
||||||
twi_ack = 0; // ~_BV(TWEA)
|
twi_ack = 0; // ~_BV(TWEA)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
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(twi.twi_scl); // _BV(TWINT)
|
SCL_HIGH(twi.twi_scl); // _BV(TWINT)
|
||||||
twi_ack = 1; // _BV(TWEA)
|
twi_ack = 1; // _BV(TWEA)
|
||||||
SDA_HIGH(twi.twi_sda);
|
SDA_HIGH(twi.twi_sda);
|
||||||
|
|
||||||
// update twi state
|
// update twi state
|
||||||
@ -657,7 +600,6 @@ void ICACHE_RAM_ATTR Twi::onTwipEvent(uint8_t status)
|
|||||||
break;
|
break;
|
||||||
case TW_BUS_ERROR: // bus error, illegal stop/start
|
case TW_BUS_ERROR: // bus error, illegal stop/start
|
||||||
twi_error = TW_BUS_ERROR;
|
twi_error = TW_BUS_ERROR;
|
||||||
stop();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -722,7 +664,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
|
|||||||
sda = SDA_READ(twi.twi_sda);
|
sda = SDA_READ(twi.twi_sda);
|
||||||
scl = SCL_READ(twi.twi_scl);
|
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);
|
int twip_state_mask = S2M(twi.twip_state);
|
||||||
IFSTATE(S2M(TWIP_START) | S2M(TWIP_REP_START) | S2M(TWIP_SLA_W) | S2M(TWIP_READ))
|
IFSTATE(S2M(TWIP_START) | S2M(TWIP_REP_START) | S2M(TWIP_SLA_W) | S2M(TWIP_READ))
|
||||||
@ -797,7 +739,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SCL_LOW(twi.twi_scl); // clock stretching
|
SCL_LOW(twi.twi_scl); // clock stretching
|
||||||
SDA_HIGH(twi.twi_sda);
|
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))
|
||||||
@ -815,7 +757,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SCL_LOW(twi.twi_scl); // clock stretching
|
SCL_LOW(twi.twi_scl); // clock stretching
|
||||||
SDA_HIGH(twi.twi_sda);
|
SDA_HIGH(twi.twi_sda);
|
||||||
if (!twi.twi_ack)
|
if (!twi.twi_ack)
|
||||||
{
|
{
|
||||||
@ -893,7 +835,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SCL_LOW(twi.twi_scl); // 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);
|
||||||
@ -939,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))
|
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
|
||||||
SDA_HIGH(twi.twi_sda); // 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;
|
||||||
@ -949,7 +891,7 @@ void ICACHE_RAM_ATTR Twi::onSdaChange(void)
|
|||||||
if (sda)
|
if (sda)
|
||||||
{
|
{
|
||||||
// STOP
|
// 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);
|
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;
|
||||||
@ -983,7 +925,7 @@ void ICACHE_RAM_ATTR Twi::onSdaChange(void)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// during first bit in byte transfer - ok
|
// 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);
|
twi.onTwipEvent(TW_SR_STOP);
|
||||||
if (sda)
|
if (sda)
|
||||||
{
|
{
|
||||||
@ -1018,11 +960,6 @@ extern "C" {
|
|||||||
return twi.setAddress(a);
|
return twi.setAddress(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void twi_stop(void)
|
|
||||||
{
|
|
||||||
twi.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void twi_setClock(unsigned int freq)
|
void twi_setClock(unsigned int freq)
|
||||||
{
|
{
|
||||||
twi.setClock(freq);
|
twi.setClock(freq);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user