Refactor hardware specific code

This commit is contained in:
Theo Arends 2023-11-10 12:24:20 +01:00
parent 7febc11b8c
commit ede5e398a6
2 changed files with 248 additions and 232 deletions

View File

@ -1,218 +1,15 @@
/*
support_esp.ino - ESP specific code for Tasmota
support_esp32.ino - ESP32 specific support for Tasmota
Copyright (C) 2021 Theo Arends / Jörg Schüler-Maroldt
SPDX-FileCopyrightText: 2023 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 <http://www.gnu.org/licenses/>.
SPDX-License-Identifier: GPL-3.0-only
*/
/*********************************************************************************************\
* ESP8266 and ESP32 specific code
*
* At the end the common Tasmota calls are provided
\*********************************************************************************************/
/*********************************************************************************************\
* ESP8266 Support
\*********************************************************************************************/
#ifdef ESP8266
extern "C" {
extern struct rst_info resetInfo;
}
/*********************************************************************************************\
* Core overrides executed by core
\*********************************************************************************************/
// Add below line to tasmota_globals.h
// extern "C" void resetPins();
//
// This function overrules __resetPins() which is executed by core init() as initPins() in core_esp8266_wiring.cpp
//
// 20221229 - (v12.3.1.2) Enabled with additional check to execute on power on only to fix relay clicks on power on
// 20200321 - (v8.2.0.1) Disable core functionality to fix relay clicks on restart after OTA - make function return without setting pinMode
void resetPins() {
if ((resetInfo.reason == REASON_DEFAULT_RST) || (resetInfo.reason == REASON_EXT_SYS_RST)) {
// Only perform at power on
for (int i = 0; i <= 5; ++i) {
pinMode(i, INPUT);
}
// pins 6-11 are used for the SPI flash interface ESP8266
for (int i = 12; i <= 16; ++i) {
pinMode(i, INPUT);
}
}
}
/*********************************************************************************************\
* Hardware related
\*********************************************************************************************/
void HwWdtDisable(void) {
*((volatile uint32_t*) 0x60000900) &= ~(1); // Hardware WDT OFF
}
void HwWdtEnable(void) {
*((volatile uint32_t*) 0x60000900) |= 1; // Hardware WDT ON
}
void WdtDisable(void) {
ESP.wdtDisable();
HwWdtDisable();
}
void WdtEnable(void) {
HwWdtEnable();
ESP.wdtEnable(0);
}
/*********************************************************************************************\
* ESP8266 specifics
\*********************************************************************************************/
uint32_t ESP_ResetInfoReason(void) {
return resetInfo.reason;
}
String ESP_getResetReason(void) {
return ESP.getResetReason();
}
uint32_t ESP_getChipId(void) {
return ESP.getChipId();
}
uint32_t ESP_getFreeSketchSpace(void) {
return ESP.getFreeSketchSpace();
}
uint32_t ESP_getSketchSize(void) {
return ESP.getSketchSize();
}
uint32_t ESP_getFreeHeap(void) {
return ESP.getFreeHeap();
}
uint32_t ESP_getFlashChipId(void) {
return ESP.getFlashChipId();
}
uint32_t ESP_getFlashChipRealSize(void) {
return ESP.getFlashChipRealSize();
}
uint32_t ESP_getFlashChipSize(void) {
return ESP.getFlashChipSize();
}
void ESP_Restart(void) {
// ESP.restart(); // This results in exception 3 on restarts on core 2.3.0
ESP.reset();
}
uint32_t FlashWriteStartSector(void) {
return (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 2; // Stay on the safe side
}
uint32_t FlashWriteMaxSector(void) {
return (((uint32_t)&_FS_start - 0x40200000) / SPI_FLASH_SEC_SIZE) - 2;
}
uint8_t* FlashDirectAccess(void) {
return (uint8_t*)(0x40200000 + (FlashWriteStartSector() * SPI_FLASH_SEC_SIZE));
}
void *special_malloc(uint32_t size) {
return malloc(size);
}
void *special_realloc(void *ptr, size_t size) {
return realloc(ptr, size);
}
void *special_calloc(size_t num, size_t size) {
return calloc(num, size);
}
String GetDeviceHardware(void) {
/*
ESP8266 SoCs
- 32-bit MCU & 2.4 GHz Wi-Fi
- High-performance 160 MHz single-core CPU
- +19.5 dBm output power ensures a good physical range
- Sleep current is less than 20 μA, making it suitable for battery-powered and wearable-electronics applications
- Peripherals include UART, GPIO, I2C, I2S, SDIO, PWM, ADC and SPI
*/
// esptool.py get_efuses
uint32_t efuse0 = *(uint32_t*)(0x3FF00050);
// uint32_t efuse1 = *(uint32_t*)(0x3FF00054);
uint32_t efuse2 = *(uint32_t*)(0x3FF00058);
uint32_t efuse3 = *(uint32_t*)(0x3FF0005C);
bool r0_4 = efuse0 & (1 << 4); // ESP8285
bool r2_16 = efuse2 & (1 << 16); // ESP8285
if (r0_4 || r2_16) { // ESP8285
// 1M 2M 2M 4M flash size
// r0_4 1 1 0 0
bool r3_25 = efuse3 & (1 << 25); // flash matrix 0 0 1 1
bool r3_26 = efuse3 & (1 << 26); // flash matrix 0 1 0 1
bool r3_27 = efuse3 & (1 << 27); // flash matrix 0 0 0 0
uint32_t pkg_version = 0;
if (!r3_27) {
if (r0_4 && !r3_25) {
pkg_version = (r3_26) ? 2 : 1;
}
else if (!r0_4 && r3_25) {
pkg_version = (r3_26) ? 4 : 2;
}
}
bool max_temp = efuse0 & (1 << 5); // Max flash temperature (0 = 85C, 1 = 105C)
switch (pkg_version) {
case 1:
if (max_temp) { return F("ESP8285H08"); } // 1M flash
else { return F("ESP8285N08"); }
case 2:
if (max_temp) { return F("ESP8285H16"); } // 2M flash
else { return F("ESP8285N16"); }
case 4:
if (max_temp) { return F("ESP8285H32"); } // 4M flash
else { return F("ESP8285N32"); }
}
return F("ESP8285");
}
return F("ESP8266EX");
}
String GetDeviceHardwareRevision(void) {
// No known revisions for ESP8266/85
return GetDeviceHardware();
}
String GetCodeCores(void) {
return F("");
}
#endif
/*********************************************************************************************\
* ESP32 Support
\*********************************************************************************************/
#ifdef ESP32
/*********************************************************************************************\
* ESP32, ESP32-S2, ESP32-S3, ESP32-C2, ESP32-C3, ESP32-C6 and ESP32-H2 Support
\*********************************************************************************************/
#include "soc/soc.h"
#include "soc/spi_reg.h"
@ -233,6 +30,8 @@ String GetCodeCores(void) {
#define ESP32_ARCH "esp32c3"
#elif CONFIG_IDF_TARGET_ESP32C6
#define ESP32_ARCH "esp32c6"
#elif CONFIG_IDF_TARGET_ESP32H2
#define ESP32_ARCH "esp32h2"
#else
#define ESP32_ARCH ""
#endif
@ -256,6 +55,8 @@ String GetCodeCores(void) {
#include "esp32c3/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32C6 // ESP32-C6
#include "esp32c6/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32H2 // ESP32-H2
#include "esp32h2/rom/rtc.h"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
@ -440,6 +241,9 @@ extern "C" {
#elif CONFIG_IDF_TARGET_ESP32C6 // ESP32-C6
#include "esp32c6/rom/spi_flash.h"
#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32c6 is located at 0x0000
#elif CONFIG_IDF_TARGET_ESP32H2 // ESP32-H2
#include "esp32h2/rom/spi_flash.h"
#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32h2 is located at 0x0000
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
@ -707,6 +511,15 @@ uint32_t ESP_getFreeHeap(void) {
return heap_caps_get_free_size(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
}
uint32_t ESP_getFreeHeap1024(void) {
return ESP_getFreeHeap() / 1024;
}
/*
float ESP_getFreeHeap1024(void) {
return ((float)ESP_getFreeHeap()) / 1024;
}
*/
uint32_t ESP_getMaxAllocHeap(void) {
// arduino returns IRAM but we want only DRAM
#ifdef USE_GT911 // GT911 IRQ crashes with heap_caps_get_largest_free_block
@ -1140,21 +953,6 @@ bool CanUsePSRAM(void) {
return true;
}
#endif // ESP32
/*********************************************************************************************\
* ESP Support
\*********************************************************************************************/
uint32_t ESP_getFreeHeap1024(void) {
return ESP_getFreeHeap() / 1024;
}
/*
float ESP_getFreeHeap1024(void) {
return ((float)ESP_getFreeHeap()) / 1024;
}
*/
/*********************************************************************************************\
* High entropy hardware random generator
* Thanks to DigitalAlchemist
@ -1166,18 +964,12 @@ float ESP_getFreeHeap1024(void) {
// Based on code from https://raw.githubusercontent.com/espressif/esp-idf/master/components/esp32/hw_random.c
uint32_t HwRandom(void) {
#if ESP8266
// https://web.archive.org/web/20160922031242/http://esp8266-re.foogod.com/wiki/Random_Number_Generator
#define _RAND_ADDR 0x3FF20E44UL
#endif // ESP8266
#ifdef ESP32
#if ESP_IDF_VERSION_MAJOR >= 5
// See for more info on the HW RNG:
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/system/random.html
return esp_random();
#endif
#else
#define _RAND_ADDR 0x3FF75144UL
#endif // ESP32
static uint32_t last_ccount = 0;
uint32_t ccount;
uint32_t result = 0;
@ -1187,5 +979,8 @@ uint32_t HwRandom(void) {
} while (ccount - last_ccount < 64);
last_ccount = ccount;
return result ^ *(volatile uint32_t *)_RAND_ADDR;
#undef _RAND_ADDR
#undef _RAND_ADDR
#endif // ESP_IDF_VERSION_MAJOR >= 5
}
#endif // ESP32

View File

@ -0,0 +1,221 @@
/*
support_esp8266.ino - ESP8266 specific support for Tasmota
SPDX-FileCopyrightText: 2023 Theo Arends
SPDX-License-Identifier: GPL-3.0-only
*/
#ifdef ESP8266
/*********************************************************************************************\
* ESP8266 and ESP8285 Support
\*********************************************************************************************/
extern "C" {
extern struct rst_info resetInfo;
}
/*********************************************************************************************\
* Core overrides executed by core
\*********************************************************************************************/
// Add below line to tasmota_globals.h
// extern "C" void resetPins();
//
// This function overrules __resetPins() which is executed by core init() as initPins() in core_esp8266_wiring.cpp
//
// 20221229 - (v12.3.1.2) Enabled with additional check to execute on power on only to fix relay clicks on power on
// 20200321 - (v8.2.0.1) Disable core functionality to fix relay clicks on restart after OTA - make function return without setting pinMode
void resetPins() {
if ((resetInfo.reason == REASON_DEFAULT_RST) || (resetInfo.reason == REASON_EXT_SYS_RST)) {
// Only perform at power on
for (int i = 0; i <= 5; ++i) {
pinMode(i, INPUT);
}
// pins 6-11 are used for the SPI flash interface ESP8266
for (int i = 12; i <= 16; ++i) {
pinMode(i, INPUT);
}
}
}
/*********************************************************************************************\
* Hardware related
\*********************************************************************************************/
void HwWdtDisable(void) {
*((volatile uint32_t*) 0x60000900) &= ~(1); // Hardware WDT OFF
}
void HwWdtEnable(void) {
*((volatile uint32_t*) 0x60000900) |= 1; // Hardware WDT ON
}
void WdtDisable(void) {
ESP.wdtDisable();
HwWdtDisable();
}
void WdtEnable(void) {
HwWdtEnable();
ESP.wdtEnable(0);
}
/*********************************************************************************************\
* ESP8266 specifics
\*********************************************************************************************/
uint32_t ESP_ResetInfoReason(void) {
return resetInfo.reason;
}
String ESP_getResetReason(void) {
return ESP.getResetReason();
}
uint32_t ESP_getChipId(void) {
return ESP.getChipId();
}
uint32_t ESP_getFreeSketchSpace(void) {
return ESP.getFreeSketchSpace();
}
uint32_t ESP_getSketchSize(void) {
return ESP.getSketchSize();
}
uint32_t ESP_getFreeHeap(void) {
return ESP.getFreeHeap();
}
uint32_t ESP_getFreeHeap1024(void) {
return ESP_getFreeHeap() / 1024;
}
/*
float ESP_getFreeHeap1024(void) {
return ((float)ESP_getFreeHeap()) / 1024;
}
*/
uint32_t ESP_getFlashChipId(void) {
return ESP.getFlashChipId();
}
uint32_t ESP_getFlashChipRealSize(void) {
return ESP.getFlashChipRealSize();
}
uint32_t ESP_getFlashChipSize(void) {
return ESP.getFlashChipSize();
}
void ESP_Restart(void) {
// ESP.restart(); // This results in exception 3 on restarts on core 2.3.0
ESP.reset();
}
uint32_t FlashWriteStartSector(void) {
return (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 2; // Stay on the safe side
}
uint32_t FlashWriteMaxSector(void) {
return (((uint32_t)&_FS_start - 0x40200000) / SPI_FLASH_SEC_SIZE) - 2;
}
uint8_t* FlashDirectAccess(void) {
return (uint8_t*)(0x40200000 + (FlashWriteStartSector() * SPI_FLASH_SEC_SIZE));
}
void *special_malloc(uint32_t size) {
return malloc(size);
}
void *special_realloc(void *ptr, size_t size) {
return realloc(ptr, size);
}
void *special_calloc(size_t num, size_t size) {
return calloc(num, size);
}
String GetDeviceHardware(void) {
/*
ESP8266 SoCs
- 32-bit MCU & 2.4 GHz Wi-Fi
- High-performance 160 MHz single-core CPU
- +19.5 dBm output power ensures a good physical range
- Sleep current is less than 20 μA, making it suitable for battery-powered and wearable-electronics applications
- Peripherals include UART, GPIO, I2C, I2S, SDIO, PWM, ADC and SPI
*/
// esptool.py get_efuses
uint32_t efuse0 = *(uint32_t*)(0x3FF00050);
// uint32_t efuse1 = *(uint32_t*)(0x3FF00054);
uint32_t efuse2 = *(uint32_t*)(0x3FF00058);
uint32_t efuse3 = *(uint32_t*)(0x3FF0005C);
bool r0_4 = efuse0 & (1 << 4); // ESP8285
bool r2_16 = efuse2 & (1 << 16); // ESP8285
if (r0_4 || r2_16) { // ESP8285
// 1M 2M 2M 4M flash size
// r0_4 1 1 0 0
bool r3_25 = efuse3 & (1 << 25); // flash matrix 0 0 1 1
bool r3_26 = efuse3 & (1 << 26); // flash matrix 0 1 0 1
bool r3_27 = efuse3 & (1 << 27); // flash matrix 0 0 0 0
uint32_t pkg_version = 0;
if (!r3_27) {
if (r0_4 && !r3_25) {
pkg_version = (r3_26) ? 2 : 1;
}
else if (!r0_4 && r3_25) {
pkg_version = (r3_26) ? 4 : 2;
}
}
bool max_temp = efuse0 & (1 << 5); // Max flash temperature (0 = 85C, 1 = 105C)
switch (pkg_version) {
case 1:
if (max_temp) { return F("ESP8285H08"); } // 1M flash
else { return F("ESP8285N08"); }
case 2:
if (max_temp) { return F("ESP8285H16"); } // 2M flash
else { return F("ESP8285N16"); }
case 4:
if (max_temp) { return F("ESP8285H32"); } // 4M flash
else { return F("ESP8285N32"); }
}
return F("ESP8285");
}
return F("ESP8266EX");
}
String GetDeviceHardwareRevision(void) {
// No known revisions for ESP8266/85
return GetDeviceHardware();
}
String GetCodeCores(void) {
return F("");
}
/*********************************************************************************************\
* High entropy hardware random generator
* Thanks to DigitalAlchemist
\*********************************************************************************************/
// Based on code from https://raw.githubusercontent.com/espressif/esp-idf/master/components/esp32/hw_random.c
uint32_t HwRandom(void) {
// https://web.archive.org/web/20160922031242/http://esp8266-re.foogod.com/wiki/Random_Number_Generator
#define _RAND_ADDR 0x3FF20E44UL
static uint32_t last_ccount = 0;
uint32_t ccount;
uint32_t result = 0;
do {
ccount = ESP.getCycleCount();
result ^= *(volatile uint32_t *)_RAND_ADDR;
} while (ccount - last_ccount < 64);
last_ccount = ccount;
return result ^ *(volatile uint32_t *)_RAND_ADDR;
#undef _RAND_ADDR
}
#endif // ESP8266