From 7b8c37d235c77d881db4184a798fc4b72a1fa279 Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Mon, 15 Jan 2018 10:16:13 +0100 Subject: Add Software I2C implementation --- Makefile | 5 ++ include/driver/soft_i2c.h | 26 ++++++++++ src/driver/soft_i2c.cc | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 include/driver/soft_i2c.h create mode 100644 src/driver/soft_i2c.cc diff --git a/Makefile b/Makefile index a6f03c9..b7089b4 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,11 @@ ifneq ($(findstring sharp96,${drivers}), ) COMMON_FLAGS += -DSHARP96_CS_PIN=GPIO::${sharp96_cs_pin} endif +ifneq ($(findstring softi2c,${drivers}), ) + TARGETS += src/driver/soft_i2c.cc + COMMON_FLAGS += -DDRIVER_SOFTI2C +endif + ifeq (${timer_cycles}, 1) COMMON_FLAGS += -DTIMER_CYCLES endif diff --git a/include/driver/soft_i2c.h b/include/driver/soft_i2c.h new file mode 100644 index 0000000..aff63e3 --- /dev/null +++ b/include/driver/soft_i2c.h @@ -0,0 +1,26 @@ +#ifndef SOFTI2C_H +#define SOFTI2C_H + +class SoftI2C { + private: + SoftI2C(const SoftI2C ©); + + unsigned char sda, scl; + + void start(); + void stop(); + bool tx(unsigned char byte); + unsigned char rx(bool send_ack); + + public: + SoftI2C(unsigned char sda, unsigned char scl) : sda(sda), scl(scl) {} + signed char setup(); + void scan(unsigned int *results); + signed char xmit(unsigned char address, + unsigned char tx_len, unsigned char *tx_buf, + unsigned char rx_len, unsigned char *rx_buf); +}; + +extern SoftI2C i2c; + +#endif diff --git a/src/driver/soft_i2c.cc b/src/driver/soft_i2c.cc new file mode 100644 index 0000000..f8ee052 --- /dev/null +++ b/src/driver/soft_i2c.cc @@ -0,0 +1,121 @@ +#include "driver/soft_i2c.h" +#include "driver/gpio.h" + +signed char SoftI2C::setup() +{ + gpio.write(sda, 0); + gpio.write(scl, 0); + return 0; +} + +void SoftI2C::start() +{ + gpio.input(sda); + gpio.input(scl); + // + gpio.output(sda); + // + gpio.output(scl); +} + +void SoftI2C::stop() +{ + gpio.output(sda); + // + gpio.input(scl); + // + gpio.input(sda); +} + +bool SoftI2C::tx(unsigned char byte) +{ + unsigned char got_ack = 0; + for (unsigned char i = 0; i <= 8; i++) { + if ((byte & 0x80) || (i == 8)) { + gpio.input(sda); + } else { + gpio.output(sda); + } + byte <<= 1; + // + gpio.input(scl); + // + if (i == 8) { + if (!gpio.read(sda)) { + got_ack = 1; + } + } + gpio.output(scl); + // + } + return got_ack; +} + +unsigned char SoftI2C::rx(bool send_ack) +{ + unsigned char byte = 0; + gpio.input(sda); + for (unsigned char i = 0; i <= 8; i++) { + // + gpio.input(scl); + // + if ((i < 8) && gpio.read(sda)) { + byte |= 1 << (7 - i); + } + // + gpio.output(scl); + // + if ((i == 7) && send_ack) { + gpio.output(sda); + } else if ((i == 8) && send_ack) { + gpio.input(sda); + } + } + return byte; +} + +void SoftI2C::scan(unsigned int *results) +{ + unsigned char i2caddr; + for (unsigned char address = 0; address < 128; address++) { + + i2caddr = (address << 1) | 1; + + start(); + + if (tx(i2caddr)) { + results[address / (8 * sizeof(unsigned int))] |= 1 << (address % (8 * sizeof(unsigned int))); + } + } + stop(); +} + +signed char SoftI2C::xmit(unsigned char address, + unsigned char tx_len, unsigned char *tx_buf, + unsigned char rx_len, unsigned char *rx_buf) +{ + unsigned char i; + + if (tx_len) { + start(); + tx((address << 1) | 0); + + for (i = 0; i < tx_len; i++) { + tx(tx_buf[i]); + } + } + if (rx_len) { + start(); + tx((address << 1) | 1); + + for (i = 1; i <= rx_len; i++) { + rx_buf[i] = rx((i < rx_len) * 1); + } + } + + stop(); + + return 0; +} + +SoftI2C i2c(GPIO::p1_6, GPIO::p1_7); -- cgit v1.2.3