From 12338747bf5694fce95a01df64679d6081118ac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 14 May 2022 21:47:56 +0200 Subject: [PATCH] [realtek-ambz] Add Wire library --- README.md | 2 +- arduino/libretuya/api/Wire.h | 66 ++++++ .../realtek-ambz/libraries/Flash/Flash.cpp | 11 +- arduino/realtek-ambz/libraries/Wire/Wire.cpp | 192 ++++++++++++++++++ arduino/realtek-ambz/libraries/Wire/Wire.h | 75 +++++++ boards/wr3/variant.h | 6 +- 6 files changed, 342 insertions(+), 10 deletions(-) create mode 100644 arduino/libretuya/api/Wire.h create mode 100644 arduino/realtek-ambz/libraries/Wire/Wire.cpp create mode 100644 arduino/realtek-ambz/libraries/Wire/Wire.h diff --git a/README.md b/README.md index 34806a6..3217c13 100644 --- a/README.md +++ b/README.md @@ -179,7 +179,7 @@ Flash I/O | ❓ **CORE LIBRARIES** | SoftwareSerial | ❌ SPI | ❌ -Wire | ❌ +Wire | ❗ **OTHER LIBRARIES** | Wi-Fi STA/AP/Mixed | ✔️ Wi-Fi Client (SSL) | ✔️ (✔️) diff --git a/arduino/libretuya/api/Wire.h b/arduino/libretuya/api/Wire.h new file mode 100644 index 0000000..eded4cf --- /dev/null +++ b/arduino/libretuya/api/Wire.h @@ -0,0 +1,66 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-05-09. */ + +#include + +class ITwoWire : public Stream { + protected: + int8_t _sda = -1; + int8_t _scl = -1; + uint32_t _freq = 0; + + void (*onRequestCallback)(void); + void (*onReceiveCallback)(int); + + public: + bool begin() { + return begin(_sda, _scl, _freq); + } + + bool begin(uint8_t address) { + return begin(address, _sda, _scl, _freq); + } + + virtual bool setPins(int8_t sda, int8_t scl) = 0; + + virtual bool begin(int8_t sda, int8_t scl, uint32_t frequency = 0) = 0; + virtual bool begin(uint8_t address, int8_t sda, int8_t scl, uint32_t frequency = 0) = 0; + virtual bool end() = 0; + + virtual bool setClock(uint32_t freq) = 0; + + virtual void beginTransmission(uint8_t address) = 0; + virtual uint8_t endTransmission(bool stopBit) = 0; + + virtual size_t requestFrom(uint8_t address, size_t len, bool stopBit) = 0; + + virtual size_t write(const uint8_t *data, size_t len) = 0; + + virtual int available() = 0; + virtual int read() = 0; + virtual int peek() = 0; + virtual void flush() = 0; + + uint32_t getClock() { + return _freq; + } + + uint8_t endTransmission() { + return endTransmission(true); + } + + size_t requestFrom(uint8_t address, size_t len) { + return requestFrom(address, len, true); + } + + virtual size_t write(uint8_t data) { + return write(&data, 1); + } + + void onReceive(void (*cb)(int)) { + onReceiveCallback = cb; + } + + void onRequest(void (*cb)(void)) { + onRequestCallback = cb; + } +}; diff --git a/arduino/realtek-ambz/libraries/Flash/Flash.cpp b/arduino/realtek-ambz/libraries/Flash/Flash.cpp index f0b745c..44520a4 100644 --- a/arduino/realtek-ambz/libraries/Flash/Flash.cpp +++ b/arduino/realtek-ambz/libraries/Flash/Flash.cpp @@ -4,15 +4,12 @@ #include -#ifdef __cplusplus extern "C" { -#endif // __cplusplus - #include +} -#ifdef __cplusplus -} // extern "C" -#endif +// Global Flash object. +FlashClass Flash; FlashClass::FlashClass() { flash = NULL; @@ -67,5 +64,3 @@ bool FlashClass::writeBlock(uint32_t offset, uint8_t *data, size_t size) { initialize(); return flash_stream_write(flash, offset, size, data); } - -FlashClass Flash; diff --git a/arduino/realtek-ambz/libraries/Wire/Wire.cpp b/arduino/realtek-ambz/libraries/Wire/Wire.cpp new file mode 100644 index 0000000..f22605c --- /dev/null +++ b/arduino/realtek-ambz/libraries/Wire/Wire.cpp @@ -0,0 +1,192 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-05-08. */ + +#include "Wire.h" + +#include + +extern "C" { +#include +extern int i2c_write_timeout(i2c_t *obj, int address, char *data, int length, int stop, int timeout_ms); +} + +#ifdef PIN_WIRE0_SDA +// Wire object associated to I2C0 interface. +TwoWire Wire(PIN_WIRE0_SDA, PIN_WIRE0_SCL); +#endif + +#if defined(PIN_WIRE0_SDA) && defined(PIN_WIRE1_SDA) +// Wire object associated to I2C1 interface. +TwoWire Wire1(PIN_WIRE1_SDA, PIN_WIRE1_SCL); +#endif + +#if !defined(PIN_WIRE0_SDA) && defined(PIN_WIRE1_SDA) +// Wire object associated to I2C1 interface. The board doesn't support I2C0. +TwoWire Wire(PIN_WIRE1_SDA, PIN_WIRE1_SCL); +#endif + +TwoWire::TwoWire() { + _timeout = 50; +} + +TwoWire::TwoWire(int8_t sda, int8_t scl) { + _timeout = 50; + _sda = sda; + _scl = scl; +} + +TwoWire::~TwoWire() {} + +bool TwoWire::setPins(int8_t sda, int8_t scl) { + // return true when changing pins on initialized I2C + if (_inSetPins) + return true; + // check if pins are provided + if (sda == -1 || scl == -1) + return false; + // set private pins + _sda = sda; + _scl = scl; + sda = g_APinDescription[sda].pinname; + scl = g_APinDescription[scl].pinname; + + // check if pins are valid + if ((sda == PA_4 || sda == PA_19 || sda == PA_30) && (scl == PA_1 || scl == PA_22 || scl == PA_29)) { + // I2C index 0 + _idx = 0; + } else if ((sda == PA_27 || sda == PA_2 || sda == PA_23) && (scl == PA_28 || scl == PA_3 || scl == PA_18)) { + // I2C index 1 + _idx = 1; + } else { + return false; + } + + // restart I2C if changing pins + // this will never be called from begin() + if (_i2c) { + _inSetPins = true; + end(); + begin(); + _inSetPins = false; + } + return true; +} + +bool TwoWire::begin(int8_t sda, int8_t scl, uint32_t frequency) { + if (_i2c) + return true; + // set private i2c pins + if (!setPins(sda, scl)) + return false; + // use default frequency + if (!frequency) + frequency = WIRE_DEFAULT_FREQ; + + _i2c = new i2c_t; + i2c_init(_i2c, (PinName)g_APinDescription[_sda].pinname, (PinName)g_APinDescription[_scl].pinname); + i2c_frequency(_i2c, frequency); + _freq = frequency; + return true; +} + +bool TwoWire::begin(uint8_t address, int8_t sda, int8_t scl, uint32_t frequency) { + if (_i2c) + return true; + // init master bus first, return if failed (wrong pins) + if (!begin(sda, scl, frequency)) + return false; + + i2c_slave_address(_i2c, _idx, address, 0xff); + i2c_slave_mode(_i2c, true); + return true; +} + +bool TwoWire::end() { + i2c_reset(_i2c); + delete _i2c; + _i2c = NULL; +} + +bool TwoWire::setClock(uint32_t freq) { + if (_i2c) { + i2c_frequency(_i2c, freq); + } + _freq = freq; +} + +void TwoWire::beginTransmission(uint8_t address) { + _txAddr = address; + _txBuf.clear(); +} + +// Errors: +// 0 : Success +// 1 : Data too long +// 2 : NACK on transmit of address +// 3 : NACK on transmit of data +// 4 : Other error +uint8_t TwoWire::endTransmission(bool stopBit) { + if (!_i2c || !_txAddr) + return 4; + char *buf = (char *)malloc(_txBuf.available()); + uint8_t i = 0; + while (_txBuf.available()) { + buf[i++] = _txBuf.read_char(); + } + int len = i2c_write_timeout(_i2c, _txAddr, buf, i, stopBit, _timeout); + free(buf); + _txAddr = 0; + if (len == -1) + return 2; // slave not available (if tx length == 0) + if (len != i) + return 3; // less bytes written + return 0; +} + +size_t TwoWire::requestFrom(uint8_t address, size_t len, bool stopBit) { + if (!len) + return 0; + + if (len > SERIAL_BUFFER_SIZE) + len = SERIAL_BUFFER_SIZE; + + _rxBuf.clear(); + + char *buf = (char *)malloc(_txBuf.available()); + i2c_read(_i2c, address, buf, len, stopBit); + uint8_t i = 0; + while (len) { + _rxBuf.store_char(buf[i++]); + len--; + } + free(buf); + return len; +} + +size_t TwoWire::write(uint8_t data) { + if (!_txAddr || _txBuf.isFull()) + return 0; + _txBuf.store_char(data); + return 1; +} + +size_t TwoWire::write(const uint8_t *data, size_t len) { + for (size_t i = 0; i < len; i++) { + if (!write(data[i])) + return i; + } + return len; +} + +int TwoWire::available() { + return _rxBuf.available(); +} + +int TwoWire::read() { + return _rxBuf.read_char(); +} + +int TwoWire::peek() { + return _rxBuf.peek(); +} + +void TwoWire::flush() {} diff --git a/arduino/realtek-ambz/libraries/Wire/Wire.h b/arduino/realtek-ambz/libraries/Wire/Wire.h new file mode 100644 index 0000000..8bcafeb --- /dev/null +++ b/arduino/realtek-ambz/libraries/Wire/Wire.h @@ -0,0 +1,75 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-05-08. */ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +// #include +#ifdef __cplusplus +} +#endif + +#if !defined(PIN_WIRE0_SDA) && defined(PIN_WIRE1_SDA) +#define Wire1 Wire +#endif + +#define WIRE_HAS_END 1 +#define WIRE_DEFAULT_FREQ 100000 + +struct i2c_s; +typedef struct i2c_s i2c_t; + +using arduino::RingBuffer; + +class TwoWire : public ITwoWire { + private: + i2c_t *_i2c = NULL; + uint8_t _idx = 0; + + RingBuffer _rxBuf; + RingBuffer _txBuf; + uint8_t _txAddr = 0; + bool _inSetPins = false; + + public: + TwoWire(); + TwoWire(int8_t sda, int8_t scl); + ~TwoWire(); + + bool setPins(int8_t sda, int8_t scl); + + bool begin(int8_t sda, int8_t scl, uint32_t frequency = 0); + bool begin(uint8_t address, int8_t sda, int8_t scl, uint32_t frequency = 0); + bool end(); + + bool setClock(uint32_t freq); + + void beginTransmission(uint8_t address); + uint8_t endTransmission(bool stopBit); + + size_t requestFrom(uint8_t address, size_t len, bool stopBit); + size_t write(uint8_t data); + size_t write(const uint8_t *data, size_t len); + + int available(); + int read(); + int peek(); + void flush(); + + using ITwoWire::begin; + using ITwoWire::endTransmission; + using ITwoWire::requestFrom; + using ITwoWire::write; + using Print::write; +}; + +#ifdef PIN_WIRE0_SDA +extern TwoWire Wire; +#endif +#ifdef PIN_WIRE1_SDA +extern TwoWire Wire1; +#endif diff --git a/boards/wr3/variant.h b/boards/wr3/variant.h index f02607f..76dba08 100644 --- a/boards/wr3/variant.h +++ b/boards/wr3/variant.h @@ -40,7 +40,11 @@ static const uint8_t A2 = PIN_A2; // Wire Interfaces // --------------- -#define WIRE_INTERFACES_COUNT 0 +#define WIRE_INTERFACES_COUNT 2 +#define PIN_WIRE0_SDA 1u // PA_19 +#define PIN_WIRE0_SCL 0u // PA_22 +#define PIN_WIRE1_SDA 10u // PA_23 +#define PIN_WIRE1_SCL 9u // PA_18 // Serial ports // ------------