Files
ESP8266lib/io/SoftI2C.h
kazu 5cb02880b3 many updates..
new sensors.. display.. led.. drawing.. stuff..
2019-01-17 23:12:01 +01:00

241 lines
5.0 KiB
C++

#ifndef SOFTI2C_H
#define SOFTI2C_H
#include "../Platforms.h"
#include "../Debug.h"
#include "GPIO.h"
#if ESP8266
#include "fastGPIO.h"
#elif ESP32
# error "Not yet supported"
#endif
// https://www.best-microcontroller-projects.com/i2c-tutorial.html
namespace i2c {
static constexpr const char* NAME = "SoftI2C";
#if ESP8266
// static inline void init() {
// //debugMod(NAME, "init()");
// GPIO5_OUTPUT_SET; // clock is always output
// //GPIO5_INPUT_PULLUP_SET; // pullup for i2c
// //GPIO4_INPUT_PULLUP_SET; // pullup for i2c
// }
// static inline void sclLo() {GPIO5_L;}
// static inline void sclHi() {GPIO5_H;}
// static inline void sclDirOut() {GPIO5_OUTPUT_SET;}
// static inline void sdaDirIn() {GPIO4_INPUT_SET;}// GPIO4_INPUT_PULLUP_SET;}
// static inline void sdaDirOut() {GPIO4_OUTPUT_SET;}
// static inline uint8_t sdaRead() {return GPIO4_IN;}
// static inline void sdaLo() {GPIO4_L;}
// static inline void sdaHi() {GPIO4_H;}
static constexpr const uint8_t PIN_SCL = 5;
static constexpr const uint8_t PIN_SDA = 4;
#elif ESP32
//# error "Not yet supported"
#endif
#if (SOFTI2C_SPEED == 1)
// safe
static inline void waitShort() {os_delay_us(1);}
static inline void waitLong() {os_delay_us(10);}
#elif (SOFTI2C_SPEED == 2)
// fast
static inline void waitShort() {asm("nop");asm("nop");}
static inline void waitLong() {os_delay_us(1);}
#elif (SOFTI2C_SPEED == 3)
// ultra fast
static inline void waitShort() {}
static inline void waitLong() {asm("nop");asm("nop");asm("nop");asm("nop");}
#else
#error "SOFTI2C Speed not set"
#endif
static inline void init() {
GPIO::setOutput(PIN_SCL); // always output
}
static inline void sclLo() {GPIO::clear(PIN_SCL);}
static inline void sclHi() {GPIO::set(PIN_SCL);}
static inline void sclDirOut() {GPIO::setOutput(PIN_SCL);}
static inline void sdaDirIn() {GPIO::setInput(PIN_SDA);}// GPIO4_INPUT_PULLUP_SET;}
static inline void sdaDirOut() {GPIO::setOutput(PIN_SDA);}
static inline uint8_t sdaRead() {return GPIO::get(PIN_SDA);}
static inline void sdaLo() {GPIO::clear(PIN_SDA);}
static inline void sdaHi() {GPIO::set(PIN_SDA);}
static inline void start() {
init();
sdaDirOut();
sclDirOut();
sdaHi();
sclHi();
waitLong();
sdaLo();
waitLong();
sclLo();
waitLong();
}
static inline void stop() {
sdaDirOut();
sclDirOut();
sdaLo();
sclLo();
waitLong();
sclHi();
waitLong();
sdaHi();
sdaDirIn(); // free the bus
waitLong();
}
/** write one bit to the bus */
static inline void writeBit(const bool out) {
sdaDirOut(); // switch to output mode
if(out) {sdaHi();} else {sdaLo();} // apply data
sclHi(); // clock pulse
waitShort();
sclLo();
waitShort();
sdaDirIn(); // free the bus
}
/** read one bit from the bus */
static inline uint8_t readBit() {
sdaDirIn(); // switch to input mode
sclHi(); // clock pulse and read
waitShort();
const uint8_t val = sdaRead();
sclLo();
waitShort();
return val;
}
static inline bool readAck() {
const uint8_t res = readBit();
//os_printf("readAck() - Bus: %d\n", res);
return res == 0; // ACK when input pulled low
}
static inline void writeAck() {
writeBit(0);
}
static inline void writeNAck() {
writeBit(1);
}
/** read 8 bits from the bus, WITHOUT sending ACK/NACK */
static uint8_t IN_FLASH readByte() {
return
(readBit() << 7) |
(readBit() << 6) |
(readBit() << 5) |
(readBit() << 4) |
(readBit() << 3) |
(readBit() << 2) |
(readBit() << 1) |
(readBit() << 0);
}
/** read the given number of bytes from the slave and generate ACK/NACK as needed */
static void readBytes(uint8_t* dst, uint8_t len) {
while(len) {
*dst = readByte();
--len;
++dst;
if (len) {writeAck();} else {writeNAck();} // done? or want more?
}
}
/** write one byte to the bus */
static void IN_FLASH writeByte(const uint8_t byte) {
writeBit(byte & BIT( 7));
writeBit(byte & BIT( 6));
writeBit(byte & BIT( 5));
writeBit(byte & BIT( 4));
writeBit(byte & BIT( 3));
writeBit(byte & BIT( 2));
writeBit(byte & BIT( 1));
writeBit(byte & BIT( 0));
}
/** write one byte to the bus and check slave's ACK/NACK */
static bool IN_FLASH writeByteAndCheck(const uint8_t byte) {
writeByte(byte);
return readAck();
}
/** write several bytes to the bus and check slave's ACK/NACK */
static bool IN_FLASH writeBytesAndCheck(const uint8_t* src, uint8_t len) {
while(len) {
const bool ok = writeByteAndCheck(*src);
if (!ok) {return false;}
--len; ++src;
}
return true;
}
static inline bool startWrite(const uint8_t addr7) {
start();
writeByte( (addr7<<1) | 0 );
const bool ok = readAck();
return ok;
}
static inline bool startRead(const uint8_t addr7) {
start();
writeByte( (addr7<<1) | 1 );
const bool ok = readAck();
return ok;
}
static inline bool query(const uint8_t addr7) {
bool ok = startWrite(addr7);
stop();
return ok;
}
}
#endif // SOFTSPI_H