From c93e810feede285b14388febc9e2255d26a8cd1b Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Fri, 18 Dec 2020 10:35:14 +0100 Subject: [PATCH] m5stack core2 support --- .../ILI9341-gemu-1.0/ILI9341_2.cpp | 267 ++++++-- lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.h | 10 +- lib/libesp32/CORE2_Library/AXP192.cpp | 614 ++++++++++++++++++ lib/libesp32/CORE2_Library/AXP192.h | 106 +++ lib/libesp32/CORE2_Library/BM8563_RTC.cpp | 353 ++++++++++ lib/libesp32/CORE2_Library/BM8563_RTC.h | 76 +++ lib/libesp32/CORE2_Library/MPU6886.cpp | 252 +++++++ lib/libesp32/CORE2_Library/MPU6886.h | 98 +++ lib/libesp32/CORE2_Library/MahonyAHRS.cpp | 254 ++++++++ lib/libesp32/CORE2_Library/MahonyAHRS.h | 33 + tasmota/xdrv_10_scripter.ino | 21 +- tasmota/xdrv_13_display.ino | 42 +- tasmota/xdrv_84_core2.ino | 266 ++++++++ tasmota/xdsp_13_ILI9341-2.ino | 96 ++- 14 files changed, 2435 insertions(+), 53 deletions(-) create mode 100755 lib/libesp32/CORE2_Library/AXP192.cpp create mode 100755 lib/libesp32/CORE2_Library/AXP192.h create mode 100755 lib/libesp32/CORE2_Library/BM8563_RTC.cpp create mode 100755 lib/libesp32/CORE2_Library/BM8563_RTC.h create mode 100755 lib/libesp32/CORE2_Library/MPU6886.cpp create mode 100755 lib/libesp32/CORE2_Library/MPU6886.h create mode 100755 lib/libesp32/CORE2_Library/MahonyAHRS.cpp create mode 100755 lib/libesp32/CORE2_Library/MahonyAHRS.h create mode 100644 tasmota/xdrv_84_core2.ino diff --git a/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.cpp b/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.cpp index 482f3fa77..a4391f10e 100644 --- a/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.cpp +++ b/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.cpp @@ -60,6 +60,15 @@ #define ILI9341_2_HWSPI #endif +#if defined (ILI9341_2_HWSPI) +#define SPI_BEGIN_TRANSACTION() if (_hwspi) spi2->beginTransaction(sspi2) +#define SPI_END_TRANSACTION() if (_hwspi) spi2->endTransaction() +#else +#define SPI_BEGIN_TRANSACTION() (void) +#define SPI_END_TRANSACTION() (void) +#endif + + const uint16_t ili9341_2_colors[]={ILI9341_2_BLACK,ILI9341_2_WHITE,ILI9341_2_RED,ILI9341_2_GREEN,ILI9341_2_BLUE,ILI9341_2_CYAN,ILI9341_2_MAGENTA,\ ILI9341_2_YELLOW,ILI9341_2_NAVY,ILI9341_2_DARKGREEN,ILI9341_2_DARKCYAN,ILI9341_2_MAROON,ILI9341_2_PURPLE,ILI9341_2_OLIVE,\ @@ -99,6 +108,32 @@ static const uint8_t PROGMEM ili9341_2_initcmd[] = { 0x00 // End of list }; +static const uint8_t PROGMEM ili9342_initcmd[] = { + 0xEF, 3, 0x03, 0x80, 0x02, + 0xCF, 3, 0x00, 0xC1, 0x30, + 0xED, 4, 0x64, 0x03, 0x12, 0x81, + 0xE8, 3, 0x85, 0x00, 0x78, + 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, + 0xF7, 1, 0x20, + 0xEA, 2, 0x00, 0x00, + ILI9341_2_PWCTR1 , 1, 0x23, // Power control VRH[5:0] + ILI9341_2_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0] + ILI9341_2_VMCTR1 , 2, 0x2B, 0x2B, // 0x3e, 0x28, // VCM control + ILI9341_2_VMCTR2 , 1, 0xC0, // VCM control2 + ILI9341_2_MADCTL , 1, 0x48, // Memory Access Control + ILI9341_2_VSCRSADD, 1, 0x00, // Vertical scroll zero + ILI9341_2_PIXFMT , 1, 0x55, + ILI9341_2_FRMCTR1 , 2, 0x00, 0x1B, + ILI9341_2_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control + 0xF2, 1, 0x00, // 3Gamma Function Disable + ILI9341_2_GAMMASET , 1, 0x01, // Gamma curve selected + ILI9341_2_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, + ILI9341_2_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, + ILI9341_2_INVON , 0x80, + ILI9341_2_SLPOUT , 0x80, // Exit Sleep + ILI9341_2_DISPON , 0x80, // Display on + 0x00 // End of list +}; ILI9341_2::ILI9341_2(int8_t cs, int8_t mosi, int8_t miso, int8_t sclk, int8_t res, int8_t dc, int8_t bp) : Renderer(ILI9341_2_TFTWIDTH, ILI9341_2_TFTHEIGHT) { _cs = cs; @@ -108,7 +143,16 @@ ILI9341_2::ILI9341_2(int8_t cs, int8_t mosi, int8_t miso, int8_t sclk, int8_t re _res = res; _dc = dc; _bp = bp; - _hwspi = 0; + _hwspi = 1; +} + +// special init for ILI9342 +ILI9341_2::ILI9341_2(int8_t cs, int8_t res, int8_t dc, int8_t bp) : Renderer(ILI9341_2_TFTWIDTH, ILI9341_2_TFTHEIGHT) { + _cs = cs; + _res = res; + _dc = dc; + _bp = bp; + _hwspi = 2; } #define ILI9341_2_CS_LOW digitalWrite( _cs, LOW); @@ -128,12 +172,25 @@ void ILI9341_2::writecmd(uint8_t d) { void ILI9341_2::init(uint16_t width, uint16_t height) { //sspi2 = SPISettings(2500000, MSBFIRST, SPI_MODE3); + if (_hwspi==2) { + iwidth=ILI9341_2_TFTWIDTH; + iheight=ILI9341_2_TFTHEIGHT; + } else { + iwidth=ILI9341_2_TFTHEIGHT; + iheight=ILI9341_2_TFTWIDTH; + } + #ifdef ILI9341_2_HWSPI - spi2 = new SPIClass(HSPI); - spi2->setDataMode(SPI_MODE3); - spi2->setBitOrder(MSBFIRST); - spi2->setFrequency(40000000); - spi2->begin(_sclk, _miso, _mosi, -1); + + sspi2 = SPISettings(40000000, MSBFIRST, SPI_MODE0); + + if (_hwspi==2) { + spi2=&SPI; + } else { + spi2 = new SPIClass(HSPI); + spi2->begin(_sclk, _miso, _mosi, -1); + } + #else pinMode(_mosi, OUTPUT); digitalWrite(_mosi,HIGH); @@ -144,13 +201,31 @@ void ILI9341_2::init(uint16_t width, uint16_t height) { pinMode(_cs, OUTPUT); digitalWrite(_cs,HIGH); + pinMode(_dc, OUTPUT); digitalWrite(_dc,HIGH); - pinMode(_bp, OUTPUT); - digitalWrite(_bp,HIGH); - pinMode(_res, OUTPUT); - digitalWrite(_res,HIGH); + if (_bp>=0) { + pinMode(_bp, OUTPUT); + digitalWrite(_bp,HIGH); + } + + if (_res>=0) { + pinMode(_res, OUTPUT); + digitalWrite(_res, HIGH); + delay(100); + digitalWrite(_res, LOW); + delay(100); + digitalWrite(_res, HIGH); + delay(200); + } else { + SPI_BEGIN_TRANSACTION(); + ILI9341_2_CS_LOW + writecmd(ILI9341_2_SWRESET); // software reset + ILI9341_2_CS_HIGH + SPI_END_TRANSACTION(); + delay(150); + } if (_bp>=0) { #ifdef ILI9341_2_DIMMER @@ -162,16 +237,16 @@ void ILI9341_2::init(uint16_t width, uint16_t height) { #endif } - pinMode(_res, OUTPUT); - digitalWrite(_res, HIGH); - delay(100); - digitalWrite(_res, LOW); - delay(100); - digitalWrite(_res, HIGH); - delay(200); - uint8_t cmd, x, numArgs; - const uint8_t *addr = ili9341_2_initcmd; + const uint8_t *addr; + + if (_hwspi<2) { + addr = ili9341_2_initcmd; + } else { + addr = ili9342_initcmd; + } + + SPI_BEGIN_TRANSACTION(); while ((cmd = pgm_read_byte(addr++)) > 0) { ILI9341_2_CS_LOW @@ -188,11 +263,15 @@ void ILI9341_2::init(uint16_t width, uint16_t height) { ILI9341_2_CS_HIGH if(x & 0x80) delay(120); } + SPI_END_TRANSACTION(); // endWrite(); } void ILI9341_2::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) { +// SPI_BEGIN_TRANSACTION(); +// writecmd(ILI9341_2_INVOFF); +// SPI_END_TRANSACTION(); setRotation(rot); setTextFont(font&3); setTextSize(size&7); @@ -201,9 +280,37 @@ void ILI9341_2::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) { fillScreen(ILI9341_2_BLACK); } -void ILI9341_2::setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) { +void ILI9341_2::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { + + if (!x0 && !y0 && !x1 && !y1) { + ILI9341_2_CS_HIGH + SPI_END_TRANSACTION(); + } else { + ILI9341_2_CS_LOW + SPI_BEGIN_TRANSACTION(); + setAddrWindow_int(x0,y0,x1-x0,y1-y0); + } +} + +void ILI9341_2::pushColors(uint16_t *data, uint8_t len, boolean first) { + uint16_t color; + + while (len--) { + color = *data++; +#ifdef ILI9341_2_HWSPI + spi2->write16(color); +#else + spiwrite16(color); +#endif + } + +} + +void ILI9341_2::setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h) { uint32_t xa = ((uint32_t)x << 16) | (x+w-1); uint32_t ya = ((uint32_t)y << 16) | (y+h-1); + + writecmd(ILI9341_2_CASET); // Column addr set #ifdef ILI9341_2_HWSPI spi2->write32(xa); @@ -218,6 +325,8 @@ void ILI9341_2::setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) { spiwrite32(ya); #endif writecmd(ILI9341_2_RAMWR); // write to RAM + + } void ILI9341_2::drawPixel(int16_t x, int16_t y, uint16_t color) { @@ -227,7 +336,10 @@ void ILI9341_2::drawPixel(int16_t x, int16_t y, uint16_t color) { ILI9341_2_CS_LOW - setAddrWindow(x,y,1,1); + SPI_BEGIN_TRANSACTION(); + + setAddrWindow_int(x,y,1,1); + #ifdef ILI9341_2_HWSPI spi2->write16(color); @@ -236,39 +348,80 @@ void ILI9341_2::drawPixel(int16_t x, int16_t y, uint16_t color) { #endif ILI9341_2_CS_HIGH + SPI_END_TRANSACTION(); } + void ILI9341_2::setRotation(uint8_t m) { + + if (_hwspi<2) { rotation = m % 4; // can't be higher than 3 switch (rotation) { case 0: m = (MADCTL_2_MX | MADCTL_2_BGR); - _width = ILI9341_2_TFTWIDTH; - _height = ILI9341_2_TFTHEIGHT; + _width = iwidth; + _height = iheight; break; case 1: m = (MADCTL_2_MV | MADCTL_2_BGR); - _width = ILI9341_2_TFTHEIGHT; - _height = ILI9341_2_TFTWIDTH; + _width = iheight; + _height = iwidth; break; case 2: m = (MADCTL_2_MY | MADCTL_2_BGR); - _width = ILI9341_2_TFTWIDTH; - _height = ILI9341_2_TFTHEIGHT; + _width = iwidth; + _height = iheight; break; case 3: m = (MADCTL_2_MX | MADCTL_2_MY | MADCTL_2_MV | MADCTL_2_BGR); - _width = ILI9341_2_TFTHEIGHT; - _height = ILI9341_2_TFTWIDTH; + _width = iheight; + _height = iwidth; break; } - ILI9341_2_CS_LOW - writecmd(ILI9341_2_MADCTL); - spiwrite(m); - ILI9341_2_CS_HIGH +} else { + +#define MADCTL_MY 0x80 ///< Bottom to top +#define MADCTL_MX 0x40 ///< Right to left +#define MADCTL_MV 0x20 ///< Reverse Mode +#define MADCTL_ML 0x10 ///< LCD refresh Bottom to top +#define MADCTL_RGB 0x00 ///< Red-Green-Blue pixel order +#define MADCTL_BGR 0x08 ///< Blue-Green-Red pixel order +#define MADCTL_MH 0x04 ///< LCD refresh right to left + + rotation = m % 4; // can't be higher than 3 + switch (rotation) { + case 0: + m = (MADCTL_BGR); + _width = iwidth; + _height = iheight; + break; + case 1: + m = (MADCTL_MV | MADCTL_BGR); + _width = iheight; + _height = iwidth; + break; + case 2: + m = (MADCTL_MY | MADCTL_BGR); + _width = iwidth; + _height = iheight; + break; + case 3: + m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR); + _width = iheight; + _height = iwidth; + break; + } + } + SPI_BEGIN_TRANSACTION(); + ILI9341_2_CS_LOW + writecmd(ILI9341_2_MADCTL); + spiwrite(m); + ILI9341_2_CS_HIGH + SPI_END_TRANSACTION(); } + void ILI9341_2::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { // Rudimentary clipping @@ -277,7 +430,10 @@ void ILI9341_2::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { ILI9341_2_CS_LOW - setAddrWindow(x, y, 1, h); + SPI_BEGIN_TRANSACTION(); + + setAddrWindow_int(x, y, 1, h); + while (h--) { #ifdef ILI9341_2_HWSPI @@ -289,6 +445,7 @@ void ILI9341_2::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { ILI9341_2_CS_HIGH + SPI_END_TRANSACTION(); } void ILI9341_2::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { @@ -299,7 +456,10 @@ void ILI9341_2::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { ILI9341_2_CS_LOW - setAddrWindow(x, y, w, 1); + SPI_BEGIN_TRANSACTION(); + + setAddrWindow_int(x, y, w, 1); + while (w--) { #ifdef ILI9341_2_HWSPI @@ -310,6 +470,8 @@ void ILI9341_2::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { } ILI9341_2_CS_HIGH + + SPI_END_TRANSACTION(); } void ILI9341_2::fillScreen(uint16_t color) { @@ -326,7 +488,9 @@ void ILI9341_2::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t co ILI9341_2_CS_LOW - setAddrWindow(x, y, w-1, h-1); + SPI_BEGIN_TRANSACTION(); + + setAddrWindow_int(x, y, w, h); for (y=h; y>0; y--) { for (x=w; x>0; x--) { @@ -338,11 +502,26 @@ void ILI9341_2::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t co } } ILI9341_2_CS_HIGH + + SPI_END_TRANSACTION(); } + + +void ili9342_bpwr(uint8_t on); + void ILI9341_2::DisplayOnff(int8_t on) { + + if (_hwspi==2) { + ili9342_bpwr(on); + } + if (on) { - writecmd(ILI9341_2_DISPON); //Display on + SPI_BEGIN_TRANSACTION(); + ILI9341_2_CS_LOW + writecmd(ILI9341_2_DISPON); + ILI9341_2_CS_HIGH + SPI_END_TRANSACTION(); if (_bp>=0) { #ifdef ILI9341_2_DIMMER ledcWrite(ESP32_PWM_CHANNEL,dimmer); @@ -351,7 +530,11 @@ void ILI9341_2::DisplayOnff(int8_t on) { #endif } } else { + SPI_BEGIN_TRANSACTION(); + ILI9341_2_CS_LOW writecmd(ILI9341_2_DISPOFF); + ILI9341_2_CS_HIGH + SPI_END_TRANSACTION(); if (_bp>=0) { #ifdef ILI9341_2_DIMMER ledcWrite(ESP32_PWM_CHANNEL,0); @@ -362,13 +545,21 @@ void ILI9341_2::DisplayOnff(int8_t on) { } } +void ili9342_dimm(uint8_t dim); + // dimmer 0-100 void ILI9341_2::dim(uint8_t dim) { dimmer = dim; if (dimmer>15) dimmer=15; dimmer=((float)dimmer/15.0)*255.0; #ifdef ESP32 - ledcWrite(ESP32_PWM_CHANNEL,dimmer); + if (_bp>=0) { + ledcWrite(ESP32_PWM_CHANNEL,dimmer); + } else { + if (_hwspi==2) { + ili9342_dimm(dim); + } + } #endif } diff --git a/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.h b/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.h index d1483dae1..27ff00e5d 100644 --- a/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.h +++ b/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.h @@ -23,7 +23,7 @@ #include #define ILI9341_2_TFTWIDTH 320 -#define ILI9341_2_TFTHEIGHT 480 +#define ILI9341_2_TFTHEIGHT 240 #define ILI9341_2_NOP 0x00 ///< No-op register #define ILI9341_2_SWRESET 0x01 ///< Software reset register @@ -116,6 +116,7 @@ class ILI9341_2 : public Renderer { public: ILI9341_2(int8_t cs, int8_t mosi, int8_t miso, int8_t sclk, int8_t res, int8_t dc, int8_t bp); + ILI9341_2(int8_t cs, int8_t res, int8_t dc, int8_t bp); void init(uint16_t width, uint16_t height); /* @@ -148,7 +149,8 @@ class ILI9341_2 : public Renderer { SPIClass *spi2; SPISettings sspi2; void writecmd(uint8_t d); - void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h); + void setAddrWindow(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); + void setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h); void drawPixel(int16_t x, int16_t y, uint16_t color); void DisplayOnff(int8_t on); void setRotation(uint8_t m); @@ -158,7 +160,7 @@ class ILI9341_2 : public Renderer { void fillScreen(uint16_t color); void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); void dim(uint8_t dim); - + void pushColors(uint16_t *data, uint8_t len, boolean first); void spiwrite(uint8_t c); void spiwrite16(uint16_t c); @@ -174,6 +176,8 @@ class ILI9341_2 : public Renderer { int8_t _dc; int8_t _bp; int8_t _hwspi; + uint16_t iwidth; + uint16_t iheight; }; #endif diff --git a/lib/libesp32/CORE2_Library/AXP192.cpp b/lib/libesp32/CORE2_Library/AXP192.cpp new file mode 100755 index 000000000..6e68245ab --- /dev/null +++ b/lib/libesp32/CORE2_Library/AXP192.cpp @@ -0,0 +1,614 @@ +#include "AXP192.h" + +//#define AXP192_DEBUG + +AXP192::AXP192() +{ +} + +void AXP192::begin(void) +{ + + Wire1.begin(21, 22); + Wire1.setClock(400000); + + //AXP192 30H + Write1Byte(0x30, (Read8bit(0x30) & 0x04) | 0X02); +#ifdef AXP192_DEBUG + Serial.printf("axp: vbus limit off\n"); +#endif + + //AXP192 GPIO1:OD OUTPUT + Write1Byte(0x92, Read8bit(0x92) & 0xf8); +#ifdef AXP192_DEBUG + Serial.printf("axp: gpio1 init\n"); +#endif + //AXP192 GPIO2:OD OUTPUT + Write1Byte(0x93, Read8bit(0x93) & 0xf8); +#ifdef AXP192_DEBUG + Serial.printf("axp: gpio2 init\n"); +#endif + //AXP192 RTC CHG + Write1Byte(0x35, (Read8bit(0x35) & 0x1c) | 0xa2); +#ifdef AXP192_DEBUG + Serial.printf("axp: rtc battery charging enabled\n"); +#endif + SetESPVoltage(3350); +#ifdef AXP192_DEBUG + Serial.printf("axp: esp32 power voltage was set to 3.35v\n"); +#endif + SetLcdVoltage(2800); +#ifdef AXP192_DEBUG + Serial.printf("axp: lcd backlight voltage was set to 2.80v\n"); +#endif + SetLDOVoltage(2, 3300); //Periph power voltage preset (LCD_logic, SD card) +#ifdef AXP192_DEBUG + Serial.printf("axp: lcd logic and sdcard voltage preset to 3.3v\n"); +#endif + SetLDOVoltage(3, 2000); //Vibrator power voltage preset +#ifdef AXP192_DEBUG + Serial.printf("axp: vibrator voltage preset to 2v\n"); +#endif + + SetLDOEnable(2, true); + SetDCDC3(true); // LCD backlight + SetLed(true); + + SetCHGCurrent(kCHG_100mA); + //SetAxpPriphPower(1); + //Serial.printf("axp: lcd_logic and sdcard power enabled\n\n"); + + //pinMode(39, INPUT_PULLUP); + + //AXP192 GPIO4 + Write1Byte(0X95, (Read8bit(0x95) & 0x72) | 0X84); + + Write1Byte(0X36, 0X4C); + + Write1Byte(0x82,0xff); + + SetLCDRSet(0); + delay(100); + SetLCDRSet(1); + delay(100); + // I2C_WriteByteDataAt(0X15,0XFE,0XFF); + + // bus power mode_output + SetBusPowerMode(0); +} + +void AXP192::Write1Byte(uint8_t Addr, uint8_t Data) +{ + Wire1.beginTransmission(0x34); + Wire1.write(Addr); + Wire1.write(Data); + Wire1.endTransmission(); +} + +uint8_t AXP192::Read8bit(uint8_t Addr) +{ + Wire1.beginTransmission(0x34); + Wire1.write(Addr); + Wire1.endTransmission(); + Wire1.requestFrom(0x34, 1); + return Wire1.read(); +} + +uint16_t AXP192::Read12Bit(uint8_t Addr) +{ + uint16_t Data = 0; + uint8_t buf[2]; + ReadBuff(Addr, 2, buf); + Data = ((buf[0] << 4) + buf[1]); // + return Data; +} + +uint16_t AXP192::Read13Bit(uint8_t Addr) +{ + uint16_t Data = 0; + uint8_t buf[2]; + ReadBuff(Addr, 2, buf); + Data = ((buf[0] << 5) + buf[1]); // + return Data; +} + +uint16_t AXP192::Read16bit(uint8_t Addr) +{ + uint16_t ReData = 0; + Wire1.beginTransmission(0x34); + Wire1.write(Addr); + Wire1.endTransmission(); + Wire1.requestFrom(0x34, 2); + for (int i = 0; i < 2; i++) + { + ReData <<= 8; + ReData |= Wire1.read(); + } + return ReData; +} + +uint32_t AXP192::Read24bit(uint8_t Addr) +{ + uint32_t ReData = 0; + Wire1.beginTransmission(0x34); + Wire1.write(Addr); + Wire1.endTransmission(); + Wire1.requestFrom(0x34, 3); + for (int i = 0; i < 3; i++) + { + ReData <<= 8; + ReData |= Wire1.read(); + } + return ReData; +} + +uint32_t AXP192::Read32bit(uint8_t Addr) +{ + uint32_t ReData = 0; + Wire1.beginTransmission(0x34); + Wire1.write(Addr); + Wire1.endTransmission(); + Wire1.requestFrom(0x34, 2); + for (int i = 0; i < 4; i++) + { + ReData <<= 8; + ReData |= Wire1.read(); + } + return ReData; +} + +void AXP192::ReadBuff(uint8_t Addr, uint8_t Size, uint8_t *Buff) +{ + Wire1.beginTransmission(0x34); + Wire1.write(Addr); + Wire1.endTransmission(); + Wire1.requestFrom(0x34, (int)Size); + for (int i = 0; i < Size; i++) + { + *(Buff + i) = Wire1.read(); + } +} + +void AXP192::ScreenBreath(uint8_t brightness) +{ + if (brightness > 12) + { + brightness = 12; + } + uint8_t buf = Read8bit(0x28); + Write1Byte(0x28, ((buf & 0x0f) | (brightness << 4))); +} + +bool AXP192::GetBatState() +{ + if (Read8bit(0x01) | 0x20) + return true; + else + return false; +} +//---------coulombcounter_from_here--------- +//enable: void EnableCoulombcounter(void); +//disable: void DisableCOulombcounter(void); +//stop: void StopCoulombcounter(void); +//clear: void ClearCoulombcounter(void); +//get charge data: uint32_t GetCoulombchargeData(void); +//get discharge data: uint32_t GetCoulombdischargeData(void); +//get coulomb val affter calculation: float GetCoulombData(void); +//------------------------------------------ +void AXP192::EnableCoulombcounter(void) +{ + Write1Byte(0xB8, 0x80); +} + +void AXP192::DisableCoulombcounter(void) +{ + Write1Byte(0xB8, 0x00); +} + +void AXP192::StopCoulombcounter(void) +{ + Write1Byte(0xB8, 0xC0); +} + +void AXP192::ClearCoulombcounter(void) +{ + Write1Byte(0xB8, 0xA0); +} + +uint32_t AXP192::GetCoulombchargeData(void) +{ + return Read32bit(0xB0); +} + +uint32_t AXP192::GetCoulombdischargeData(void) +{ + return Read32bit(0xB4); +} + +float AXP192::GetCoulombData(void) +{ + + uint32_t coin = 0; + uint32_t coout = 0; + + coin = GetCoulombchargeData(); + coout = GetCoulombdischargeData(); + + //c = 65536 * current_LSB * (coin - coout) / 3600 / ADC rate + //Adc rate can be read from 84H ,change this variable if you change the ADC reate + float ccc = 65536 * 0.5 * (coin - coout) / 3600.0 / 25.0; + return ccc; +} + +// Cut all power, except for LDO1 (RTC) +void AXP192::PowerOff(void) +{ + Write1Byte(0x32, Read8bit(0x32) | 0b10000000); +} + +void AXP192::SetAdcState(bool state) +{ + // Enable / Disable all ADCs + Write1Byte(0x82, state ? 0xff : 0x00); +} + +void AXP192::PrepareToSleep(void) +{ + // Disable ADCs + SetAdcState(false); + + // Turn LED off + SetLed(false); + + // Turn LCD backlight off + SetDCDC3(false); +} + +void AXP192::RestoreFromLightSleep(void) +{ + // Turn LCD backlight on + SetDCDC3(true); + + // Turn LED on + SetLed(true); + + // Enable ADCs + SetAdcState(true); +} + +uint8_t AXP192::GetWarningLeve(void) +{ + Wire1.beginTransmission(0x34); + Wire1.write(0x47); + Wire1.endTransmission(); + Wire1.requestFrom(0x34, 1); + uint8_t buf = Wire1.read(); + return (buf & 0x01); +} + +// -- sleep +void AXP192::DeepSleep(uint64_t time_in_us) +{ + PrepareToSleep(); + + if (time_in_us > 0) + { + esp_sleep_enable_timer_wakeup(time_in_us); + } + else + { + esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER); + } + (time_in_us == 0) ? esp_deep_sleep_start() : esp_deep_sleep(time_in_us); + + // Never reached - after deep sleep ESP32 restarts +} + +void AXP192::LightSleep(uint64_t time_in_us) +{ + PrepareToSleep(); + + if (time_in_us > 0) + { + esp_sleep_enable_timer_wakeup(time_in_us); + } + else + { + esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER); + } + esp_light_sleep_start(); + + RestoreFromLightSleep(); +} + +uint8_t AXP192::GetWarningLevel(void) +{ + return Read8bit(0x47) & 0x01; +} + +float AXP192::GetBatVoltage() +{ + float ADCLSB = 1.1 / 1000.0; + uint16_t ReData = Read12Bit(0x78); + return ReData * ADCLSB; +} + +float AXP192::GetBatCurrent() +{ + float ADCLSB = 0.5; + uint16_t CurrentIn = Read13Bit(0x7A); + uint16_t CurrentOut = Read13Bit(0x7C); + return (CurrentIn - CurrentOut) * ADCLSB; +} + +float AXP192::GetVinVoltage() +{ + float ADCLSB = 1.7 / 1000.0; + uint16_t ReData = Read12Bit(0x56); + return ReData * ADCLSB; +} + +float AXP192::GetVinCurrent() +{ + float ADCLSB = 0.625; + uint16_t ReData = Read12Bit(0x58); + return ReData * ADCLSB; +} + +float AXP192::GetVBusVoltage() +{ + float ADCLSB = 1.7 / 1000.0; + uint16_t ReData = Read12Bit(0x5A); + return ReData * ADCLSB; +} + +float AXP192::GetVBusCurrent() +{ + float ADCLSB = 0.375; + uint16_t ReData = Read12Bit(0x5C); + return ReData * ADCLSB; +} + +float AXP192::GetTempInAXP192() +{ + float ADCLSB = 0.1; + const float OFFSET_DEG_C = -144.7; + uint16_t ReData = Read12Bit(0x5E); + return OFFSET_DEG_C + ReData * ADCLSB; +} + +float AXP192::GetBatPower() +{ + float VoltageLSB = 1.1; + float CurrentLCS = 0.5; + uint32_t ReData = Read24bit(0x70); + return VoltageLSB * CurrentLCS * ReData / 1000.0; +} + +float AXP192::GetBatChargeCurrent() +{ + float ADCLSB = 0.5; + uint16_t ReData = Read12Bit(0x7A); + return ReData * ADCLSB; +} +float AXP192::GetAPSVoltage() +{ + float ADCLSB = 1.4 / 1000.0; + uint16_t ReData = Read12Bit(0x7E); + return ReData * ADCLSB; +} + +float AXP192::GetBatCoulombInput() +{ + uint32_t ReData = Read32bit(0xB0); + return ReData * 65536 * 0.5 / 3600 / 25.0; +} + +float AXP192::GetBatCoulombOut() +{ + uint32_t ReData = Read32bit(0xB4); + return ReData * 65536 * 0.5 / 3600 / 25.0; +} + +void AXP192::SetCoulombClear() +{ + Write1Byte(0xB8, 0x20); +} + +void AXP192::SetLDO2(bool State) +{ + uint8_t buf = Read8bit(0x12); + if (State == true) + buf = (1 << 2) | buf; + else + buf = ~(1 << 2) & buf; + Write1Byte(0x12, buf); +} + +void AXP192::SetDCDC3(bool State) +{ + uint8_t buf = Read8bit(0x12); + if (State == true) + buf = (1 << 1) | buf; + else + buf = ~(1 << 1) & buf; + Write1Byte(0x12, buf); +} + +uint8_t AXP192::AXPInState() +{ + return Read8bit(0x00); +} +bool AXP192::isACIN() +{ + return ( Read8bit(0x00) & 0x80 ) ? true : false; +} +bool AXP192::isCharging() +{ + return ( Read8bit(0x00) & 0x04 ) ? true : false; +} +bool AXP192::isVBUS() +{ + return ( Read8bit(0x00) & 0x20 ) ? true : false; +} + +void AXP192::SetLDOVoltage(uint8_t number, uint16_t voltage) +{ + voltage = (voltage > 3300) ? 15 : (voltage / 100) - 18; + switch (number) + { + //uint8_t reg, data; + case 2: + Write1Byte(0x28, (Read8bit(0x28) & 0X0F) | (voltage << 4)); + break; + case 3: + Write1Byte(0x28, (Read8bit(0x28) & 0XF0) | voltage); + break; + } +} + +void AXP192::SetDCVoltage(uint8_t number, uint16_t voltage) +{ + uint8_t addr; + if (number > 2) + return; + voltage = (voltage < 700) ? 0 : (voltage - 700) / 25; + switch (number) + { + case 0: + addr = 0x26; + break; + case 1: + addr = 0x25; + break; + case 2: + addr = 0x27; + break; + } + Write1Byte(addr, (Read8bit(addr) & 0X80) | (voltage & 0X7F)); +} + +void AXP192::SetESPVoltage(uint16_t voltage) +{ + if (voltage >= 3000 && voltage <= 3400) + { + SetDCVoltage(0, voltage); + } +} +void AXP192::SetLcdVoltage(uint16_t voltage) +{ + if (voltage >= 2500 && voltage <= 3300) + { + SetDCVoltage(2, voltage); + } +} + +void AXP192::SetLDOEnable(uint8_t number, bool state) +{ + uint8_t mark = 0x01; + if ((number < 2) || (number > 3)) + return; + + mark <<= number; + if (state) + { + Write1Byte(0x12, (Read8bit(0x12) | mark)); + } + else + { + Write1Byte(0x12, (Read8bit(0x12) & (~mark))); + } +} + +void AXP192::SetLCDRSet(bool state) +{ + uint8_t reg_addr = 0x96; + uint8_t gpio_bit = 0x02; + uint8_t data; + data = Read8bit(reg_addr); + + if (state) + { + data |= gpio_bit; + } + else + { + data &= ~gpio_bit; + } + + Write1Byte(reg_addr, data); +} + +void AXP192::SetBusPowerMode(uint8_t state) +{ + uint8_t data; + if (state == 0) + { + data = Read8bit(0x91); + Write1Byte(0x91, (data & 0X0F) | 0XF0); + + data = Read8bit(0x90); + Write1Byte(0x90, (data & 0XF8) | 0X02); //set GPIO0 to LDO OUTPUT , pullup N_VBUSEN to disable supply from BUS_5V + + data = Read8bit(0x91); + + data = Read8bit(0x12); //read reg 0x12 + Write1Byte(0x12, data | 0x40); //set EXTEN to enable 5v boost + } + else + { + data = Read8bit(0x12); //read reg 0x10 + Write1Byte(0x12, data & 0XBF); //set EXTEN to disable 5v boost + + //delay(2000); + + data = Read8bit(0x90); + Write1Byte(0x90, (data & 0xF8) | 0X01); //set GPIO0 to float , using enternal pulldown resistor to enable supply from BUS_5VS + } +} + +void AXP192::SetLed(uint8_t state) +{ + uint8_t reg_addr=0x94; + uint8_t data; + data=Read8bit(reg_addr); + + if(state) + { + data=data&0XFD; + } + else + { + data|=0X02; + } + + Write1Byte(reg_addr,data); +} + +//set led state(GPIO high active,set 1 to enable amplifier) +void AXP192::SetSpkEnable(uint8_t state) +{ + uint8_t reg_addr=0x94; + uint8_t gpio_bit=0x04; + uint8_t data; + data=Read8bit(reg_addr); + + if(state) + { + data|=gpio_bit; + } + else + { + data&=~gpio_bit; + } + + Write1Byte(reg_addr,data); +} + +void AXP192::SetCHGCurrent(uint8_t state) +{ + uint8_t data = Read8bit(0x33); + data &= 0xf0; + data = data | ( state & 0x0f ); + Write1Byte(0x33,data); +} diff --git a/lib/libesp32/CORE2_Library/AXP192.h b/lib/libesp32/CORE2_Library/AXP192.h new file mode 100755 index 000000000..662c37e8b --- /dev/null +++ b/lib/libesp32/CORE2_Library/AXP192.h @@ -0,0 +1,106 @@ +#ifndef __AXP192_H__ +#define __AXP192_H__ + +#include +#include + +#define SLEEP_MSEC(us) (((uint64_t)us) * 1000L) +#define SLEEP_SEC(us) (((uint64_t)us) * 1000000L) +#define SLEEP_MIN(us) (((uint64_t)us) * 60L * 1000000L) +#define SLEEP_HR(us) (((uint64_t)us) * 60L * 60L * 1000000L) + +#define AXP_ADDR 0X34 + +#define PowerOff(x) SetSleep(x) + +class AXP192 { +public: + + enum CHGCurrent{ + kCHG_100mA = 0, + kCHG_190mA, + kCHG_280mA, + kCHG_360mA, + kCHG_450mA, + kCHG_550mA, + kCHG_630mA, + kCHG_700mA, + kCHG_780mA, + kCHG_880mA, + kCHG_960mA, + kCHG_1000mA, + kCHG_1080mA, + kCHG_1160mA, + kCHG_1240mA, + kCHG_1320mA, + }; + + AXP192(); + void begin(void); + void ScreenBreath(uint8_t brightness); + bool GetBatState(); + + void EnableCoulombcounter(void); + void DisableCoulombcounter(void); + void StopCoulombcounter(void); + void ClearCoulombcounter(void); + uint32_t GetCoulombchargeData(void); + uint32_t GetCoulombdischargeData(void); + float GetCoulombData(void); + void PowerOff(void); + void SetAdcState(bool state); + // -- sleep + void PrepareToSleep(void); + void RestoreFromLightSleep(void); + void DeepSleep(uint64_t time_in_us = 0); + void LightSleep(uint64_t time_in_us = 0); + uint8_t GetWarningLeve(void); + +public: + // void SetChargeVoltage( uint8_t ); + // void SetChargeCurrent( uint8_t ); + float GetBatVoltage(); + float GetBatCurrent(); + float GetVinVoltage(); + float GetVinCurrent(); + float GetVBusVoltage(); + float GetVBusCurrent(); + float GetTempInAXP192(); + float GetBatPower(); + float GetBatChargeCurrent(); + float GetAPSVoltage(); + float GetBatCoulombInput(); + float GetBatCoulombOut(); + uint8_t GetWarningLevel(void); + void SetCoulombClear(); + void SetLDO2( bool State ); + void SetDCDC3( bool State ); + + uint8_t AXPInState(); + bool isACIN(); + bool isCharging(); + bool isVBUS(); + + void SetLDOVoltage(uint8_t number , uint16_t voltage); + void SetDCVoltage(uint8_t number , uint16_t voltage); + void SetESPVoltage(uint16_t voltage); + void SetLcdVoltage(uint16_t voltage); + void SetLDOEnable( uint8_t number ,bool state ); + void SetLCDRSet( bool state ); + void SetBusPowerMode( uint8_t state ); + void SetLed(uint8_t state); + void SetSpkEnable(uint8_t state); + void SetCHGCurrent(uint8_t state); + +private: + void Write1Byte( uint8_t Addr , uint8_t Data ); + uint8_t Read8bit( uint8_t Addr ); + uint16_t Read12Bit( uint8_t Addr); + uint16_t Read13Bit( uint8_t Addr); + uint16_t Read16bit( uint8_t Addr ); + uint32_t Read24bit( uint8_t Addr ); + uint32_t Read32bit( uint8_t Addr ); + void ReadBuff( uint8_t Addr , uint8_t Size , uint8_t *Buff ); +}; + +#endif diff --git a/lib/libesp32/CORE2_Library/BM8563_RTC.cpp b/lib/libesp32/CORE2_Library/BM8563_RTC.cpp new file mode 100755 index 000000000..986ccf897 --- /dev/null +++ b/lib/libesp32/CORE2_Library/BM8563_RTC.cpp @@ -0,0 +1,353 @@ +#include "BM8563_RTC.h" + +BM8563_RTC::BM8563_RTC() +{ +} + +void BM8563_RTC::begin(void) +{ + Wire1.begin(21, 22); + WriteReg(0x00,0x00); + WriteReg(0x01,0x00); + WriteReg(0x0D,0x00); +} + +void BM8563_RTC::WriteReg(uint8_t reg, uint8_t data) +{ + Wire1.beginTransmission(RTC_ADRESS); + Wire1.write(reg); + Wire1.write(data); + Wire1.endTransmission(); +} + +uint8_t BM8563_RTC::ReadReg(uint8_t reg) +{ + Wire1.beginTransmission(0x51); + Wire1.write(reg); + Wire1.endTransmission(); + Wire1.requestFrom(0x51, 1); + return Wire1.read(); +} + +void BM8563_RTC::GetBm8563Time(void) +{ + Wire1.beginTransmission(0x51); + Wire1.write(0x02); + Wire1.endTransmission(); + Wire1.requestFrom(0x51, 7); + while (Wire1.available()) + { + + trdata[0] = Wire1.read(); + trdata[1] = Wire1.read(); + trdata[2] = Wire1.read(); + trdata[3] = Wire1.read(); + trdata[4] = Wire1.read(); + trdata[5] = Wire1.read(); + trdata[6] = Wire1.read(); + } + + DataMask(); + Bcd2asc(); + Str2Time(); +} + +void BM8563_RTC::Str2Time(void) +{ + + Second = (asc[0] - 0x30) * 10 + asc[1] - 0x30; + Minute = (asc[2] - 0x30) * 10 + asc[3] - 0x30; + Hour = (asc[4] - 0x30) * 10 + asc[5] - 0x30; + /* + uint8_t Hour; + uint8_t Week; + uint8_t Day; + uint8_t Month; + uint8_t Year; + */ +} + +void BM8563_RTC::DataMask() +{ + + trdata[0] = trdata[0] & 0x7f; //秒 + trdata[1] = trdata[1] & 0x7f; //分 + trdata[2] = trdata[2] & 0x3f; //时 + + trdata[3] = trdata[3] & 0x3f; //日 + trdata[4] = trdata[4] & 0x07; //星期 + trdata[5] = trdata[5] & 0x1f; //月 + + trdata[6] = trdata[6] & 0xff; //年 +} +/******************************************************************** +函 数 名: void Bcd2asc(void) +功 能: bcd 码转换成 asc 码,供Lcd显示用 +说 明: +调 用: +入口参数: +返 回 值:无 +***********************************************************************/ +void BM8563_RTC::Bcd2asc(void) +{ + uint8_t i, j; + for (j = 0, i = 0; i < 7; i++) + { + asc[j++] = (trdata[i] & 0xf0) >> 4 | 0x30; /*格式为: 秒 分 时 日 月 星期 年 */ + asc[j++] = (trdata[i] & 0x0f) | 0x30; + } +} + +uint8_t BM8563_RTC::Bcd2ToByte(uint8_t Value) +{ + uint8_t tmp = 0; + tmp = ((uint8_t)(Value & (uint8_t)0xF0) >> (uint8_t)0x4) * 10; + return (tmp + (Value & (uint8_t)0x0F)); +} + +uint8_t BM8563_RTC::ByteToBcd2(uint8_t Value) +{ + uint8_t bcdhigh = 0; + + while (Value >= 10) + { + bcdhigh++; + Value -= 10; + } + + return ((uint8_t)(bcdhigh << 4) | Value); +} + +void BM8563_RTC::GetTime(RTC_TimeTypeDef *RTC_TimeStruct) +{ + + //if() + uint8_t buf[3] = {0}; + + Wire1.beginTransmission(0x51); + Wire1.write(0x02); + Wire1.endTransmission(); + Wire1.requestFrom(0x51, 3); + + while (Wire1.available()) + { + + buf[0] = Wire1.read(); + buf[1] = Wire1.read(); + buf[2] = Wire1.read(); + } + + RTC_TimeStruct->Seconds = Bcd2ToByte(buf[0] & 0x7f); //秒 + RTC_TimeStruct->Minutes = Bcd2ToByte(buf[1] & 0x7f); //分 + RTC_TimeStruct->Hours = Bcd2ToByte(buf[2] & 0x3f); //时 +} + +void BM8563_RTC::SetTime(RTC_TimeTypeDef *RTC_TimeStruct) +{ + + if (RTC_TimeStruct == NULL) + return; + + Wire1.beginTransmission(0x51); + Wire1.write(0x02); + Wire1.write(ByteToBcd2(RTC_TimeStruct->Seconds)); + Wire1.write(ByteToBcd2(RTC_TimeStruct->Minutes)); + Wire1.write(ByteToBcd2(RTC_TimeStruct->Hours)); + Wire1.endTransmission(); +} + +void BM8563_RTC::GetDate(RTC_DateTypeDef *RTC_DateStruct) +{ + + uint8_t buf[4] = {0}; + + Wire1.beginTransmission(0x51); + Wire1.write(0x05); + Wire1.endTransmission(); + Wire1.requestFrom(0x51, 4); + + while (Wire1.available()) + { + + buf[0] = Wire1.read(); + buf[1] = Wire1.read(); + buf[2] = Wire1.read(); + buf[3] = Wire1.read(); + } + + RTC_DateStruct->Date = Bcd2ToByte(buf[0] & 0x3f); + RTC_DateStruct->WeekDay = Bcd2ToByte(buf[1] & 0x07); + RTC_DateStruct->Month = Bcd2ToByte(buf[2] & 0x1f); + + if (buf[2] & 0x80) + { + RTC_DateStruct->Year = 1900 + Bcd2ToByte(buf[3] & 0xff); + } + else + { + RTC_DateStruct->Year = 2000 + Bcd2ToByte(buf[3] & 0xff); + } +} + +void BM8563_RTC::SetDate(RTC_DateTypeDef *RTC_DateStruct) +{ + + if (RTC_DateStruct == NULL) + return; + Wire1.beginTransmission(0x51); + Wire1.write(0x05); + Wire1.write(ByteToBcd2(RTC_DateStruct->Date)); + Wire1.write(ByteToBcd2(RTC_DateStruct->WeekDay)); + + if (RTC_DateStruct->Year < 2000) + { + + Wire1.write(ByteToBcd2(RTC_DateStruct->Month) | 0x80); + Wire1.write(ByteToBcd2((uint8_t)(RTC_DateStruct->Year % 100))); + } + else + { + /* code */ + Wire1.write(ByteToBcd2(RTC_DateStruct->Month) | 0x00); + Wire1.write(ByteToBcd2((uint8_t)(RTC_DateStruct->Year % 100))); + } + + Wire1.endTransmission(); +} + +int BM8563_RTC::SetAlarmIRQ(int afterSeconds) +{ + uint8_t reg_value = 0; + reg_value = ReadReg(0x01); + + if (afterSeconds < 0) + { + reg_value &= ~(1 << 0); + WriteReg(0x01, reg_value); + reg_value = 0x03; + WriteReg(0x0E, reg_value); + return -1; + } + + uint8_t type_value = 2; + uint8_t div = 1; + if (afterSeconds > 255) + { + div = 60; + type_value = 0x83; + } + else + { + type_value = 0x82; + } + + afterSeconds = (afterSeconds / div) & 0xFF; + WriteReg(0x0F, afterSeconds); + WriteReg(0x0E, type_value); + + reg_value |= (1 << 0); + reg_value &= ~(1 << 7); + WriteReg(0x01, reg_value); + return afterSeconds * div; +} + +int BM8563_RTC::SetAlarmIRQ(const RTC_TimeTypeDef &RTC_TimeStruct) +{ + uint8_t irq_enable = false; + uint8_t out_buf[4] = {0x80, 0x80, 0x80, 0x80}; + + if (RTC_TimeStruct.Minutes >= 0) + { + irq_enable = true; + out_buf[0] = ByteToBcd2(RTC_TimeStruct.Minutes) & 0x7f; + } + + if (RTC_TimeStruct.Hours >= 0) + { + irq_enable = true; + out_buf[1] = ByteToBcd2(RTC_TimeStruct.Hours) & 0x3f; + } + + out_buf[2] = 0x00; + out_buf[3] = 0x00; + + uint8_t reg_value = ReadReg(0x01); + + if (irq_enable) + { + reg_value |= (1 << 1); + } + else + { + reg_value &= ~(1 << 1); + } + + for (int i = 0; i < 4; i++) + { + WriteReg(0x09 + i, out_buf[i]); + } + WriteReg(0x01, reg_value); + + return irq_enable ? 1 : 0; +} + +int BM8563_RTC::SetAlarmIRQ(const RTC_DateTypeDef &RTC_DateStruct, const RTC_TimeTypeDef &RTC_TimeStruct) +{ + uint8_t irq_enable = false; + uint8_t out_buf[4] = {0x80, 0x80, 0x80, 0x80}; + + if (RTC_TimeStruct.Minutes >= 0) + { + irq_enable = true; + out_buf[0] = ByteToBcd2(RTC_TimeStruct.Minutes) & 0x7f; + } + + if (RTC_TimeStruct.Hours >= 0) + { + irq_enable = true; + out_buf[1] = ByteToBcd2(RTC_TimeStruct.Hours) & 0x3f; + } + + if (RTC_DateStruct.Date >= 0) + { + irq_enable = true; + out_buf[2] = ByteToBcd2(RTC_DateStruct.Date) & 0x3f; + } + + if (RTC_DateStruct.WeekDay >= 0) + { + irq_enable = true; + out_buf[3] = ByteToBcd2(RTC_DateStruct.WeekDay) & 0x07; + } + + uint8_t reg_value = ReadReg(0x01); + + if (irq_enable) + { + reg_value |= (1 << 1); + } + else + { + reg_value &= ~(1 << 1); + } + + for (int i = 0; i < 4; i++) + { + WriteReg(0x09 + i, out_buf[i]); + } + WriteReg(0x01, reg_value); + + return irq_enable ? 1 : 0; +} + +void BM8563_RTC::clearIRQ() +{ + uint8_t data = ReadReg(0x01); + WriteReg(0x01, data & 0xf3); +} +void BM8563_RTC::disableIRQ() +{ + clearIRQ(); + uint8_t data = ReadReg(0x01); + WriteReg(0x01, data & 0xfC); +} diff --git a/lib/libesp32/CORE2_Library/BM8563_RTC.h b/lib/libesp32/CORE2_Library/BM8563_RTC.h new file mode 100755 index 000000000..84c6e0b37 --- /dev/null +++ b/lib/libesp32/CORE2_Library/BM8563_RTC.h @@ -0,0 +1,76 @@ +#ifndef __RTC_H__ +#define __RTC_H__ + +#include + +#define RTC_ADRESS 0x51 + +typedef struct +{ + uint8_t Hours; + uint8_t Minutes; + uint8_t Seconds; +}RTC_TimeTypeDef; + + +typedef struct +{ + uint8_t WeekDay; + uint8_t Month; + uint8_t Date; + uint16_t Year; +}RTC_DateTypeDef; + +class BM8563_RTC { +public: + BM8563_RTC(); + + void begin(void); + void GetBm8563Time(void); + + void SetTime(RTC_TimeTypeDef* RTC_TimeStruct); + void SetDate(RTC_DateTypeDef* RTC_DateStruct); + + void GetTime(RTC_TimeTypeDef* RTC_TimeStruct); + void GetDate(RTC_DateTypeDef* RTC_DateStruct); + + int SetAlarmIRQ(int afterSeconds); + int SetAlarmIRQ( const RTC_TimeTypeDef &RTC_TimeStruct); + int SetAlarmIRQ( const RTC_DateTypeDef &RTC_DateStruct, const RTC_TimeTypeDef &RTC_TimeStruct); + + void clearIRQ(); + void disableIRQ(); + +public: + uint8_t Second; + uint8_t Minute; + uint8_t Hour; + uint8_t Week; + uint8_t Day; + uint8_t Month; + uint8_t Year; + uint8_t DateString[9]; + uint8_t TimeString[9]; + + uint8_t asc[14]; + + +private: + void Bcd2asc(void); + void DataMask(); + void Str2Time(void); + void WriteReg(uint8_t reg, uint8_t data); + uint8_t ReadReg(uint8_t reg); + uint8_t Bcd2ToByte(uint8_t Value); + uint8_t ByteToBcd2(uint8_t Value); + +private: + + /*定义数组用来存储读取的时间数据 */ + uint8_t trdata[7]; + /*定义数组用来存储转换的 asc 码时间数据*/ + //uint8_t asc[14]; + +}; + +#endif diff --git a/lib/libesp32/CORE2_Library/MPU6886.cpp b/lib/libesp32/CORE2_Library/MPU6886.cpp new file mode 100755 index 000000000..418c94b39 --- /dev/null +++ b/lib/libesp32/CORE2_Library/MPU6886.cpp @@ -0,0 +1,252 @@ +#include "MPU6886.h" +#include +#include + +MPU6886::MPU6886(){ + +} + +void MPU6886::I2C_Read_NBytes(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *read_Buffer){ + + Wire1.beginTransmission(driver_Addr); + Wire1.write(start_Addr); + Wire1.endTransmission(false); + uint8_t i = 0; + Wire1.requestFrom(driver_Addr,number_Bytes); + + //! Put read results in the Rx buffer + while (Wire1.available()) { + read_Buffer[i++] = Wire1.read(); + } +} + +void MPU6886::I2C_Write_NBytes(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *write_Buffer){ + + Wire1.beginTransmission(driver_Addr); + Wire1.write(start_Addr); + Wire1.write(*write_Buffer); + Wire1.endTransmission(); + +} + +int MPU6886::Init(void){ + unsigned char tempdata[1]; + unsigned char regdata; + + Wire1.begin(21,22); + + I2C_Read_NBytes(MPU6886_ADDRESS, MPU6886_WHOAMI, 1, tempdata); + if(tempdata[0] != 0x19) + return -1; + delay(1); + + regdata = 0x00; + I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_PWR_MGMT_1, 1, ®data); + delay(10); + + regdata = (0x01<<7); + I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_PWR_MGMT_1, 1, ®data); + delay(10); + + regdata = (0x01<<0); + I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_PWR_MGMT_1, 1, ®data); + delay(10); + + regdata = 0x10; + I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_ACCEL_CONFIG, 1, ®data); + delay(1); + + regdata = 0x18; + I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_GYRO_CONFIG, 1, ®data); + delay(1); + + regdata = 0x01; + I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_CONFIG, 1, ®data); + delay(1); + + regdata = 0x05; + I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_SMPLRT_DIV, 1,®data); + delay(1); + + regdata = 0x00; + I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_INT_ENABLE, 1, ®data); + delay(1); + + regdata = 0x00; + I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_ACCEL_CONFIG2, 1, ®data); + delay(1); + + regdata = 0x00; + I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_USER_CTRL, 1, ®data); + delay(1); + + regdata = 0x00; + I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_FIFO_EN, 1, ®data); + delay(1); + + regdata = 0x22; + I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_INT_PIN_CFG, 1, ®data); + delay(1); + + regdata = 0x01; + I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_INT_ENABLE, 1, ®data); + + delay(100); + getGres(); + getAres(); + return 0; +} + +void MPU6886::getAccelAdc(int16_t* ax, int16_t* ay, int16_t* az){ + + uint8_t buf[6]; + I2C_Read_NBytes(MPU6886_ADDRESS,MPU6886_ACCEL_XOUT_H,6,buf); + + *ax=((int16_t)buf[0]<<8)|buf[1]; + *ay=((int16_t)buf[2]<<8)|buf[3]; + *az=((int16_t)buf[4]<<8)|buf[5]; + +} +void MPU6886::getGyroAdc(int16_t* gx, int16_t* gy, int16_t* gz){ + + uint8_t buf[6]; + I2C_Read_NBytes(MPU6886_ADDRESS,MPU6886_GYRO_XOUT_H,6,buf); + + *gx=((uint16_t)buf[0]<<8)|buf[1]; + *gy=((uint16_t)buf[2]<<8)|buf[3]; + *gz=((uint16_t)buf[4]<<8)|buf[5]; + +} + +void MPU6886::getTempAdc(int16_t *t){ + + uint8_t buf[2]; + I2C_Read_NBytes(MPU6886_ADDRESS,MPU6886_TEMP_OUT_H,2,buf); + + *t=((uint16_t)buf[0]<<8)|buf[1]; +} + + + +//!俯仰,航向,横滚:pitch,yaw,roll,指三维空间中飞行器的旋转状态。 +void MPU6886::getAhrsData(float *pitch,float *roll,float *yaw){ + + float accX = 0; + float accY = 0; + float accZ = 0; + + float gyroX = 0; + float gyroY = 0; + float gyroZ = 0; + + + getGyroData(&gyroX,&gyroY,&gyroZ); + getAccelData(&accX,&accY,&accZ); + + MahonyAHRSupdateIMU(gyroX * DEG_TO_RAD, gyroY * DEG_TO_RAD, gyroZ * DEG_TO_RAD, accX, accY, accZ,pitch,roll,yaw); + +} + +void MPU6886::getGres(){ + + switch (Gyscale) + { + // Possible gyro scales (and their register bit settings) are: + case GFS_250DPS: + gRes = 250.0/32768.0; + break; + case GFS_500DPS: + gRes = 500.0/32768.0; + break; + case GFS_1000DPS: + gRes = 1000.0/32768.0; + break; + case GFS_2000DPS: + gRes = 2000.0/32768.0; + break; + } + +} + + +void MPU6886::getAres(){ + switch (Acscale) + { + // Possible accelerometer scales (and their register bit settings) are: + // 2 Gs (00), 4 Gs (01), 8 Gs (10), and 16 Gs (11). + // Here's a bit of an algorith to calculate DPS/(ADC tick) based on that 2-bit value: + case AFS_2G: + aRes = 2.0/32768.0; + break; + case AFS_4G: + aRes = 4.0/32768.0; + break; + case AFS_8G: + aRes = 8.0/32768.0; + break; + case AFS_16G: + aRes = 16.0/32768.0; + break; + } + +} + +void MPU6886::SetGyroFsr(Gscale scale) +{ + //return IIC_Write_Byte(MPU_GYRO_CFG_REG,scale<<3);//设置陀螺仪满量程范围 + unsigned char regdata; + regdata = (scale<<3); + I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_GYRO_CONFIG, 1, ®data); + delay(10); + + Gyscale = scale; + getGres(); +} + +void MPU6886::SetAccelFsr(Ascale scale) +{ + unsigned char regdata; + regdata = (scale<<3); + I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_ACCEL_CONFIG, 1, ®data); + delay(10); + + Acscale = scale; + getAres(); +} + + + + +void MPU6886::getAccelData(float* ax, float* ay, float* az){ + + + int16_t accX = 0; + int16_t accY = 0; + int16_t accZ = 0; + getAccelAdc(&accX,&accY,&accZ); + + + *ax = (float)accX * aRes; + *ay = (float)accY * aRes; + *az = (float)accZ * aRes; + +} + +void MPU6886::getGyroData(float* gx, float* gy, float* gz){ + int16_t gyroX = 0; + int16_t gyroY = 0; + int16_t gyroZ = 0; + getGyroAdc(&gyroX,&gyroY,&gyroZ); + + *gx = (float)gyroX * gRes; + *gy = (float)gyroY * gRes; + *gz = (float)gyroZ * gRes; +} + +void MPU6886::getTempData(float *t){ + + int16_t temp = 0; + getTempAdc(&temp); + + *t = (float)temp / 326.8 + 25.0; +} diff --git a/lib/libesp32/CORE2_Library/MPU6886.h b/lib/libesp32/CORE2_Library/MPU6886.h new file mode 100755 index 000000000..b1a0fb16b --- /dev/null +++ b/lib/libesp32/CORE2_Library/MPU6886.h @@ -0,0 +1,98 @@ +/* + Note: The MPU6886 is an I2C sensor and uses the Arduino Wire library. + Because the sensor is not 5V tolerant, we are using a 3.3 V 8 MHz Pro Mini or + a 3.3 V Teensy 3.1. We have disabled the internal pull-ups used by the Wire + library in the Wire.h/twi.c utility file. We are also using the 400 kHz fast + I2C mode by setting the TWI_FREQ to 400000L /twi.h utility file. + */ +#ifndef _MPU6886_H_ +#define _MPU6886_H_ + +#include +#include +#include "MahonyAHRS.h" + +#define MPU6886_ADDRESS 0x68 +#define MPU6886_WHOAMI 0x75 +#define MPU6886_ACCEL_INTEL_CTRL 0x69 +#define MPU6886_SMPLRT_DIV 0x19 +#define MPU6886_INT_PIN_CFG 0x37 +#define MPU6886_INT_ENABLE 0x38 +#define MPU6886_ACCEL_XOUT_H 0x3B +#define MPU6886_ACCEL_XOUT_L 0x3C +#define MPU6886_ACCEL_YOUT_H 0x3D +#define MPU6886_ACCEL_YOUT_L 0x3E +#define MPU6886_ACCEL_ZOUT_H 0x3F +#define MPU6886_ACCEL_ZOUT_L 0x40 + +#define MPU6886_TEMP_OUT_H 0x41 +#define MPU6886_TEMP_OUT_L 0x42 + +#define MPU6886_GYRO_XOUT_H 0x43 +#define MPU6886_GYRO_XOUT_L 0x44 +#define MPU6886_GYRO_YOUT_H 0x45 +#define MPU6886_GYRO_YOUT_L 0x46 +#define MPU6886_GYRO_ZOUT_H 0x47 +#define MPU6886_GYRO_ZOUT_L 0x48 + +#define MPU6886_USER_CTRL 0x6A +#define MPU6886_PWR_MGMT_1 0x6B +#define MPU6886_PWR_MGMT_2 0x6C +#define MPU6886_CONFIG 0x1A +#define MPU6886_GYRO_CONFIG 0x1B +#define MPU6886_ACCEL_CONFIG 0x1C +#define MPU6886_ACCEL_CONFIG2 0x1D +#define MPU6886_FIFO_EN 0x23 + +//#define G (9.8) +#define RtA 57.324841 +#define AtR 0.0174533 +#define Gyro_Gr 0.0010653 + +class MPU6886 { + public: + enum Ascale { + AFS_2G = 0, + AFS_4G, + AFS_8G, + AFS_16G + }; + + enum Gscale { + GFS_250DPS = 0, + GFS_500DPS, + GFS_1000DPS, + GFS_2000DPS + }; + + Gscale Gyscale = GFS_2000DPS; + Ascale Acscale = AFS_8G; + public: + MPU6886(); + int Init(void); + void getAccelAdc(int16_t* ax, int16_t* ay, int16_t* az); + void getGyroAdc(int16_t* gx, int16_t* gy, int16_t* gz); + void getTempAdc(int16_t *t); + + void getAccelData(float* ax, float* ay, float* az); + void getGyroData(float* gx, float* gy, float* gz); + void getTempData(float *t); + + void SetGyroFsr(Gscale scale); + void SetAccelFsr(Ascale scale); + + void getAhrsData(float *pitch,float *roll,float *yaw); + + public: + float aRes, gRes; + + private: + + private: + void I2C_Read_NBytes(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *read_Buffer); + void I2C_Write_NBytes(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *write_Buffer); + void getGres(); + void getAres(); + +}; +#endif \ No newline at end of file diff --git a/lib/libesp32/CORE2_Library/MahonyAHRS.cpp b/lib/libesp32/CORE2_Library/MahonyAHRS.cpp new file mode 100755 index 000000000..cae005075 --- /dev/null +++ b/lib/libesp32/CORE2_Library/MahonyAHRS.cpp @@ -0,0 +1,254 @@ +//===================================================================================================== +// MahonyAHRS.c +//===================================================================================================== +// +// Madgwick's implementation of Mayhony's AHRS algorithm. +// See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms +// +// Date Author Notes +// 29/09/2011 SOH Madgwick Initial release +// 02/10/2011 SOH Madgwick Optimised for reduced CPU load +// +//===================================================================================================== + +//--------------------------------------------------------------------------------------------------- +// Header files + +#include "MahonyAHRS.h" +#include "Arduino.h" +#include +//--------------------------------------------------------------------------------------------------- +// Definitions + +#define sampleFreq 25.0f // sample frequency in Hz +#define twoKpDef (2.0f * 1.0f) // 2 * proportional gain +#define twoKiDef (2.0f * 0.0f) // 2 * integral gain + +//#define twoKiDef (0.0f * 0.0f) + +//--------------------------------------------------------------------------------------------------- +// Variable definitions + +volatile float twoKp = twoKpDef; // 2 * proportional gain (Kp) +volatile float twoKi = twoKiDef; // 2 * integral gain (Ki) +volatile float q0 = 1.0, q1 = 0.0, q2 = 0.0, q3 = 0.0; // quaternion of sensor frame relative to auxiliary frame +volatile float integralFBx = 0.0f, integralFBy = 0.0f, integralFBz = 0.0f; // integral error terms scaled by Ki + +//--------------------------------------------------------------------------------------------------- +// Function declarations + +//float invSqrt(float x); + +//==================================================================================================== +// Functions + +//--------------------------------------------------------------------------------------------------- +// AHRS algorithm update + +void MahonyAHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz) { + float recipNorm; + float q0q0, q0q1, q0q2, q0q3, q1q1, q1q2, q1q3, q2q2, q2q3, q3q3; + float hx, hy, bx, bz; + float halfvx, halfvy, halfvz, halfwx, halfwy, halfwz; + float halfex, halfey, halfez; + float qa, qb, qc; + + // Use IMU algorithm if magnetometer measurement invalid (avoids NaN in magnetometer normalisation) + if((mx == 0.0f) && (my == 0.0f) && (mz == 0.0f)) { + //MahonyAHRSupdateIMU(gx, gy, gz, ax, ay, az); + return; + } + + // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) + if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) { + + // Normalise accelerometer measurement + recipNorm = sqrt(ax * ax + ay * ay + az * az); + ax *= recipNorm; + ay *= recipNorm; + az *= recipNorm; + + // Normalise magnetometer measurement + recipNorm = sqrt(mx * mx + my * my + mz * mz); + mx *= recipNorm; + my *= recipNorm; + mz *= recipNorm; + + // Auxiliary variables to avoid repeated arithmetic + q0q0 = q0 * q0; + q0q1 = q0 * q1; + q0q2 = q0 * q2; + q0q3 = q0 * q3; + q1q1 = q1 * q1; + q1q2 = q1 * q2; + q1q3 = q1 * q3; + q2q2 = q2 * q2; + q2q3 = q2 * q3; + q3q3 = q3 * q3; + + // Reference direction of Earth's magnetic field + hx = 2.0f * (mx * (0.5f - q2q2 - q3q3) + my * (q1q2 - q0q3) + mz * (q1q3 + q0q2)); + hy = 2.0f * (mx * (q1q2 + q0q3) + my * (0.5f - q1q1 - q3q3) + mz * (q2q3 - q0q1)); + bx = sqrt(hx * hx + hy * hy); + bz = 2.0f * (mx * (q1q3 - q0q2) + my * (q2q3 + q0q1) + mz * (0.5f - q1q1 - q2q2)); + + // Estimated direction of gravity and magnetic field + halfvx = q1q3 - q0q2; + halfvy = q0q1 + q2q3; + halfvz = q0q0 - 0.5f + q3q3; + halfwx = bx * (0.5f - q2q2 - q3q3) + bz * (q1q3 - q0q2); + halfwy = bx * (q1q2 - q0q3) + bz * (q0q1 + q2q3); + halfwz = bx * (q0q2 + q1q3) + bz * (0.5f - q1q1 - q2q2); + + // Error is sum of cross product between estimated direction and measured direction of field vectors + halfex = (ay * halfvz - az * halfvy) + (my * halfwz - mz * halfwy); + halfey = (az * halfvx - ax * halfvz) + (mz * halfwx - mx * halfwz); + halfez = (ax * halfvy - ay * halfvx) + (mx * halfwy - my * halfwx); + + // Compute and apply integral feedback if enabled + if(twoKi > 0.0f) { + integralFBx += twoKi * halfex * (1.0f / sampleFreq); // integral error scaled by Ki + integralFBy += twoKi * halfey * (1.0f / sampleFreq); + integralFBz += twoKi * halfez * (1.0f / sampleFreq); + gx += integralFBx; // apply integral feedback + gy += integralFBy; + gz += integralFBz; + } + else { + integralFBx = 0.0f; // prevent integral windup + integralFBy = 0.0f; + integralFBz = 0.0f; + } + + // Apply proportional feedback + gx += twoKp * halfex; + gy += twoKp * halfey; + gz += twoKp * halfez; + } + + // Integrate rate of change of quaternion + gx *= (0.5f * (1.0f / sampleFreq)); // pre-multiply common factors + gy *= (0.5f * (1.0f / sampleFreq)); + gz *= (0.5f * (1.0f / sampleFreq)); + qa = q0; + qb = q1; + qc = q2; + q0 += (-qb * gx - qc * gy - q3 * gz); + q1 += (qa * gx + qc * gz - q3 * gy); + q2 += (qa * gy - qb * gz + q3 * gx); + q3 += (qa * gz + qb * gy - qc * gx); + + // Normalise quaternion + recipNorm = sqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3); + q0 *= recipNorm; + q1 *= recipNorm; + q2 *= recipNorm; + q3 *= recipNorm; +} + +//--------------------------------------------------------------------------------------------------- +// IMU algorithm update + +void MahonyAHRSupdateIMU(float gx, float gy, float gz, float ax, float ay, float az,float *pitch,float *roll,float *yaw) { + float recipNorm; + float halfvx, halfvy, halfvz; + float halfex, halfey, halfez; + float qa, qb, qc; + + + // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) + if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) { + + // Normalise accelerometer measurement + recipNorm = invSqrt(ax * ax + ay * ay + az * az); + ax *= recipNorm; + ay *= recipNorm; + az *= recipNorm; + + // Estimated direction of gravity and vector perpendicular to magnetic flux + halfvx = q1 * q3 - q0 * q2; + halfvy = q0 * q1 + q2 * q3; + halfvz = q0 * q0 - 0.5f + q3 * q3; + + + + // Error is sum of cross product between estimated and measured direction of gravity + halfex = (ay * halfvz - az * halfvy); + halfey = (az * halfvx - ax * halfvz); + halfez = (ax * halfvy - ay * halfvx); + + // Compute and apply integral feedback if enabled + if(twoKi > 0.0f) { + integralFBx += twoKi * halfex * (1.0f / sampleFreq); // integral error scaled by Ki + integralFBy += twoKi * halfey * (1.0f / sampleFreq); + integralFBz += twoKi * halfez * (1.0f / sampleFreq); + gx += integralFBx; // apply integral feedback + gy += integralFBy; + gz += integralFBz; + } + else { + integralFBx = 0.0f; // prevent integral windup + integralFBy = 0.0f; + integralFBz = 0.0f; + } + + // Apply proportional feedback + gx += twoKp * halfex; + gy += twoKp * halfey; + gz += twoKp * halfez; + } + + // Integrate rate of change of quaternion + gx *= (0.5f * (1.0f / sampleFreq)); // pre-multiply common factors + gy *= (0.5f * (1.0f / sampleFreq)); + gz *= (0.5f * (1.0f / sampleFreq)); + qa = q0; + qb = q1; + qc = q2; + q0 += (-qb * gx - qc * gy - q3 * gz); + q1 += (qa * gx + qc * gz - q3 * gy); + q2 += (qa * gy - qb * gz + q3 * gx); + q3 += (qa * gz + qb * gy - qc * gx); + + // Normalise quaternion + recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3); + q0 *= recipNorm; + q1 *= recipNorm; + q2 *= recipNorm; + q3 *= recipNorm; + + + *pitch = asin(-2 * q1 * q3 + 2 * q0* q2); // pitch + *roll = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1); // roll + *yaw = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3); //yaw + + *pitch *= RAD_TO_DEG; + *yaw *= RAD_TO_DEG; + // Declination of SparkFun Electronics (40°05'26.6"N 105°11'05.9"W) is + // 8° 30' E ± 0° 21' (or 8.5°) on 2016-07-19 + // - http://www.ngdc.noaa.gov/geomag-web/#declination + *yaw -= 8.5; + *roll *= RAD_TO_DEG; + + ///Serial.printf("%f %f %f \r\n", pitch, roll, yaw); +} + +//--------------------------------------------------------------------------------------------------- +// Fast inverse square-root +// See: http://en.wikipedia.org/wiki/Fast_inverse_square_root + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +float invSqrt(float x) { + float halfx = 0.5f * x; + float y = x; + long i = *(long*)&y; + i = 0x5f3759df - (i>>1); + y = *(float*)&i; + y = y * (1.5f - (halfx * y * y)); + return y; +} +#pragma GCC diagnostic pop +//==================================================================================================== +// END OF CODE +//==================================================================================================== diff --git a/lib/libesp32/CORE2_Library/MahonyAHRS.h b/lib/libesp32/CORE2_Library/MahonyAHRS.h new file mode 100755 index 000000000..bae082d24 --- /dev/null +++ b/lib/libesp32/CORE2_Library/MahonyAHRS.h @@ -0,0 +1,33 @@ +//===================================================================================================== +// MahonyAHRS.h +//===================================================================================================== +// +// Madgwick's implementation of Mayhony's AHRS algorithm. +// See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms +// +// Date Author Notes +// 29/09/2011 SOH Madgwick Initial release +// 02/10/2011 SOH Madgwick Optimised for reduced CPU load +// +//===================================================================================================== +#ifndef MahonyAHRS_h +#define MahonyAHRS_h + +//---------------------------------------------------------------------------------------------------- +// Variable declaration + +extern volatile float twoKp; // 2 * proportional gain (Kp) +extern volatile float twoKi; // 2 * integral gain (Ki) +//volatile float q0, q1, q2, q3; // quaternion of sensor frame relative to auxiliary frame + +//--------------------------------------------------------------------------------------------------- +// Function declarations + +void MahonyAHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz); +//void MahonyAHRSupdateIMU(float gx, float gy, float gz, float ax, float ay, float az); +void MahonyAHRSupdateIMU(float gx, float gy, float gz, float ax, float ay, float az,float *pitch,float *roll,float *yaw); +float invSqrt(float x); +#endif +//===================================================================================================== +// End of file +//===================================================================================================== diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino index d2049af81..259d86c8f 100755 --- a/tasmota/xdrv_10_scripter.ino +++ b/tasmota/xdrv_10_scripter.ino @@ -1919,6 +1919,19 @@ chknext: fvar = xPortGetCoreID(); goto exit; } +#ifdef USE_M5STACK_CORE2 + if (!strncmp(vname, "c2ps(", 5)) { + lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, 0); + while (*lp==' ') lp++; + float fvar1; + lp = GetNumericArgument(lp, OPER_EQU, &fvar1, 0); + fvar = core2_setaxppin(fvar, fvar1); + lp++; + len=0; + goto exit; + } +#endif // USE_M5STACK_CORE2 + #ifdef USE_SCRIPT_TASK if (!strncmp(vname, "ct(", 3)) { lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, 0); @@ -2667,7 +2680,7 @@ chknext: len++; goto exit; } -#if defined(ESP32) && (defined(USE_I2S_AUDIO) || defined(USE_TTGO_WATCH)) +#if defined(ESP32) && (defined(USE_I2S_AUDIO) || defined(USE_TTGO_WATCH) || defined(USE_M5STACK_CORE2)) if (!strncmp(vname, "pl(", 3)) { char path[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 3, OPER_EQU, path, 0); @@ -2860,7 +2873,7 @@ chknext: len = 0; goto strexit; } -#if defined(ESP32) && (defined(USE_I2S_AUDIO) || defined(USE_TTGO_WATCH)) +#if defined(ESP32) && (defined(USE_I2S_AUDIO) || defined(USE_TTGO_WATCH) || defined(USE_M5STACK_CORE2)) if (!strncmp(vname, "say(", 4)) { char text[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 4, OPER_EQU, text, 0); @@ -3161,7 +3174,7 @@ chknext: goto exit; } #endif // USE_TTGO_WATCH -#if defined(USE_TTGO_WATCH) && defined(USE_FT5206) +#if defined(USE_FT5206) if (!strncmp(vname, "wtch(", 5)) { lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, 0); fvar = Touch_Status(fvar); @@ -7550,7 +7563,7 @@ bool Xdrv10(uint8_t function) // fs on SD card #ifdef ESP32 if (PinUsed(GPIO_SPI_MOSI) && PinUsed(GPIO_SPI_MISO) && PinUsed(GPIO_SPI_CLK)) { - SPI.begin(Pin(GPIO_SPI_CLK),Pin(GPIO_SPI_MISO),Pin(GPIO_SPI_MOSI), -1); + SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); } #endif // ESP32 fsp = &SD; diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino index 515a6b90b..2fa7d95d8 100644 --- a/tasmota/xdrv_13_display.ino +++ b/tasmota/xdrv_13_display.ino @@ -2089,8 +2089,8 @@ uint32_t Touch_Status(uint32_t sel) { #ifdef USE_TOUCH_BUTTONS -void Touch_MQTT(uint8_t index, const char *cp) { - ResponseTime_P(PSTR(",\"FT5206\":{\"%s%d\":\"%d\"}}"), cp, index+1, buttons[index]->vpower.on_off); +void Touch_MQTT(uint8_t index, const char *cp, uint32_t val) { + ResponseTime_P(PSTR(",\"FT5206\":{\"%s%d\":\"%d\"}}"), cp, index+1, val); MqttPublishTeleSensor(); } @@ -2100,6 +2100,10 @@ void Touch_RDW_BUTT(uint32_t count, uint32_t pwr) { else buttons[count]->vpower.on_off = 0; } +#ifdef USE_M5STACK_CORE2 +uint8_t tbstate[3]; +#endif + // check digitizer hit void Touch_Check(void(*rotconvert)(int16_t *x, int16_t *y)) { uint16_t temp; @@ -2113,6 +2117,26 @@ uint8_t vbutt=0; if (renderer) { +#ifdef USE_M5STACK_CORE2 + // handle 3 built in touch buttons + uint16_t xcenter = 80; +#define TDELTA 30 +#define TYPOS 275 + + for (uint32_t tbut = 0; tbut < 3; tbut++) { + if (pLoc.x>(xcenter-TDELTA) && pLoc.x<(xcenter+TDELTA) && pLoc.y>(TYPOS-TDELTA) && pLoc.y<(TYPOS+TDELTA)) { + // hit a button + if (!(tbstate[tbut] & 1)) { + // pressed + tbstate[tbut] |= 1; + //AddLog_P(LOG_LEVEL_INFO, PSTR("tbut: %d pressed"), tbut); + Touch_MQTT(tbut, "BIB", tbstate[tbut] & 1); + } + } + xcenter += 100; + } +#endif + rotconvert(&pLoc.x, &pLoc.y); //AddLog_P(LOG_LEVEL_INFO, PSTR("touch %d - %d"), pLoc.x, pLoc.y); @@ -2142,7 +2166,7 @@ uint8_t vbutt=0; cp="PBT"; } buttons[count]->xdrawButton(buttons[count]->vpower.on_off); - Touch_MQTT(count,cp); + Touch_MQTT(count, cp, buttons[count]->vpower.on_off); } } } @@ -2156,6 +2180,16 @@ uint8_t vbutt=0; } } else { // no hit +#ifdef USE_M5STACK_CORE2 + for (uint32_t tbut = 0; tbut < 3; tbut++) { + if (tbstate[tbut] & 1) { + // released + tbstate[tbut] &= 0xfe; + Touch_MQTT(tbut, "BIB", tbstate[tbut] & 1); + //AddLog_P(LOG_LEVEL_INFO, PSTR("tbut: %d released"), tbut); + } + } +#endif for (uint8_t count=0; countpress(false); @@ -2164,7 +2198,7 @@ uint8_t vbutt=0; if (buttons[count]->vpower.is_pushbutton) { // push button buttons[count]->vpower.on_off = 0; - Touch_MQTT(count,"PBT"); + Touch_MQTT(count,"PBT", buttons[count]->vpower.on_off); buttons[count]->xdrawButton(buttons[count]->vpower.on_off); } } diff --git a/tasmota/xdrv_84_core2.ino b/tasmota/xdrv_84_core2.ino new file mode 100644 index 000000000..e3925eef6 --- /dev/null +++ b/tasmota/xdrv_84_core2.ino @@ -0,0 +1,266 @@ +/* + xdrv_84_core2.ino - ESP32 m5stack core2 support for Tasmota + + Copyright (C) 2020 Gerhard Mutz and Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* remaining work: + +i2s microphone, at least as loudness sensor +rtc use after reboot, sync with internet on regular intervals. + +*/ + +#ifdef ESP32 +#ifdef USE_M5STACK_CORE2 + +#include +#include +#include +#include +#include + +#define XDRV_84 84 + +struct CORE2_globs { + AXP192 Axp; + MPU6886 Mpu; + BM8563_RTC Rtc; + bool ready; + bool tset; + uint32_t shutdownseconds; + uint8_t shutdowndelay; + +} core2_globs; + +struct CORE2_ADC { + float vbus_v; + float batt_v; + float temp; + int16_t x; + int16_t y; + int16_t z; +} core2_adc; + +// cause SC card is needed by scripter +void CORE2_Module_Init(void) { + + // m5stack uses pin 38 not selectable in tasmota + SPI.setFrequency(40000000); + SPI.begin(18, 38, 23, -1); + // establish power chip on wire1 SDA 21, SCL 22 + core2_globs.Axp.begin(); + I2cSetActiveFound(AXP_ADDR, "AXP192"); + + core2_globs.Axp.SetAdcState(true); + + core2_globs.Mpu.Init(); + I2cSetActiveFound(MPU6886_ADDRESS, "MPU6886"); + + core2_globs.Rtc.begin(); + I2cSetActiveFound(RTC_ADRESS, "RTC"); + + core2_globs.ready = true; +} + + +void CORE2_Init(void) { + +} + +void CORE2_audio_power(bool power) { + core2_globs.Axp.SetSpkEnable(power); +} + +#ifdef USE_WEBSERVER +const char HTTP_CORE2[] PROGMEM = + "{s}VBUS Voltage" "{m}%s V" "{e}" + "{s}BATT Voltage" "{m}%s V" "{e}" + "{s}Chip Temperature" "{m}%s C" "{e}"; +#ifdef USE_MPU6886 +const char HTTP_CORE2_MPU[] PROGMEM = + "{s}MPU x" "{m}%d mg" "{e}" + "{s}MPU y" "{m}%d mg" "{e}" + "{s}MPU z" "{m}%d mg" "{e}"; +#endif // USE_MPU6886 +#endif // USE_WEBSERVER + + +void CORE2_loop(uint32_t flg) { +} + +void CORE2_WebShow(uint32_t json) { + + char vstring[32]; + char bvstring[32]; + char tstring[32]; + dtostrfd(core2_adc.vbus_v, 3, vstring); + dtostrfd(core2_adc.batt_v, 3, bvstring); + dtostrfd(core2_adc.temp, 2, tstring); + + if (json) { + ResponseAppend_P(PSTR(",\"CORE2\":{\"VBV\":%s,\"BV\":%s,\"CT\":%s"), vstring, bvstring, tstring); + +#ifdef USE_MPU6886 + ResponseAppend_P(PSTR(",\"MPUX\":%d,\"MPUY\":%d,\"MPUZ\":%d"), core2_adc.x, core2_adc.y, core2_adc.z); +#endif + ResponseJsonEnd(); + } else { + WSContentSend_PD(HTTP_CORE2, vstring, bvstring, tstring); + +#ifdef USE_MPU6886 + WSContentSend_PD(HTTP_CORE2_MPU, core2_adc.x, core2_adc.y, core2_adc.z); +#endif // USE_MPU6886 + } +} + +const char CORE2_Commands[] PROGMEM = "CORE2|" + "SHUTDOWN"; + +void (* const CORE2_Command[])(void) PROGMEM = { + &CORE2_Shutdown}; + + +void CORE2_Shutdown(void) { + if (XdrvMailbox.payload >= 30) { + core2_globs.shutdownseconds = XdrvMailbox.payload; + core2_globs.shutdowndelay = 10; + } + ResponseCmndNumber(XdrvMailbox.payload -2); +} + +void CORE2_DoShutdown(void) { + SettingsSaveAll(); + RtcSettingsSave(); + core2_globs.Rtc.clearIRQ(); + core2_globs.Rtc.SetAlarmIRQ(core2_globs.shutdownseconds); + delay(10); + core2_globs.Axp.PowerOff(); +} + +extern uint8_t tbstate[3]; + +float core2_setaxppin(uint32_t sel, uint32_t val) { + switch (sel) { + case 0: + core2_globs.Axp.SetLed(val); + break; + case 1: + core2_globs.Axp.SetLDOEnable(3, val); + break; + case 2: + if (val<1 || val>3) val = 1; + return tbstate[val - 1] & 1; + break; + + } + return 0; +} + +void core2_disp_pwr(uint8_t on) { + core2_globs.Axp.SetDCDC3(on); +} + +// display dimmer ranges from 0-15 +// very little effect +void core2_disp_dim(uint8_t dim) { +uint16_t voltage = 2200; + + voltage += ((uint32_t)dim*1200)/15; + core2_globs.Axp.SetLcdVoltage(voltage); + + +// core2_globs.Axp.ScreenBreath(dim); + +} + +void CORE2_EverySecond(void) { + if (core2_globs.ready) { + CORE2_GetADC(); + + if (RtcTime.year>2000 && core2_globs.tset==false) { + RTC_TimeTypeDef RTCtime; + RTCtime.Hours = RtcTime.hour; + RTCtime.Minutes = RtcTime.minute; + RTCtime.Seconds = RtcTime.second; + core2_globs.Rtc.SetTime(&RTCtime); + core2_globs.tset = true; + } + + if (core2_globs.shutdowndelay) { + core2_globs.shutdowndelay--; + if (!core2_globs.shutdowndelay) { + CORE2_DoShutdown(); + } + } + } +} + +// currents are not supported by hardware implementation +void CORE2_GetADC(void) { + core2_adc.vbus_v = core2_globs.Axp.GetVBusVoltage(); + core2_adc.batt_v = core2_globs.Axp.GetBatVoltage(); + core2_adc.temp = core2_globs.Axp.GetTempInAXP192(); +#ifdef USE_MPU6886 + float x; + float y; + float z; + core2_globs.Mpu.getAccelData(&x, &y, &z); + core2_adc.x=x*1000; + core2_adc.y=y*1000; + core2_adc.z=z*1000; +#endif // USE_MPU6886 +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv84(uint8_t function) { + bool result = false; + + switch (function) { + + case FUNC_WEB_SENSOR: +#ifdef USE_WEBSERVER + CORE2_WebShow(0); +#endif + break; + case FUNC_JSON_APPEND: + CORE2_WebShow(1); + break; + case FUNC_COMMAND: + result = DecodeCommand(CORE2_Commands, CORE2_Command); + break; + case FUNC_MODULE_INIT: + CORE2_Module_Init(); + break; + case FUNC_INIT: + CORE2_Init(); + break; + case FUNC_EVERY_SECOND: + CORE2_EverySecond(); + break; + case FUNC_LOOP: + CORE2_loop(1); + break; + + } + return result; +} + +#endif // USE_M5STACK_CORE2 +#endif // ESP32 diff --git a/tasmota/xdsp_13_ILI9341-2.ino b/tasmota/xdsp_13_ILI9341-2.ino index 0caaa1f6e..9df5e9038 100644 --- a/tasmota/xdsp_13_ILI9341-2.ino +++ b/tasmota/xdsp_13_ILI9341-2.ino @@ -20,7 +20,7 @@ //#ifdef USE_SPI #ifdef USE_SPI #ifdef USE_DISPLAY -#ifdef USE_DISPLAY_ILI9341_2 +#if (defined(USE_DISPLAY_ILI9341_2) || defined(USE_DISPLAY_ILI9342)) #define XDSP_13 13 @@ -42,9 +42,13 @@ extern uint8_t *buffer; extern uint8_t color_type; ILI9341_2 *ili9341_2; +#ifdef USE_FT5206 +#include +#undef FT6336_address +#define FT6336_address 0x38 +uint8_t ili9342_ctouch_counter = 0; +#endif // USE_FT5206 -#undef BACKPLANE_PIN -#define BACKPLANE_PIN 4 /*********************************************************************************************/ @@ -54,6 +58,7 @@ void ILI9341_2_InitDriver() Settings.display_model = XDSP_13; } + if (XDSP_13 == Settings.display_model) { if (Settings.display_width != ILI9341_2_TFTWIDTH) { @@ -70,13 +75,17 @@ void ILI9341_2_InitDriver() fg_color = ILI9341_2_WHITE; bg_color = ILI9341_2_BLACK; - +#ifdef USE_M5STACK_CORE2 + ili9341_2 = new ILI9341_2(5, -2, 15, -2); +#else // init renderer, may use hardware spi, however we use SSPI defintion because SD card uses SPI definition (2 spi busses) if (PinUsed(GPIO_SSPI_CS) && PinUsed(GPIO_OLED_RESET) && PinUsed(GPIO_BACKLIGHT) && PinUsed(GPIO_SSPI_MOSI) && PinUsed(GPIO_SSPI_MISO) && PinUsed(GPIO_SSPI_SCLK) && PinUsed(GPIO_SSPI_DC)) { ili9341_2 = new ILI9341_2(Pin(GPIO_SSPI_CS), Pin(GPIO_SSPI_MOSI), Pin(GPIO_SSPI_MISO), Pin(GPIO_SSPI_SCLK), Pin(GPIO_OLED_RESET), Pin(GPIO_SSPI_DC), Pin(GPIO_BACKLIGHT)); } else { return; } +#endif + ili9341_2->init(Settings.display_width,Settings.display_height); renderer = ili9341_2; renderer->DisplayInit(DISPLAY_INIT_MODE,Settings.display_size,Settings.display_rotate,Settings.display_font); @@ -92,9 +101,79 @@ void ILI9341_2_InitDriver() color_type = COLOR_COLOR; +#ifdef ESP32 +#ifdef USE_FT5206 + // start digitizer with fixed adress and pins for esp32 + #define SDA_2 21 + #define SCL_2 22 + Wire1.begin(SDA_2, SCL_2, 400000); + Touch_Init(Wire1); +#endif // USE_FT5206 +#endif // ESP32 + + } } +void core2_disp_pwr(uint8_t on); +void core2_disp_dim(uint8_t dim); + +void ili9342_bpwr(uint8_t on) { +#ifdef USE_M5STACK_CORE2 + core2_disp_pwr(on); +#endif +} + +void ili9342_dimm(uint8_t dim) { +#ifdef USE_M5STACK_CORE2 + core2_disp_dim(dim); +#endif +} + +#ifdef ESP32 +#ifdef USE_FT5206 +#ifdef USE_TOUCH_BUTTONS + +void ili9342_RotConvert(int16_t *x, int16_t *y) { + +int16_t temp; + if (renderer) { + uint8_t rot=renderer->getRotation(); + switch (rot) { + case 0: + break; + case 1: + temp=*y; + *y=renderer->height()-*x; + *x=temp; + break; + case 2: + *x=renderer->width()-*x; + *y=renderer->height()-*y; + break; + case 3: + temp=*y; + *y=*x; + *x=renderer->width()-temp; + break; + } + } +} + +// check digitizer hit +void ili9342_CheckTouch() { +ili9342_ctouch_counter++; + if (2 == ili9342_ctouch_counter) { + // every 100 ms should be enough + ili9342_ctouch_counter = 0; + Touch_Check(ili9342_RotConvert); + } +} +#endif // USE_TOUCH_BUTTONS +#endif // USE_FT5206 +#endif // ESP32 + + /*********************************************************************************************/ /*********************************************************************************************\ * Interface @@ -111,6 +190,15 @@ bool Xdsp13(uint8_t function) case FUNC_DISPLAY_MODEL: result = true; break; +#ifdef USE_FT5206 +#ifdef USE_TOUCH_BUTTONS + case FUNC_DISPLAY_EVERY_50_MSECOND: + if (FT5206_found) { + ili9342_CheckTouch(); + } + break; +#endif // USE_TOUCH_BUTTONS +#endif // USE_FT5206 } } return result;