2020-04-10 17:24:08 +01:00
/*
2021-02-08 10:34:29 +00:00
support_esp . ino - ESP specific code for Tasmota
2020-04-10 17:24:08 +01:00
2021-01-01 12:44:04 +00:00
Copyright ( C ) 2021 Theo Arends / Jörg Schüler - Maroldt
2020-04-10 17:24:08 +01:00
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/>.
*/
2021-02-08 10:34:29 +00:00
/*********************************************************************************************\
* ESP8266 and ESP32 specific code
*
* At the end the common Tasmota calls are provided
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-04-19 15:58:13 +01:00
/*********************************************************************************************\
* ESP8266 Support
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef ESP8266
extern " C " {
extern struct rst_info resetInfo ;
}
2020-04-22 15:07:52 +01:00
uint32_t ESP_ResetInfoReason ( void ) {
2020-04-19 15:58:13 +01:00
return resetInfo . reason ;
}
2020-04-22 15:07:52 +01:00
String ESP_getResetReason ( void ) {
2020-04-19 15:58:13 +01:00
return ESP . getResetReason ( ) ;
}
2020-04-22 15:07:52 +01:00
uint32_t ESP_getChipId ( void ) {
2020-04-19 15:58:13 +01:00
return ESP . getChipId ( ) ;
}
2022-05-05 16:52:35 +01:00
uint32_t ESP_getFreeSketchSpace ( void ) {
return ESP . getFreeSketchSpace ( ) ;
}
2020-04-22 15:07:52 +01:00
uint32_t ESP_getSketchSize ( void ) {
2020-04-19 15:58:13 +01:00
return ESP . getSketchSize ( ) ;
}
2020-04-22 15:07:52 +01:00
uint32_t ESP_getFreeHeap ( void ) {
return ESP . getFreeHeap ( ) ;
}
2022-05-09 21:43:27 +01:00
uint32_t ESP_getFlashChipId ( void ) {
return ESP . getFlashChipId ( ) ;
}
uint32_t ESP_getFlashChipRealSize ( void ) {
return ESP . getFlashChipRealSize ( ) ;
}
2022-09-17 14:53:58 +01:00
uint32_t ESP_getFlashChipSize ( void ) {
return ESP . getFlashChipSize ( ) ;
}
2020-04-22 15:07:52 +01:00
void ESP_Restart ( void ) {
2020-04-19 15:58:13 +01:00
// ESP.restart(); // This results in exception 3 on restarts on core 2.3.0
ESP . reset ( ) ;
}
2020-11-22 16:35:04 +00:00
uint32_t FlashWriteStartSector ( void ) {
return ( ESP . getSketchSize ( ) / SPI_FLASH_SEC_SIZE ) + 2 ; // Stay on the safe side
}
uint32_t FlashWriteMaxSector ( void ) {
2021-01-11 16:56:18 +00:00
return ( ( ( uint32_t ) & _FS_start - 0x40200000 ) / SPI_FLASH_SEC_SIZE ) - 2 ;
2020-11-22 16:35:04 +00:00
}
uint8_t * FlashDirectAccess ( void ) {
return ( uint8_t * ) ( 0x40200000 + ( FlashWriteStartSector ( ) * SPI_FLASH_SEC_SIZE ) ) ;
}
2021-01-04 15:39:00 +00:00
void * special_malloc ( uint32_t size ) {
return malloc ( size ) ;
}
2021-03-20 17:44:35 +00:00
void * special_realloc ( void * ptr , size_t size ) {
return realloc ( ptr , size ) ;
}
2021-05-09 17:15:15 +01:00
void * special_calloc ( size_t num , size_t size ) {
return calloc ( num , size ) ;
}
2021-04-17 14:57:35 +01:00
String GetDeviceHardware ( void ) {
// esptool.py get_efuses
uint32_t efuse1 = * ( uint32_t * ) ( 0x3FF00050 ) ;
uint32_t efuse2 = * ( uint32_t * ) ( 0x3FF00054 ) ;
// uint32_t efuse3 = *(uint32_t*)(0x3FF00058);
// uint32_t efuse4 = *(uint32_t*)(0x3FF0005C);
2021-04-22 14:51:50 +01:00
if ( ( ( efuse1 & ( 1 < < 4 ) ) | | ( efuse2 & ( 1 < < 16 ) ) ) & & ( ESP . getFlashChipRealSize ( ) < 1048577 ) ) { // ESP8285 can only have 1M flash
return F ( " ESP8285 " ) ;
2021-04-17 14:57:35 +01:00
}
2021-04-22 14:51:50 +01:00
return F ( " ESP8266EX " ) ;
2021-04-17 14:57:35 +01:00
}
2022-04-23 16:59:37 +01:00
String GetDeviceHardwareRevision ( void ) {
2022-04-24 10:24:01 +01:00
// No known revisions for ESP8266/85
return GetDeviceHardware ( ) ;
2022-04-23 16:59:37 +01:00
}
2022-10-04 16:52:15 +01:00
String GetCodeCores ( void ) {
return F ( " " ) ;
}
2020-04-19 15:58:13 +01:00
# endif
/*********************************************************************************************\
* ESP32 Support
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-04-10 17:24:08 +01:00
# ifdef ESP32
2022-05-09 21:43:27 +01:00
# include "bootloader_flash.h"
2022-08-21 19:22:39 +01:00
# include "soc/soc.h"
# include "soc/spi_reg.h"
2021-11-10 19:58:06 +00:00
// ESP32_ARCH contains the name of the architecture (used by autoconf)
# if CONFIG_IDF_TARGET_ESP32
2022-07-01 23:13:27 +01:00
# ifdef CORE32SOLO1
# define ESP32_ARCH "esp32solo1"
# else
# define ESP32_ARCH "esp32"
# endif
2021-11-10 19:58:06 +00:00
# elif CONFIG_IDF_TARGET_ESP32S2
# define ESP32_ARCH "esp32s2"
# elif CONFIG_IDF_TARGET_ESP32S3
# define ESP32_ARCH "esp32s3"
# elif CONFIG_IDF_TARGET_ESP32C3
# define ESP32_ARCH "esp32c3"
# else
# define ESP32_ARCH ""
# endif
2020-07-05 13:51:55 +01:00
// Handle 20k of NVM
2020-04-10 17:24:08 +01:00
# include <nvs.h>
2021-02-02 16:55:45 +00:00
2021-02-03 11:22:17 +00:00
// See libraries\ESP32\examples\ResetReason.ino
# if ESP_IDF_VERSION_MAJOR > 3 // IDF 4+
# if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
# include "esp32/rom/rtc.h"
# elif CONFIG_IDF_TARGET_ESP32S2 // ESP32-S2
# include "esp32s2/rom/rtc.h"
2022-01-30 11:55:03 +00:00
# elif CONFIG_IDF_TARGET_ESP32S3 // ESP32-S3
# include "esp32s3/rom/rtc.h"
2021-04-17 18:57:13 +01:00
# elif CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3
# include "esp32c3/rom/rtc.h"
2021-02-03 11:22:17 +00:00
# else
# error Target CONFIG_IDF_TARGET is not supported
# endif
# else // ESP32 Before IDF 4.0
# include "rom/rtc.h"
2021-02-02 16:55:45 +00:00
# endif
2022-01-03 17:52:30 +00:00
// Set the Stacksize for Arduino core. Default is 8192, some builds may need a bigger one
size_t getArduinoLoopTaskStackSize ( void ) {
return SET_ESP32_STACK_SIZE ;
}
2020-11-12 16:50:34 +00:00
# include <esp_phy_init.h>
2020-04-10 17:24:08 +01:00
2021-12-12 17:04:46 +00:00
bool NvmLoad ( const char * sNvsName , const char * sName , void * pSettings , unsigned nSettingsLen ) {
nvs_handle_t handle ;
esp_err_t result = nvs_open ( sNvsName , NVS_READONLY , & handle ) ;
if ( result ! = ESP_OK ) {
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " NVS: Error %d " ) , result ) ;
return false ;
}
2020-04-19 14:36:04 +01:00
size_t size = nSettingsLen ;
nvs_get_blob ( handle , sName , pSettings , & size ) ;
2020-04-10 17:24:08 +01:00
nvs_close ( handle ) ;
2021-12-12 17:04:46 +00:00
return true ;
2020-04-10 17:24:08 +01:00
}
2020-04-22 15:07:52 +01:00
void NvmSave ( const char * sNvsName , const char * sName , const void * pSettings , unsigned nSettingsLen ) {
2021-12-17 17:01:27 +00:00
# ifdef USE_WEBCAM
WcInterrupt ( 0 ) ; // Stop stream if active to fix TG1WDT_SYS_RESET
# endif
2021-12-12 17:04:46 +00:00
nvs_handle_t handle ;
esp_err_t result = nvs_open ( sNvsName , NVS_READWRITE , & handle ) ;
if ( result ! = ESP_OK ) {
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " NVS: Error %d " ) , result ) ;
2021-12-17 17:01:27 +00:00
} else {
nvs_set_blob ( handle , sName , pSettings , nSettingsLen ) ;
nvs_commit ( handle ) ;
nvs_close ( handle ) ;
2021-12-12 17:04:46 +00:00
}
2021-12-17 17:01:27 +00:00
# ifdef USE_WEBCAM
WcInterrupt ( 1 ) ;
# endif
2020-04-10 17:24:08 +01:00
}
2020-11-12 17:37:01 +00:00
int32_t NvmErase ( const char * sNvsName ) {
2021-12-12 17:04:46 +00:00
nvs_handle_t handle ;
2020-11-12 17:37:01 +00:00
int32_t result = nvs_open ( sNvsName , NVS_READWRITE , & handle ) ;
2020-11-12 16:38:15 +00:00
if ( ESP_OK = = result ) { result = nvs_erase_all ( handle ) ; }
if ( ESP_OK = = result ) { result = nvs_commit ( handle ) ; }
2020-04-10 17:24:08 +01:00
nvs_close ( handle ) ;
2020-11-12 16:38:15 +00:00
return result ;
2020-04-10 17:24:08 +01:00
}
2020-04-22 15:07:52 +01:00
void SettingsErase ( uint8_t type ) {
2021-01-08 16:06:17 +00:00
// SDK and Tasmota data is held in default NVS partition
2021-01-12 13:54:12 +00:00
// Tasmota data is held also in file /.settings on default filesystem
2020-11-12 16:50:34 +00:00
// cal_data - SDK PHY calibration data as documented in esp_phy_init.h
// qpc - Tasmota Quick Power Cycle state
// main - Tasmota Settings data
2021-06-20 21:04:32 +01:00
int32_t r1 , r2 , r3 = 0 ;
2020-11-12 16:38:15 +00:00
switch ( type ) {
2021-01-13 11:38:35 +00:00
case 0 : // Reset 2 = Erase all flash from program end to end of physical flash
case 2 : // Reset 5, 6 = Erase all flash from program end to end of physical flash excluding filesystem
2020-11-12 16:38:15 +00:00
// nvs_flash_erase(); // Erase RTC, PHY, sta.mac, ap.sndchan, ap.mac, Tasmota etc.
r1 = NvmErase ( " qpc " ) ;
r2 = NvmErase ( " main " ) ;
2021-06-20 21:04:32 +01:00
# ifdef USE_UFILESYS
2021-01-08 16:06:17 +00:00
r3 = TfsDeleteFile ( TASM_FILE_SETTINGS ) ;
2021-06-20 21:04:32 +01:00
# endif
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_APPLICATION D_ERASE " Tasmota data (%d,%d,%d) " ) , r1 , r2 , r3 ) ;
2020-11-12 16:38:15 +00:00
break ;
2021-01-13 11:38:35 +00:00
case 1 : // Reset 3 = SDK parameter area
case 4 : // WIFI_FORCE_RF_CAL_ERASE = SDK parameter area
2020-11-12 16:50:34 +00:00
r1 = esp_phy_erase_cal_data_in_nvs ( ) ;
// r1 = NvmErase("cal_data");
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_APPLICATION D_ERASE " PHY data (%d) " ) , r1 ) ;
2020-11-12 16:38:15 +00:00
break ;
case 3 : // QPC Reached = QPC, Tasmota and SDK parameter area (0x0F3xxx - 0x0FFFFF)
// nvs_flash_erase(); // Erase RTC, PHY, sta.mac, ap.sndchan, ap.mac, Tasmota etc.
r1 = NvmErase ( " qpc " ) ;
r2 = NvmErase ( " main " ) ;
// r3 = esp_phy_erase_cal_data_in_nvs();
// r3 = NvmErase("cal_data");
2021-01-23 15:26:23 +00:00
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_ERASE " Tasmota (%d,%d) and PHY data (%d)"), r1, r2, r3);
2021-06-20 21:04:32 +01:00
# ifdef USE_UFILESYS
2021-01-08 16:06:17 +00:00
r3 = TfsDeleteFile ( TASM_FILE_SETTINGS ) ;
2021-06-20 21:04:32 +01:00
# endif
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_APPLICATION D_ERASE " Tasmota data (%d,%d,%d) " ) , r1 , r2 , r3 ) ;
2020-11-12 16:38:15 +00:00
break ;
2020-04-19 14:36:04 +01:00
}
2020-04-10 17:24:08 +01:00
}
2021-01-08 15:22:06 +00:00
uint32_t SettingsRead ( void * data , size_t size ) {
2021-06-20 21:04:32 +01:00
# ifdef USE_UFILESYS
2021-12-12 17:04:46 +00:00
if ( TfsLoadFile ( TASM_FILE_SETTINGS , ( uint8_t * ) data , size ) ) {
return 2 ;
2021-01-08 15:22:06 +00:00
}
2021-06-20 21:04:32 +01:00
# endif
2021-12-12 17:04:46 +00:00
if ( NvmLoad ( " main " , " Settings " , data , size ) ) {
return 1 ;
} ;
return 0 ;
2020-04-10 17:24:08 +01:00
}
2020-04-22 15:07:52 +01:00
void SettingsWrite ( const void * pSettings , unsigned nSettingsLen ) {
2021-06-20 21:04:32 +01:00
# ifdef USE_UFILESYS
2021-01-08 16:06:17 +00:00
TfsSaveFile ( TASM_FILE_SETTINGS , ( const uint8_t * ) pSettings , nSettingsLen ) ;
2021-06-20 21:04:32 +01:00
# endif
2021-12-17 17:01:27 +00:00
NvmSave ( " main " , " Settings " , pSettings , nSettingsLen ) ;
2020-04-10 17:24:08 +01:00
}
2020-04-22 15:07:52 +01:00
void QPCRead ( void * pSettings , unsigned nSettingsLen ) {
2020-04-19 14:36:04 +01:00
NvmLoad ( " qpc " , " pcreg " , pSettings , nSettingsLen ) ;
2020-04-10 17:24:08 +01:00
}
2020-04-22 15:07:52 +01:00
void QPCWrite ( const void * pSettings , unsigned nSettingsLen ) {
2020-04-19 14:36:04 +01:00
NvmSave ( " qpc " , " pcreg " , pSettings , nSettingsLen ) ;
2020-04-10 17:24:08 +01:00
}
2022-05-10 21:21:34 +01:00
bool OtaFactoryRead ( void ) {
uint32_t pOtaLoader ;
NvmLoad ( " otal " , " otal " , & pOtaLoader , sizeof ( pOtaLoader ) ) ;
return pOtaLoader ;
}
void OtaFactoryWrite ( bool value ) {
uint32_t pOtaLoader = value ;
NvmSave ( " otal " , " otal " , & pOtaLoader , sizeof ( pOtaLoader ) ) ;
}
2020-12-15 15:24:01 +00:00
void NvsInfo ( void ) {
nvs_stats_t nvs_stats ;
nvs_get_stats ( NULL , & nvs_stats ) ;
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_INFO , PSTR ( " NVS: Used %d/%d entries, NameSpaces %d " ) ,
2020-12-16 11:01:10 +00:00
nvs_stats . used_entries , nvs_stats . total_entries , nvs_stats . namespace_count ) ;
2020-07-05 14:13:57 +01:00
}
2020-11-22 16:35:04 +00:00
//
// Flash memory mapping
//
2021-02-03 11:22:17 +00:00
// See Esp.cpp
2020-11-22 16:35:04 +00:00
# include "Esp.h"
# include "esp_spi_flash.h"
# include <memory>
# include <soc/soc.h>
# include <soc/efuse_reg.h>
# include <esp_partition.h>
extern " C " {
# include "esp_ota_ops.h"
# include "esp_image_format.h"
}
2021-02-03 11:22:17 +00:00
# include "esp_system.h"
# if ESP_IDF_VERSION_MAJOR > 3 // IDF 4+
# if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
# include "esp32/rom/spi_flash.h"
2022-09-17 14:53:58 +01:00
# define ESP_FLASH_IMAGE_BASE 0x1000 // Flash offset containing magic flash size and spi mode
2021-02-03 11:22:17 +00:00
# elif CONFIG_IDF_TARGET_ESP32S2 // ESP32-S2
# include "esp32s2/rom/spi_flash.h"
2022-09-17 14:53:58 +01:00
# define ESP_FLASH_IMAGE_BASE 0x1000 // Flash offset containing magic flash size and spi mode
2022-01-30 11:55:03 +00:00
# elif CONFIG_IDF_TARGET_ESP32S3 // ESP32-S3
# include "esp32s3/rom/spi_flash.h"
2022-09-17 14:53:58 +01:00
# define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32s3 is located at 0x0000
2021-04-17 18:57:13 +01:00
# elif CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3
# include "esp32c3/rom/spi_flash.h"
2022-09-17 14:53:58 +01:00
# define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32c3 is located at 0x0000
2021-02-03 11:22:17 +00:00
# else
# error Target CONFIG_IDF_TARGET is not supported
# endif
# else // ESP32 Before IDF 4.0
# include "rom/spi_flash.h"
2022-09-17 14:53:58 +01:00
# define ESP_FLASH_IMAGE_BASE 0x1000
2021-02-03 11:22:17 +00:00
# endif
2020-11-22 16:35:04 +00:00
2022-05-14 16:41:52 +01:00
uint32_t EspProgramSize ( const char * label ) {
const esp_partition_t * part = esp_partition_find_first ( ESP_PARTITION_TYPE_APP , ESP_PARTITION_SUBTYPE_ANY , label ) ;
if ( ! part ) {
return 0 ;
}
const esp_partition_pos_t part_pos = {
. offset = part - > address ,
. size = part - > size ,
} ;
esp_image_metadata_t data ;
data . start_addr = part_pos . offset ;
esp_image_verify ( ESP_IMAGE_VERIFY , & part_pos , & data ) ;
return data . image_len ;
}
2022-05-01 15:12:54 +01:00
bool EspSingleOtaPartition ( void ) {
return ( 1 = = esp_ota_get_app_partition_count ( ) ) ;
}
2022-05-05 17:20:25 +01:00
uint32_t EspRunningFactoryPartition ( void ) {
2022-05-01 22:16:21 +01:00
const esp_partition_t * cur_part = esp_ota_get_running_partition ( ) ;
2022-05-05 17:20:25 +01:00
// return (cur_part->type == 0 && cur_part->subtype == 0);
if ( cur_part - > type = = 0 & & cur_part - > subtype = = 0 ) {
return cur_part - > size ;
}
return 0 ;
2022-05-01 22:16:21 +01:00
}
2022-05-05 10:19:39 +01:00
void EspPrepRestartToSafeBoot ( void ) {
2022-05-01 16:32:42 +01:00
const esp_partition_t * otadata_partition = esp_partition_find_first ( ESP_PARTITION_TYPE_DATA , ESP_PARTITION_SUBTYPE_DATA_OTA , NULL ) ;
if ( otadata_partition ) {
esp_partition_erase_range ( otadata_partition , 0 , SPI_FLASH_SEC_SIZE * 2 ) ;
}
2022-05-01 15:12:54 +01:00
}
2022-05-15 13:59:39 +01:00
bool EspPrepSwitchPartition ( uint32_t state ) {
2022-05-05 14:24:00 +01:00
bool valid = EspSingleOtaPartition ( ) ;
if ( valid ) {
bool running_factory = EspRunningFactoryPartition ( ) ;
2022-05-15 13:59:39 +01:00
switch ( state ) {
case 0 : // Off = safeboot
if ( ! running_factory ) {
EspPrepRestartToSafeBoot ( ) ;
} else {
valid = false ;
}
break ;
case 1 : // On = ota0
if ( running_factory ) {
const esp_partition_t * partition = esp_ota_get_next_update_partition ( nullptr ) ;
esp_ota_set_boot_partition ( partition ) ;
} else {
valid = false ;
}
break ;
case 2 : // Toggle
if ( ! running_factory ) {
EspPrepRestartToSafeBoot ( ) ;
} else {
const esp_partition_t * partition = esp_ota_get_next_update_partition ( nullptr ) ;
esp_ota_set_boot_partition ( partition ) ;
}
2022-05-05 14:24:00 +01:00
}
}
return valid ;
}
2020-11-22 16:35:04 +00:00
uint32_t EspFlashBaseAddress ( void ) {
2022-05-01 15:12:54 +01:00
if ( EspSingleOtaPartition ( ) ) { // Only one partition so start at end of sketch
2022-05-01 14:18:15 +01:00
const esp_partition_t * running = esp_ota_get_running_partition ( ) ;
if ( ! running ) { return 0 ; }
return running - > address + ESP_getSketchSize ( ) ;
} else { // Select other partition
const esp_partition_t * partition = esp_ota_get_next_update_partition ( nullptr ) ;
if ( ! partition ) { return 0 ; }
return partition - > address ; // For tasmota 0x00010000 or 0x00200000
}
2020-11-22 16:35:04 +00:00
}
uint32_t EspFlashBaseEndAddress ( void ) {
2022-05-01 15:12:54 +01:00
const esp_partition_t * partition = ( EspSingleOtaPartition ( ) ) ? esp_ota_get_running_partition ( ) : esp_ota_get_next_update_partition ( nullptr ) ;
2020-11-22 16:35:04 +00:00
if ( ! partition ) { return 0 ; }
return partition - > address + partition - > size ; // For tasmota 0x00200000 or 0x003F0000
}
uint8_t * EspFlashMmap ( uint32_t address ) {
static spi_flash_mmap_handle_t handle = 0 ;
if ( handle ) {
spi_flash_munmap ( handle ) ;
handle = 0 ;
}
const uint8_t * data ;
int32_t err = spi_flash_mmap ( address , 5 * SPI_FLASH_MMU_PAGE_SIZE , SPI_FLASH_MMAP_DATA , ( const void * * ) & data , & handle ) ;
/*
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " DBG: Spi_flash_map %d " ) , err ) ;
2020-11-22 16:35:04 +00:00
spi_flash_mmap_dump ( ) ;
*/
return ( uint8_t * ) data ;
}
/*
int32_t EspPartitionMmap ( uint32_t action ) {
static spi_flash_mmap_handle_t handle ;
int32_t err = 0 ;
if ( 1 = = action ) {
const esp_partition_t * partition = esp_ota_get_running_partition ( ) ;
// const esp_partition_t* partition = esp_ota_get_next_update_partition(nullptr);
if ( ! partition ) { return 0 ; }
err = esp_partition_mmap ( partition , 0 , 4 * SPI_FLASH_MMU_PAGE_SIZE , SPI_FLASH_MMAP_DATA , ( const void * * ) & TasmotaGlobal_mmap_data , & handle ) ;
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " DBG: Partition start 0x%08X, Partition end 0x%08X, Mmap data 0x%08X " ) , partition - > address , partition - > size , TasmotaGlobal_mmap_data ) ;
2020-11-22 16:35:04 +00:00
} else {
spi_flash_munmap ( handle ) ;
handle = 0 ;
}
return err ;
}
*/
2020-04-10 17:24:08 +01:00
2020-04-19 14:36:04 +01:00
//
// ESP32 specific
//
# include "soc/soc.h"
# include "soc/rtc_cntl_reg.h"
2020-04-22 15:07:52 +01:00
void DisableBrownout ( void ) {
2020-04-19 14:36:04 +01:00
// https://github.com/espressif/arduino-esp32/issues/863#issuecomment-347179737
WRITE_PERI_REG ( RTC_CNTL_BROWN_OUT_REG , 0 ) ; // Disable brownout detector
}
2020-04-19 15:58:13 +01:00
//
// ESP32 Alternatives
//
2020-04-22 15:07:52 +01:00
String ESP32GetResetReason ( uint32_t cpu_no ) {
2020-04-19 15:58:13 +01:00
// tools\sdk\include\esp32\rom\rtc.h
2021-06-29 17:15:22 +01:00
// tools\sdk\esp32\include\esp_rom\include\esp32c3\rom\rtc.h
2021-02-02 16:55:45 +00:00
// tools\sdk\esp32\include\esp_rom\include\esp32s2\rom\rtc.h
2021-06-29 17:15:22 +01:00
switch ( rtc_get_reset_reason ( cpu_no ) ) { // ESP32 ESP32-S / ESP32-C
case 1 : return F ( " Vbat power on reset " ) ; // 1 POWERON_RESET POWERON_RESET
case 3 : return F ( " Software reset digital core " ) ; // 3 SW_RESET RTC_SW_SYS_RESET
case 4 : return F ( " Legacy watch dog reset digital core " ) ; // 4 OWDT_RESET -
case 5 : return F ( " Deep Sleep reset digital core " ) ; // 5 DEEPSLEEP_RESET DEEPSLEEP_RESET
case 6 : return F ( " Reset by SLC module, reset digital core " ) ; // 6 SDIO_RESET
case 7 : return F ( " Timer Group0 Watch dog reset digital core " ) ; // 7 TG0WDT_SYS_RESET
case 8 : return F ( " Timer Group1 Watch dog reset digital core " ) ; // 8 TG1WDT_SYS_RESET
case 9 : return F ( " RTC Watch dog Reset digital core " ) ; // 9 RTCWDT_SYS_RESET
case 10 : return F ( " Instrusion tested to reset CPU " ) ; // 10 INTRUSION_RESET
case 11 : return F ( " Time Group0 reset CPU " ) ; // 11 TGWDT_CPU_RESET TG0WDT_CPU_RESET
case 12 : return F ( " Software reset CPU " ) ; // 12 SW_CPU_RESET RTC_SW_CPU_RESET
case 13 : return F ( " RTC Watch dog Reset CPU " ) ; // 13 RTCWDT_CPU_RESET
case 14 : return F ( " or APP CPU, reseted by PRO CPU " ) ; // 14 EXT_CPU_RESET -
case 15 : return F ( " Reset when the vdd voltage is not stable " ) ; // 15 RTCWDT_BROWN_OUT_RESET
case 16 : return F ( " RTC Watch dog reset digital core and rtc module " ) ; // 16 RTCWDT_RTC_RESET
case 17 : return F ( " Time Group1 reset CPU " ) ; // 17 - TG1WDT_CPU_RESET
case 18 : return F ( " Super watchdog reset digital core and rtc module " ) ; // 18 - SUPER_WDT_RESET
case 19 : return F ( " Glitch reset digital core and rtc module " ) ; // 19 - GLITCH_RTC_RESET
2022-04-04 10:23:40 +01:00
case 20 : return F ( " Efuse reset digital core " ) ; // 20 EFUSE_RESET
case 21 : return F ( " Usb uart reset digital core " ) ; // 21 USB_UART_CHIP_RESET
case 22 : return F ( " Usb jtag reset digital core " ) ; // 22 USB_JTAG_CHIP_RESET
case 23 : return F ( " Power glitch reset digital core and rtc module " ) ; // 23 POWER_GLITCH_RESET
2021-02-02 16:55:45 +00:00
}
2021-06-29 17:15:22 +01:00
return F ( " No meaning " ) ; // 0 and undefined
2020-04-19 15:58:13 +01:00
}
2020-04-22 15:07:52 +01:00
String ESP_getResetReason ( void ) {
2020-04-19 15:58:13 +01:00
return ESP32GetResetReason ( 0 ) ; // CPU 0
}
2020-04-22 15:07:52 +01:00
uint32_t ESP_ResetInfoReason ( void ) {
2020-04-19 15:58:13 +01:00
RESET_REASON reason = rtc_get_reset_reason ( 0 ) ;
2021-06-29 17:15:22 +01:00
if ( 1 = = reason ) { return REASON_DEFAULT_RST ; } // POWERON_RESET
if ( 12 = = reason ) { return REASON_SOFT_RESTART ; } // SW_CPU_RESET / RTC_SW_CPU_RESET
if ( 5 = = reason ) { return REASON_DEEP_SLEEP_AWAKE ; } // DEEPSLEEP_RESET
if ( 3 = = reason ) { return REASON_EXT_SYS_RST ; } // SW_RESET / RTC_SW_SYS_RESET
2020-11-15 08:57:23 +00:00
return - 1 ; //no "official error code", but should work with the current code base
2020-04-19 15:58:13 +01:00
}
2020-04-22 15:07:52 +01:00
uint32_t ESP_getChipId ( void ) {
2020-04-19 15:58:13 +01:00
uint32_t id = 0 ;
for ( uint32_t i = 0 ; i < 17 ; i = i + 8 ) {
id | = ( ( ESP . getEfuseMac ( ) > > ( 40 - i ) ) & 0xff ) < < i ;
}
return id ;
}
2022-09-17 14:53:58 +01:00
uint32_t ESP_getFlashChipMagicSize ( void )
{
esp_image_header_t fhdr ;
if ( ESP . flashRead ( ESP_FLASH_IMAGE_BASE , ( uint32_t * ) & fhdr , sizeof ( esp_image_header_t ) ) & & fhdr . magic ! = ESP_IMAGE_HEADER_MAGIC ) {
return 0 ;
}
return ESP_magicFlashChipSize ( fhdr . spi_size ) ;
}
uint32_t ESP_magicFlashChipSize ( uint8_t byte )
{
switch ( byte & 0x0F ) {
case 0x0 : // 8 MBit (1MB)
return 1048576 ;
case 0x1 : // 16 MBit (2MB)
return 2097152 ;
case 0x2 : // 32 MBit (4MB)
return 4194304 ;
case 0x3 : // 64 MBit (8MB)
return 8388608 ;
case 0x4 : // 128 MBit (16MB)
return 16777216 ;
default : // fail?
return 0 ;
}
}
2020-04-22 15:07:52 +01:00
uint32_t ESP_getSketchSize ( void ) {
2020-04-19 15:58:13 +01:00
static uint32_t sketchsize = 0 ;
if ( ! sketchsize ) {
sketchsize = ESP . getSketchSize ( ) ; // This takes almost 2 seconds on an ESP32
}
return sketchsize ;
}
2022-05-07 10:05:10 +01:00
uint32_t ESP_getFreeSketchSpace ( void ) {
if ( EspSingleOtaPartition ( ) ) {
uint32_t size = EspRunningFactoryPartition ( ) ;
if ( ! size ) {
size = ESP . getFreeSketchSpace ( ) ;
}
return size - ESP_getSketchSize ( ) ;
}
return ESP . getFreeSketchSpace ( ) ;
}
2020-04-22 15:07:52 +01:00
uint32_t ESP_getFreeHeap ( void ) {
2021-10-07 17:37:58 +01:00
// ESP_getFreeHeap() returns also IRAM which we don't use
return heap_caps_get_free_size ( MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT ) ;
2020-04-22 15:07:52 +01:00
}
2020-08-12 10:46:06 +01:00
uint32_t ESP_getMaxAllocHeap ( void ) {
2021-10-07 17:37:58 +01:00
// arduino returns IRAM but we want only DRAM
uint32_t free_block_size = heap_caps_get_largest_free_block ( MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT ) ;
2020-08-12 11:11:47 +01:00
if ( free_block_size > 100 ) { free_block_size - = 100 ; }
return free_block_size ;
2020-08-12 10:46:06 +01:00
}
2021-10-08 10:52:50 +01:00
int32_t ESP_getHeapFragmentation ( void ) {
int32_t free_maxmem = 100 - ( int32_t ) ( ESP_getMaxAllocHeap ( ) * 100 / ESP_getFreeHeap ( ) ) ;
if ( free_maxmem < 0 ) { free_maxmem = 0 ; }
return free_maxmem ;
}
2020-04-22 15:07:52 +01:00
void ESP_Restart ( void ) {
2020-04-19 15:58:13 +01:00
ESP . restart ( ) ;
}
2020-11-22 16:35:04 +00:00
uint32_t FlashWriteStartSector ( void ) {
// Needs to be on SPI_FLASH_MMU_PAGE_SIZE (= 0x10000) alignment for mmap usage
uint32_t aligned_address = ( ( EspFlashBaseAddress ( ) + ( 2 * SPI_FLASH_MMU_PAGE_SIZE ) ) / SPI_FLASH_MMU_PAGE_SIZE ) * SPI_FLASH_MMU_PAGE_SIZE ;
return aligned_address / SPI_FLASH_SEC_SIZE ;
}
uint32_t FlashWriteMaxSector ( void ) {
// Needs to be on SPI_FLASH_MMU_PAGE_SIZE (= 0x10000) alignment for mmap usage
uint32_t aligned_end_address = ( EspFlashBaseEndAddress ( ) / SPI_FLASH_MMU_PAGE_SIZE ) * SPI_FLASH_MMU_PAGE_SIZE ;
return aligned_end_address / SPI_FLASH_SEC_SIZE ;
}
uint8_t * FlashDirectAccess ( void ) {
uint32_t address = FlashWriteStartSector ( ) * SPI_FLASH_SEC_SIZE ;
uint8_t * data = EspFlashMmap ( address ) ;
/*
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " DBG: Flash start address 0x%08X, Mmap address 0x%08X " ) , address , data ) ;
2020-11-22 16:35:04 +00:00
uint8_t buf [ 32 ] ;
memcpy ( buf , data , sizeof ( buf ) ) ;
AddLogBuffer ( LOG_LEVEL_DEBUG , ( uint8_t * ) & buf , 32 ) ;
*/
return data ;
}
2021-01-01 16:04:36 +00:00
2021-09-01 21:48:02 +01:00
extern " C " {
bool esp_spiram_is_initialized ( void ) ;
}
// this function is a replacement for `psramFound()`.
// `psramFound()` can return true even if no PSRAM is actually installed
// This new version also checks `esp_spiram_is_initialized` to know if the PSRAM is initialized
bool FoundPSRAM ( void ) {
2021-09-02 19:54:50 +01:00
# if CONFIG_IDF_TARGET_ESP32C3
return psramFound ( ) ;
# else
2021-09-01 21:48:02 +01:00
return psramFound ( ) & & esp_spiram_is_initialized ( ) ;
2021-09-02 19:54:50 +01:00
# endif
2021-09-01 21:48:02 +01:00
}
2021-07-18 18:43:33 +01:00
// new function to check whether PSRAM is present and supported (i.e. required pacthes are present)
bool UsePSRAM ( void ) {
static bool can_use_psram = CanUsePSRAM ( ) ;
2021-09-01 21:48:02 +01:00
return FoundPSRAM ( ) & & can_use_psram ;
2021-07-18 18:43:33 +01:00
}
2021-01-04 15:39:00 +00:00
void * special_malloc ( uint32_t size ) {
2021-07-18 18:43:33 +01:00
if ( UsePSRAM ( ) ) {
2021-01-04 15:39:00 +00:00
return heap_caps_malloc ( size , MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT ) ;
} else {
return malloc ( size ) ;
}
}
2021-03-20 17:44:35 +00:00
void * special_realloc ( void * ptr , size_t size ) {
2021-07-18 18:43:33 +01:00
if ( UsePSRAM ( ) ) {
2021-03-20 17:44:35 +00:00
return heap_caps_realloc ( ptr , size , MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT ) ;
} else {
return realloc ( ptr , size ) ;
}
}
2021-05-09 17:15:15 +01:00
void * special_calloc ( size_t num , size_t size ) {
2021-07-18 18:43:33 +01:00
if ( UsePSRAM ( ) ) {
2021-05-09 17:15:15 +01:00
return heap_caps_calloc ( num , size , MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT ) ;
} else {
return calloc ( num , size ) ;
}
}
2021-01-04 15:39:00 +00:00
2022-01-06 12:41:51 +00:00
// Variants for IRAM heap, which need all accesses to be 32 bits aligned
void * special_malloc32 ( uint32_t size ) {
2022-02-15 21:51:11 +00:00
return heap_caps_malloc ( size , MALLOC_CAP_32BIT ) ;
2022-01-06 12:41:51 +00:00
}
2021-04-12 13:59:40 +01:00
float CpuTemperature ( void ) {
2021-10-10 10:22:53 +01:00
return ( float ) temperatureRead ( ) ; // In Celsius
2021-04-12 13:59:40 +01:00
}
2021-10-10 10:22:53 +01:00
/*
# ifdef __cplusplus
extern " C " {
# endif
uint8_t temprature_sens_read ( ) ;
# ifdef __cplusplus
}
# endif
# ifdef CONFIG_IDF_TARGET_ESP32
uint8_t temprature_sens_read ( ) ;
float CpuTemperature ( void ) {
uint8_t t = temprature_sens_read ( ) ;
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " TMP: value %d " ) , t ) ;
return ( t - 32 ) / 1.8 ;
}
# else
float CpuTemperature ( void ) {
// Currently (20210801) repeated calls to temperatureRead() on ESP32C3 and ESP32S2 result in IDF error messages
static float t = NAN ;
if ( isnan ( t ) ) {
t = ( float ) temperatureRead ( ) ; // In Celsius
}
return t ;
}
# endif
*/
2021-04-17 16:32:20 +01:00
/*
# if CONFIG_IDF_TARGET_ESP32S2
# include "esp32s2/esp_efuse.h"
# elif CONFIG_IDF_TARGET_ESP32S3
# include "esp32s3/esp_efuse.h"
# elif CONFIG_IDF_TARGET_ESP32C3
# include "esp32c3/esp_efuse.h"
# endif
*/
2022-02-01 11:05:56 +00:00
// #include "esp_chip_info.h"
2021-02-08 10:34:29 +00:00
String GetDeviceHardware ( void ) {
2021-04-19 16:48:18 +01:00
// https://www.espressif.com/en/products/socs
2021-04-17 14:57:35 +01:00
/*
Source : esp - idf esp_system . h and esptool
typedef enum {
2022-02-01 11:05:56 +00:00
CHIP_ESP32 = 1 , //!< ESP32
CHIP_ESP32S2 = 2 , //!< ESP32-S2
CHIP_ESP32S3 = 9 , //!< ESP32-S3
CHIP_ESP32C3 = 5 , //!< ESP32-C3
CHIP_ESP32H2 = 6 , //!< ESP32-H2
CHIP_ESP32C2 = 12 , //!< ESP32-C2
2021-04-17 14:57:35 +01:00
} esp_chip_model_t ;
// Chip feature flags, used in esp_chip_info_t
# define CHIP_FEATURE_EMB_FLASH BIT(0) //!< Chip has embedded flash memory
# define CHIP_FEATURE_WIFI_BGN BIT(1) //!< Chip has 2.4GHz WiFi
# define CHIP_FEATURE_BLE BIT(4) //!< Chip has Bluetooth LE
# define CHIP_FEATURE_BT BIT(5) //!< Chip has Bluetooth Classic
2022-02-01 11:05:56 +00:00
# define CHIP_FEATURE_IEEE802154 BIT(6) //!< Chip has IEEE 802.15.4
# define CHIP_FEATURE_EMB_PSRAM BIT(7) //!< Chip has embedded psram
2021-04-17 14:57:35 +01:00
// The structure represents information about the chip
typedef struct {
esp_chip_model_t model ; //!< chip model, one of esp_chip_model_t
uint32_t features ; //!< bit mask of CHIP_FEATURE_x feature flags
uint8_t cores ; //!< number of CPU cores
uint8_t revision ; //!< chip revision number
} esp_chip_info_t ;
2021-02-08 10:34:29 +00:00
2021-04-17 14:57:35 +01:00
*/
esp_chip_info_t chip_info ;
esp_chip_info ( & chip_info ) ;
uint32_t chip_model = chip_info . model ;
uint32_t chip_revision = chip_info . revision ;
// uint32_t chip_revision = ESP.getChipRevision();
bool rev3 = ( 3 = = chip_revision ) ;
// bool single_core = (1 == ESP.getChipCores());
bool single_core = ( 1 = = chip_info . cores ) ;
if ( chip_model < 2 ) { // ESP32
# ifdef CONFIG_IDF_TARGET_ESP32
/* esptool:
def get_pkg_version ( self ) :
word3 = self . read_efuse ( 3 )
pkg_version = ( word3 > > 9 ) & 0x07
pkg_version + = ( ( word3 > > 2 ) & 0x1 ) < < 3
return pkg_version
*/
uint32_t chip_ver = REG_GET_FIELD ( EFUSE_BLK0_RDATA3_REG , EFUSE_RD_CHIP_VER_PKG ) ;
uint32_t pkg_version = chip_ver & 0x7 ;
2021-04-22 14:51:50 +01:00
// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("HDW: ESP32 Model %d, Revision %d, Core %d, Package %d"), chip_info.model, chip_revision, chip_info.cores, chip_ver);
2021-04-19 14:34:49 +01:00
2021-04-17 14:57:35 +01:00
switch ( pkg_version ) {
case 0 :
2021-04-19 15:36:05 +01:00
if ( single_core ) { return F ( " ESP32-S0WDQ6 " ) ; } // Max 240MHz, Single core, QFN 6*6
else if ( rev3 ) { return F ( " ESP32-D0WDQ6-V3 " ) ; } // Max 240MHz, Dual core, QFN 6*6
else { return F ( " ESP32-D0WDQ6 " ) ; } // Max 240MHz, Dual core, QFN 6*6
2021-04-17 14:57:35 +01:00
case 1 :
2021-04-19 16:48:18 +01:00
if ( single_core ) { return F ( " ESP32-S0WD " ) ; } // Max 160MHz, Single core, QFN 5*5, ESP32-SOLO-1, ESP32-DevKitC
else if ( rev3 ) { return F ( " ESP32-D0WD-V3 " ) ; } // Max 240MHz, Dual core, QFN 5*5, ESP32-WROOM-32E, ESP32_WROVER-E, ESP32-DevKitC
else { return F ( " ESP32-D0WD " ) ; } // Max 240MHz, Dual core, QFN 5*5, ESP32-WROOM-32D, ESP32_WROVER-B, ESP32-DevKitC
2021-04-19 15:36:05 +01:00
case 2 : return F ( " ESP32-D2WD " ) ; // Max 160MHz, Dual core, QFN 5*5, 2MB embedded flash
2021-04-19 16:48:18 +01:00
case 3 :
if ( single_core ) { return F ( " ESP32-S0WD-OEM " ) ; } // Max 160MHz, Single core, QFN 5*5, Xiaomi Yeelight
else { return F ( " ESP32-D0WD-OEM " ) ; } // Max 240MHz, Dual core, QFN 5*5
2022-10-04 11:51:53 +01:00
case 4 :
if ( single_core ) { return F ( " ESP32-U4WDH-S " ) ; } // Max 160MHz, Single core, QFN 5*5, 4MB embedded flash, ESP32-MINI-1, ESP32-DevKitM-1
else { return F ( " ESP32-U4WDH-D " ) ; } // Max 240MHz, Dual core, QFN 5*5, 4MB embedded flash
2021-04-17 14:57:35 +01:00
case 5 :
2021-04-19 16:48:18 +01:00
if ( rev3 ) { return F ( " ESP32-PICO-V3 " ) ; } // Max 240MHz, Dual core, LGA 7*7, ESP32-PICO-V3-ZERO, ESP32-PICO-V3-ZERO-DevKit
else { return F ( " ESP32-PICO-D4 " ) ; } // Max 240MHz, Dual core, LGA 7*7, 4MB embedded flash, ESP32-PICO-KIT
case 6 : return F ( " ESP32-PICO-V3-02 " ) ; // Max 240MHz, Dual core, LGA 7*7, 8MB embedded flash, 2MB embedded PSRAM, ESP32-PICO-MINI-02, ESP32-PICO-DevKitM-2
2022-04-30 15:50:37 +01:00
case 7 : return F ( " ESP32-D0WDR2-V3 " ) ; // Max 240MHz, Dual core, QFN 5*5, ESP32-WROOM-32E, ESP32_WROVER-E, ESP32-DevKitC
2021-04-17 14:57:35 +01:00
}
# endif // CONFIG_IDF_TARGET_ESP32
return F ( " ESP32 " ) ;
2021-02-08 10:34:29 +00:00
}
2021-04-17 14:57:35 +01:00
else if ( 2 = = chip_model ) { // ESP32-S2
# ifdef CONFIG_IDF_TARGET_ESP32S2
/* esptool:
2022-04-30 15:50:37 +01:00
def get_flash_version ( self ) :
2021-04-17 14:57:35 +01:00
num_word = 3
block1_addr = self . EFUSE_BASE + 0x044
word3 = self . read_reg ( block1_addr + ( 4 * num_word ) )
pkg_version = ( word3 > > 21 ) & 0x0F
return pkg_version
2022-04-30 15:50:37 +01:00
def get_psram_version ( self ) :
num_word = 3
block1_addr = self . EFUSE_BASE + 0x044
word3 = self . read_reg ( block1_addr + ( 4 * num_word ) )
pkg_version = ( word3 > > 28 ) & 0x0F
return pkg_version
2021-04-17 14:57:35 +01:00
*/
2022-04-30 15:50:37 +01:00
uint32_t chip_ver = REG_GET_FIELD ( EFUSE_RD_MAC_SPI_SYS_3_REG , EFUSE_FLASH_VERSION ) ;
uint32_t psram_ver = REG_GET_FIELD ( EFUSE_RD_MAC_SPI_SYS_3_REG , EFUSE_PSRAM_VERSION ) ;
uint32_t pkg_version = ( chip_ver & 0xF ) + ( ( psram_ver & 0xF ) * 100 ) ;
2021-04-17 14:57:35 +01:00
2021-04-22 14:51:50 +01:00
// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("HDW: ESP32 Model %d, Revision %d, Core %d, Package %d"), chip_info.model, chip_revision, chip_info.cores, chip_ver);
2021-04-19 14:34:49 +01:00
2021-04-17 14:57:35 +01:00
switch ( pkg_version ) {
2021-04-19 16:48:18 +01:00
case 0 : return F ( " ESP32-S2 " ) ; // Max 240MHz, Single core, QFN 7*7, ESP32-S2-WROOM, ESP32-S2-WROVER, ESP32-S2-Saola-1, ESP32-S2-Kaluga-1
case 1 : return F ( " ESP32-S2FH2 " ) ; // Max 240MHz, Single core, QFN 7*7, 2MB embedded flash, ESP32-S2-MINI-1, ESP32-S2-DevKitM-1
2021-04-19 15:36:05 +01:00
case 2 : return F ( " ESP32-S2FH4 " ) ; // Max 240MHz, Single core, QFN 7*7, 4MB embedded flash
2021-04-19 16:48:18 +01:00
case 3 : return F ( " ESP32-S2FN4R2 " ) ; // Max 240MHz, Single core, QFN 7*7, 4MB embedded flash, 2MB embedded PSRAM, , ESP32-S2-MINI-1U, ESP32-S2-DevKitM-1U
2022-04-30 15:50:37 +01:00
case 100 : return F ( " ESP32-S2R2 " ) ;
case 102 : return F ( " ESP32-S2FNR2 " ) ; // Max 240MHz, Single core, QFN 7*7, 4MB embedded flash, 2MB embedded PSRAM, , Lolin S2 mini
2021-04-17 14:57:35 +01:00
}
# endif // CONFIG_IDF_TARGET_ESP32S2
return F ( " ESP32-S2 " ) ;
}
2022-02-01 11:05:56 +00:00
else if ( 9 = = chip_model ) { // ESP32-S3
# ifdef CONFIG_IDF_TARGET_ESP32S3
// no variants for now
# endif // CONFIG_IDF_TARGET_ESP32S3
2021-04-19 16:48:18 +01:00
return F ( " ESP32-S3 " ) ; // Max 240MHz, Dual core, QFN 7*7, ESP32-S3-WROOM-1, ESP32-S3-DevKitC-1
2021-04-17 14:57:35 +01:00
}
else if ( 5 = = chip_model ) { // ESP32-C3
# ifdef CONFIG_IDF_TARGET_ESP32C3
/* esptool:
def get_pkg_version ( self ) :
num_word = 3
block1_addr = self . EFUSE_BASE + 0x044
word3 = self . read_reg ( block1_addr + ( 4 * num_word ) )
pkg_version = ( word3 > > 21 ) & 0x0F
return pkg_version
*/
2021-04-17 16:32:20 +01:00
uint32_t chip_ver = REG_GET_FIELD ( EFUSE_RD_MAC_SPI_SYS_3_REG , EFUSE_PKG_VERSION ) ;
uint32_t pkg_version = chip_ver & 0x7 ;
// uint32_t pkg_version = esp_efuse_get_pkg_ver();
2021-04-17 14:57:35 +01:00
2021-04-22 14:51:50 +01:00
// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("HDW: ESP32 Model %d, Revision %d, Core %d, Package %d"), chip_info.model, chip_revision, chip_info.cores, chip_ver);
2021-04-19 14:34:49 +01:00
2021-04-17 14:57:35 +01:00
switch ( pkg_version ) {
2021-04-19 16:48:18 +01:00
case 0 : return F ( " ESP32-C3 " ) ; // Max 160MHz, Single core, QFN 5*5, ESP32-C3-WROOM-02, ESP32-C3-DevKitC-02
case 1 : return F ( " ESP32-C3FH4 " ) ; // Max 160MHz, Single core, QFN 5*5, 4MB embedded flash, ESP32-C3-MINI-1, ESP32-C3-DevKitM-1
2021-04-17 14:57:35 +01:00
}
# endif // CONFIG_IDF_TARGET_ESP32C3
return F ( " ESP32-C3 " ) ;
2021-02-08 10:34:29 +00:00
}
2021-04-17 14:57:35 +01:00
else if ( 6 = = chip_model ) { // ESP32-S3(beta3)
2021-04-19 15:36:05 +01:00
return F ( " ESP32-S3 " ) ;
2021-04-17 14:57:35 +01:00
}
2021-07-02 09:20:26 +01:00
else if ( 7 = = chip_model ) { // ESP32-C6(beta)
2021-04-17 14:57:35 +01:00
# ifdef CONFIG_IDF_TARGET_ESP32C6
/* esptool:
def get_pkg_version ( self ) :
num_word = 3
block1_addr = self . EFUSE_BASE + 0x044
word3 = self . read_reg ( block1_addr + ( 4 * num_word ) )
pkg_version = ( word3 > > 21 ) & 0x0F
return pkg_version
*/
2021-04-17 16:32:20 +01:00
uint32_t chip_ver = REG_GET_FIELD ( EFUSE_RD_MAC_SPI_SYS_3_REG , EFUSE_PKG_VERSION ) ;
uint32_t pkg_version = chip_ver & 0x7 ;
// uint32_t pkg_version = esp_efuse_get_pkg_ver();
2021-04-17 14:57:35 +01:00
2021-04-22 14:51:50 +01:00
// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("HDW: ESP32 Model %d, Revision %d, Core %d, Package %d"), chip_info.model, chip_revision, chip_info.cores, chip_ver);
2021-04-19 14:34:49 +01:00
2021-04-17 14:57:35 +01:00
switch ( pkg_version ) {
case 0 : return F ( " ESP32-C6 " ) ;
}
# endif // CONFIG_IDF_TARGET_ESP32C6
return F ( " ESP32-C6 " ) ;
}
2021-07-02 09:20:26 +01:00
else if ( 10 = = chip_model ) { // ESP32-H2
# ifdef CONFIG_IDF_TARGET_ESP32H2
/* esptool:
def get_pkg_version ( self ) :
num_word = 3
block1_addr = self . EFUSE_BASE + 0x044
word3 = self . read_reg ( block1_addr + ( 4 * num_word ) )
pkg_version = ( word3 > > 21 ) & 0x0F
return pkg_version
*/
uint32_t chip_ver = REG_GET_FIELD ( EFUSE_RD_MAC_SPI_SYS_3_REG , EFUSE_PKG_VERSION ) ;
uint32_t pkg_version = chip_ver & 0x7 ;
// uint32_t pkg_version = esp_efuse_get_pkg_ver();
// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("HDW: ESP32 Model %d, Revision %d, Core %d, Package %d"), chip_info.model, chip_revision, chip_info.cores, chip_ver);
switch ( pkg_version ) {
case 0 : return F ( " ESP32-H2 " ) ;
}
# endif // CONFIG_IDF_TARGET_ESP32H2
return F ( " ESP32-H2 " ) ;
}
2021-04-17 14:57:35 +01:00
return F ( " ESP32 " ) ;
}
2021-02-08 10:34:29 +00:00
2022-04-23 16:59:37 +01:00
String GetDeviceHardwareRevision ( void ) {
2022-04-24 10:24:01 +01:00
// ESP32-S2
// ESP32-D0WDQ6 rev.1
// ESP32-C3 rev.2
// ESP32-C3 rev.3
String result = GetDeviceHardware ( ) ; // ESP32-C3
2022-04-23 16:59:37 +01:00
esp_chip_info_t chip_info ;
esp_chip_info ( & chip_info ) ;
2022-04-23 21:48:30 +01:00
char revision [ 10 ] = { 0 } ;
if ( chip_info . revision ) {
snprintf_P ( revision , sizeof ( revision ) , PSTR ( " rev.%d " ) , chip_info . revision ) ;
}
2022-04-24 10:24:01 +01:00
result + = revision ; // ESP32-C3 rev.3
return result ;
2022-04-23 16:59:37 +01:00
}
2022-10-04 16:52:15 +01:00
String GetCodeCores ( void ) {
# if defined(CORE32SOLO1)
return F ( " single-core " ) ;
# else
return F ( " " ) ;
# endif
}
2021-07-18 18:43:33 +01:00
/*
* ESP32 v1 and v2 needs some special patches to use PSRAM .
* Standard Tasmota 32 do not include those patches .
* If using ESP32 v1 , please add : ` - mfix - esp32 - psram - cache - issue - lc - psram - workaround - lm - psram - workaround `
2021-09-03 10:19:45 +01:00
*
* This function returns true if the chip supports PSRAM natively ( v3 ) or if the
2021-07-18 18:43:33 +01:00
* patches are present .
*/
bool CanUsePSRAM ( void ) {
2021-09-01 21:48:02 +01:00
if ( ! FoundPSRAM ( ) ) return false ;
2021-07-18 18:43:33 +01:00
# ifdef HAS_PSRAM_FIX
return true ;
# endif
# ifdef CONFIG_IDF_TARGET_ESP32
esp_chip_info_t chip_info ;
esp_chip_info ( & chip_info ) ;
if ( ( CHIP_ESP32 = = chip_info . model ) & & ( chip_info . revision < 3 ) ) {
return false ;
}
# if ESP_IDF_VERSION_MAJOR < 4
uint32_t chip_ver = REG_GET_FIELD ( EFUSE_BLK0_RDATA3_REG , EFUSE_RD_CHIP_VER_PKG ) ;
uint32_t pkg_version = chip_ver & 0x7 ;
if ( ( CHIP_ESP32 = = chip_info . model ) & & ( pkg_version > = 6 ) ) {
return false ; // support for embedded PSRAM of ESP32-PICO-V3-02 requires esp-idf 4.4
}
# endif // ESP_IDF_VERSION_MAJOR < 4
# endif // CONFIG_IDF_TARGET_ESP32
return true ;
}
2021-02-08 10:34:29 +00:00
# endif // ESP32
2021-04-17 14:57:35 +01:00
/*********************************************************************************************\
* ESP Support
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2021-02-08 10:34:29 +00:00
uint32_t ESP_getFreeHeap1024 ( void ) {
return ESP_getFreeHeap ( ) / 1024 ;
}
/*
float ESP_getFreeHeap1024 ( void ) {
return ( ( float ) ESP_getFreeHeap ( ) ) / 1024 ;
}
*/
2022-08-21 13:49:09 +01:00
const char kFlashModes [ ] PROGMEM = " QIO|QOUT|DIO|DOUT|Fast|Slow " ;
/*
typedef enum {
FM_QIO = 0x00 ,
FM_QOUT = 0x01 ,
FM_DIO = 0x02 ,
FM_DOUT = 0x03 ,
FM_FAST_READ = 0x04 ,
FM_SLOW_READ = 0x05 ,
FM_UNKNOWN = 0xff
} FlashMode_t ;
*/
2022-08-21 13:21:17 +01:00
String ESP_getFlashChipMode ( void ) {
2022-08-21 13:49:09 +01:00
uint32_t flash_mode = ESP . getFlashChipMode ( ) ;
if ( flash_mode > 5 ) { flash_mode = 3 ; }
2022-08-21 13:21:17 +01:00
char stemp [ 6 ] ;
return GetTextIndexed ( stemp , sizeof ( stemp ) , flash_mode , kFlashModes ) ;
}
2021-02-08 10:34:29 +00:00
/*********************************************************************************************\
* 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 ) {
# 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
# define _RAND_ADDR 0x3FF75144UL
# endif // ESP32
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
2022-09-17 14:53:58 +01:00
}