mirror of
https://github.com/espressif/arduino-esp32
synced 2024-09-21 10:28:04 +00:00
1d895e58e7
* fix(xtal): Add a way to change the XTAL frequency Add support for boards like SparkFun ESP32 Thing that use 26MHz XTAL * ci(pre-commit): Apply automatic fixes * feat(dbg): Print the XTAL frequency in the debug report --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
405 lines
11 KiB
C
405 lines
11 KiB
C
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "sdkconfig.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "esp_attr.h"
|
|
#include "nvs_flash.h"
|
|
#include "nvs.h"
|
|
#include "esp_partition.h"
|
|
#include "esp_log.h"
|
|
#include "esp_timer.h"
|
|
#ifdef CONFIG_APP_ROLLBACK_ENABLE
|
|
#include "esp_ota_ops.h"
|
|
#endif //CONFIG_APP_ROLLBACK_ENABLE
|
|
#ifdef CONFIG_BT_ENABLED
|
|
#include "esp_bt.h"
|
|
#endif //CONFIG_BT_ENABLED
|
|
#include <sys/time.h>
|
|
#include "soc/rtc.h"
|
|
#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2)
|
|
#include "soc/rtc_cntl_reg.h"
|
|
#include "soc/apb_ctrl_reg.h"
|
|
#endif
|
|
#include "esp_task_wdt.h"
|
|
#include "esp32-hal.h"
|
|
|
|
#include "esp_system.h"
|
|
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
|
|
|
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
|
#include "esp32/rom/rtc.h"
|
|
#elif CONFIG_IDF_TARGET_ESP32S2
|
|
#include "esp32s2/rom/rtc.h"
|
|
#elif CONFIG_IDF_TARGET_ESP32S3
|
|
#include "esp32s3/rom/rtc.h"
|
|
#elif CONFIG_IDF_TARGET_ESP32C2
|
|
#include "esp32c2/rom/rtc.h"
|
|
#elif CONFIG_IDF_TARGET_ESP32C3
|
|
#include "esp32c3/rom/rtc.h"
|
|
#elif CONFIG_IDF_TARGET_ESP32C6
|
|
#include "esp32c6/rom/rtc.h"
|
|
#elif CONFIG_IDF_TARGET_ESP32H2
|
|
#include "esp32h2/rom/rtc.h"
|
|
|
|
#else
|
|
#error Target CONFIG_IDF_TARGET is not supported
|
|
#endif
|
|
|
|
#if SOC_TEMP_SENSOR_SUPPORTED
|
|
#include "driver/temperature_sensor.h"
|
|
#endif
|
|
|
|
#else // ESP32 Before IDF 4.0
|
|
#include "rom/rtc.h"
|
|
#endif
|
|
|
|
//Undocumented!!! Get chip temperature in Fahrenheit
|
|
//Source: https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_int_temp_sensor/ESP32_int_temp_sensor.ino
|
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
|
uint8_t temprature_sens_read();
|
|
|
|
float temperatureRead() {
|
|
return (temprature_sens_read() - 32) / 1.8;
|
|
}
|
|
#elif SOC_TEMP_SENSOR_SUPPORTED
|
|
static temperature_sensor_handle_t temp_sensor = NULL;
|
|
|
|
static bool temperatureReadInit() {
|
|
static volatile bool initialized = false;
|
|
if (!initialized) {
|
|
initialized = true;
|
|
//Install temperature sensor, expected temp ranger range: 10~50 ℃
|
|
temperature_sensor_config_t temp_sensor_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(10, 50);
|
|
if (temperature_sensor_install(&temp_sensor_config, &temp_sensor) != ESP_OK) {
|
|
initialized = false;
|
|
temp_sensor = NULL;
|
|
log_e("temperature_sensor_install failed");
|
|
} else if (temperature_sensor_enable(temp_sensor) != ESP_OK) {
|
|
temperature_sensor_uninstall(temp_sensor);
|
|
initialized = false;
|
|
temp_sensor = NULL;
|
|
log_e("temperature_sensor_enable failed");
|
|
}
|
|
}
|
|
return initialized;
|
|
}
|
|
|
|
float temperatureRead() {
|
|
float result = NAN;
|
|
if (temperatureReadInit()) {
|
|
if (temperature_sensor_get_celsius(temp_sensor, &result) != ESP_OK) {
|
|
log_e("temperature_sensor_get_celsius failed");
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
void __yield() {
|
|
vPortYield();
|
|
}
|
|
|
|
void yield() __attribute__((weak, alias("__yield")));
|
|
|
|
#if CONFIG_AUTOSTART_ARDUINO
|
|
|
|
extern TaskHandle_t loopTaskHandle;
|
|
extern bool loopTaskWDTEnabled;
|
|
|
|
void enableLoopWDT() {
|
|
if (loopTaskHandle != NULL) {
|
|
if (esp_task_wdt_add(loopTaskHandle) != ESP_OK) {
|
|
log_e("Failed to add loop task to WDT");
|
|
} else {
|
|
loopTaskWDTEnabled = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void disableLoopWDT() {
|
|
if (loopTaskHandle != NULL && loopTaskWDTEnabled) {
|
|
loopTaskWDTEnabled = false;
|
|
if (esp_task_wdt_delete(loopTaskHandle) != ESP_OK) {
|
|
log_e("Failed to remove loop task from WDT");
|
|
}
|
|
}
|
|
}
|
|
|
|
void feedLoopWDT() {
|
|
esp_err_t err = esp_task_wdt_reset();
|
|
if (err != ESP_OK) {
|
|
log_e("Failed to feed WDT! Error: %d", err);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void enableCore0WDT() {
|
|
TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0);
|
|
if (idle_0 == NULL || esp_task_wdt_add(idle_0) != ESP_OK) {
|
|
log_e("Failed to add Core 0 IDLE task to WDT");
|
|
}
|
|
}
|
|
|
|
void disableCore0WDT() {
|
|
TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0);
|
|
if (idle_0 == NULL || esp_task_wdt_delete(idle_0) != ESP_OK) {
|
|
log_e("Failed to remove Core 0 IDLE task from WDT");
|
|
}
|
|
}
|
|
|
|
#ifndef CONFIG_FREERTOS_UNICORE
|
|
void enableCore1WDT() {
|
|
TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1);
|
|
if (idle_1 == NULL || esp_task_wdt_add(idle_1) != ESP_OK) {
|
|
log_e("Failed to add Core 1 IDLE task to WDT");
|
|
}
|
|
}
|
|
|
|
void disableCore1WDT() {
|
|
TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1);
|
|
if (idle_1 == NULL || esp_task_wdt_delete(idle_1) != ESP_OK) {
|
|
log_e("Failed to remove Core 1 IDLE task from WDT");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
BaseType_t xTaskCreateUniversal(
|
|
TaskFunction_t pxTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority,
|
|
TaskHandle_t *const pxCreatedTask, const BaseType_t xCoreID
|
|
) {
|
|
#ifndef CONFIG_FREERTOS_UNICORE
|
|
if (xCoreID >= 0 && xCoreID < 2) {
|
|
return xTaskCreatePinnedToCore(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask, xCoreID);
|
|
} else {
|
|
#endif
|
|
return xTaskCreate(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask);
|
|
#ifndef CONFIG_FREERTOS_UNICORE
|
|
}
|
|
#endif
|
|
}
|
|
|
|
unsigned long ARDUINO_ISR_ATTR micros() {
|
|
return (unsigned long)(esp_timer_get_time());
|
|
}
|
|
|
|
unsigned long ARDUINO_ISR_ATTR millis() {
|
|
return (unsigned long)(esp_timer_get_time() / 1000ULL);
|
|
}
|
|
|
|
void delay(uint32_t ms) {
|
|
vTaskDelay(ms / portTICK_PERIOD_MS);
|
|
}
|
|
|
|
void ARDUINO_ISR_ATTR delayMicroseconds(uint32_t us) {
|
|
uint64_t m = (uint64_t)esp_timer_get_time();
|
|
if (us) {
|
|
uint64_t e = (m + us);
|
|
if (m > e) { //overflow
|
|
while ((uint64_t)esp_timer_get_time() > e) {
|
|
NOP();
|
|
}
|
|
}
|
|
while ((uint64_t)esp_timer_get_time() < e) {
|
|
NOP();
|
|
}
|
|
}
|
|
}
|
|
|
|
void initVariant() __attribute__((weak));
|
|
void initVariant() {}
|
|
|
|
void init() __attribute__((weak));
|
|
void init() {}
|
|
|
|
#ifdef CONFIG_APP_ROLLBACK_ENABLE
|
|
bool verifyOta() __attribute__((weak));
|
|
bool verifyOta() {
|
|
return true;
|
|
}
|
|
|
|
bool verifyRollbackLater() __attribute__((weak));
|
|
bool verifyRollbackLater() {
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_BT_ENABLED
|
|
#if CONFIG_IDF_TARGET_ESP32
|
|
//overwritten in esp32-hal-bt.c
|
|
bool btInUse() __attribute__((weak));
|
|
bool btInUse() {
|
|
return false;
|
|
}
|
|
#else
|
|
//from esp32-hal-bt.c
|
|
extern bool btInUse();
|
|
#endif
|
|
#endif
|
|
|
|
void initArduino() {
|
|
//init proper ref tick value for PLL (uncomment if REF_TICK is different than 1MHz)
|
|
//ESP_REG(APB_CTRL_PLL_TICK_CONF_REG) = APB_CLK_FREQ / REF_CLK_FREQ - 1;
|
|
#if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM
|
|
psramInit();
|
|
#endif
|
|
#ifdef CONFIG_APP_ROLLBACK_ENABLE
|
|
if (!verifyRollbackLater()) {
|
|
const esp_partition_t *running = esp_ota_get_running_partition();
|
|
esp_ota_img_states_t ota_state;
|
|
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
|
|
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
|
|
if (verifyOta()) {
|
|
esp_ota_mark_app_valid_cancel_rollback();
|
|
} else {
|
|
log_e("OTA verification failed! Start rollback to the previous version ...");
|
|
esp_ota_mark_app_invalid_rollback_and_reboot();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
esp_log_level_set("*", CONFIG_LOG_DEFAULT_LEVEL);
|
|
esp_err_t err = nvs_flash_init();
|
|
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
|
const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
|
|
if (partition != NULL) {
|
|
err = esp_partition_erase_range(partition, 0, partition->size);
|
|
if (!err) {
|
|
err = nvs_flash_init();
|
|
} else {
|
|
log_e("Failed to format the broken NVS partition!");
|
|
}
|
|
} else {
|
|
log_e("Could not find NVS partition");
|
|
}
|
|
}
|
|
if (err) {
|
|
log_e("Failed to initialize NVS! Error: %u", err);
|
|
}
|
|
#ifdef CONFIG_BT_ENABLED
|
|
if (!btInUse()) {
|
|
esp_bt_controller_mem_release(ESP_BT_MODE_BTDM);
|
|
}
|
|
#endif
|
|
init();
|
|
initVariant();
|
|
}
|
|
|
|
//used by hal log
|
|
const char *ARDUINO_ISR_ATTR pathToFileName(const char *path) {
|
|
size_t i = 0;
|
|
size_t pos = 0;
|
|
char *p = (char *)path;
|
|
while (*p) {
|
|
i++;
|
|
if (*p == '/' || *p == '\\') {
|
|
pos = i;
|
|
}
|
|
p++;
|
|
}
|
|
return path + pos;
|
|
}
|
|
|
|
#include "esp_rom_sys.h"
|
|
#include "esp_debug_helpers.h"
|
|
#if CONFIG_IDF_TARGET_ARCH_XTENSA
|
|
#include "esp_cpu_utils.h"
|
|
#else
|
|
#include "riscv/rvruntime-frames.h"
|
|
#endif
|
|
#include "esp_memory_utils.h"
|
|
#include "esp_private/panic_internal.h"
|
|
|
|
static arduino_panic_handler_t _panic_handler = NULL;
|
|
static void *_panic_handler_arg = NULL;
|
|
|
|
void set_arduino_panic_handler(arduino_panic_handler_t handler, void *arg) {
|
|
_panic_handler = handler;
|
|
_panic_handler_arg = arg;
|
|
}
|
|
|
|
arduino_panic_handler_t get_arduino_panic_handler(void) {
|
|
return _panic_handler;
|
|
}
|
|
|
|
void *get_arduino_panic_handler_arg(void) {
|
|
return _panic_handler_arg;
|
|
}
|
|
|
|
static void handle_custom_backtrace(panic_info_t *info) {
|
|
arduino_panic_info_t p_info;
|
|
p_info.reason = info->reason;
|
|
p_info.core = info->core;
|
|
p_info.pc = info->addr;
|
|
p_info.backtrace_len = 0;
|
|
p_info.backtrace_corrupt = false;
|
|
p_info.backtrace_continues = false;
|
|
|
|
#if CONFIG_IDF_TARGET_ARCH_XTENSA
|
|
XtExcFrame *xt_frame = (XtExcFrame *)info->frame;
|
|
esp_backtrace_frame_t stk_frame = {.pc = xt_frame->pc, .sp = xt_frame->a1, .next_pc = xt_frame->a0, .exc_frame = xt_frame};
|
|
uint32_t i = 100, pc_ptr = esp_cpu_process_stack_pc(stk_frame.pc);
|
|
p_info.backtrace[p_info.backtrace_len++] = pc_ptr;
|
|
|
|
bool corrupted = !(esp_stack_ptr_is_sane(stk_frame.sp) && (esp_ptr_executable((void *)esp_cpu_process_stack_pc(stk_frame.pc)) ||
|
|
/* Ignore the first corrupted PC in case of InstrFetchProhibited */
|
|
(stk_frame.exc_frame && ((XtExcFrame *)stk_frame.exc_frame)->exccause == EXCCAUSE_INSTR_PROHIBITED)));
|
|
|
|
while (i-- > 0 && stk_frame.next_pc != 0 && !corrupted) {
|
|
if (!esp_backtrace_get_next_frame(&stk_frame)) {
|
|
corrupted = true;
|
|
}
|
|
pc_ptr = esp_cpu_process_stack_pc(stk_frame.pc);
|
|
if (esp_ptr_executable((void *)pc_ptr)) {
|
|
p_info.backtrace[p_info.backtrace_len++] = pc_ptr;
|
|
if (p_info.backtrace_len == 60) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (corrupted) {
|
|
p_info.backtrace_corrupt = true;
|
|
} else if (stk_frame.next_pc != 0) {
|
|
p_info.backtrace_continues = true;
|
|
}
|
|
#elif CONFIG_IDF_TARGET_ARCH_RISCV
|
|
uint32_t sp = (uint32_t)((RvExcFrame *)info->frame)->sp;
|
|
p_info.backtrace[p_info.backtrace_len++] = sp;
|
|
uint32_t *spptr = (uint32_t *)(sp);
|
|
for (int i = 0; i < 256; i++) {
|
|
if (esp_ptr_executable((void *)spptr[i])) {
|
|
p_info.backtrace[p_info.backtrace_len++] = spptr[i];
|
|
if (p_info.backtrace_len == 60) {
|
|
if (i < 255) {
|
|
p_info.backtrace_continues = true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
_panic_handler(&p_info, _panic_handler_arg);
|
|
}
|
|
|
|
void __real_esp_panic_handler(panic_info_t *);
|
|
void __wrap_esp_panic_handler(panic_info_t *info) {
|
|
if (_panic_handler != NULL) {
|
|
handle_custom_backtrace(info);
|
|
}
|
|
__real_esp_panic_handler(info);
|
|
}
|