1
0
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:
StanJ 2019-12-28 16:07:38 -06:00 committed by Develo
parent 809e5c967a
commit 3197d2ac4e

View File

@ -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 @@ private:
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 @@ public:
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,25 @@ static Twi twi;
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;
#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 +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;
#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 +483,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 +600,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;
}
}
@ -949,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;
@ -1018,11 +960,6 @@ extern "C" {
return twi.setAddress(a);
}
void twi_stop(void)
{
twi.stop();
}
void twi_setClock(unsigned int freq)
{
twi.setClock(freq);