mirror of
https://github.com/espressif/esp-idf.git
synced 2026-05-05 12:25:03 +02:00
Merge branch 'master' into driver_merge_tmp/merge_gpio
This commit is contained in:
@@ -1,5 +1,25 @@
|
||||
menu "ESP32-specific config"
|
||||
|
||||
choice ESP32_DEFAULT_CPU_FREQ_MHZ
|
||||
prompt "CPU frequency"
|
||||
default ESP32_DEFAULT_CPU_FREQ_240
|
||||
help
|
||||
CPU frequency to be set on application startup.
|
||||
|
||||
config ESP32_DEFAULT_CPU_FREQ_80
|
||||
bool "80 MHz"
|
||||
config ESP32_DEFAULT_CPU_FREQ_160
|
||||
bool "160 MHz"
|
||||
config ESP32_DEFAULT_CPU_FREQ_240
|
||||
bool "240 MHz"
|
||||
endchoice
|
||||
|
||||
config ESP32_DEFAULT_CPU_FREQ_MHZ
|
||||
int
|
||||
default 80 if ESP32_DEFAULT_CPU_FREQ_80
|
||||
default 160 if ESP32_DEFAULT_CPU_FREQ_160
|
||||
default 240 if ESP32_DEFAULT_CPU_FREQ_240
|
||||
|
||||
config WIFI_ENABLED
|
||||
bool "Enable low-level WiFi stack"
|
||||
default "y"
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
// 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 <stdint.h>
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/uart.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
typedef enum{
|
||||
XTAL_40M = 40,
|
||||
XTAL_26M = 26,
|
||||
XTAL_24M = 24,
|
||||
XTAL_AUTO = 0
|
||||
} xtal_freq_t;
|
||||
|
||||
typedef enum{
|
||||
CPU_80M = 1,
|
||||
CPU_160M = 2,
|
||||
CPU_240M = 3,
|
||||
} cpu_freq_t;
|
||||
|
||||
extern void phy_get_romfunc_addr();
|
||||
|
||||
// TODO: these functions need to be moved from librtc to ESP-IDF
|
||||
extern void rtc_init_lite();
|
||||
extern void rtc_set_cpu_freq(xtal_freq_t xtal_freq, cpu_freq_t cpu_freq);
|
||||
|
||||
/*
|
||||
* This function is not exposed as an API at this point,
|
||||
* because FreeRTOS doesn't yet support dynamic changing of
|
||||
* CPU frequency. Also we need to implement hooks for
|
||||
* components which want to be notified of CPU frequency
|
||||
* changes.
|
||||
*/
|
||||
void esp_set_cpu_freq(void)
|
||||
{
|
||||
uint32_t freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
|
||||
phy_get_romfunc_addr();
|
||||
|
||||
// freq will be changed to 40MHz in rtc_init_lite,
|
||||
// wait uart tx finish, otherwise some uart output will be lost
|
||||
uart_tx_wait_idle(0);
|
||||
|
||||
rtc_init_lite();
|
||||
cpu_freq_t freq = CPU_80M;
|
||||
switch(freq_mhz) {
|
||||
case 240:
|
||||
freq = CPU_240M;
|
||||
break;
|
||||
case 160:
|
||||
freq = CPU_160M;
|
||||
break;
|
||||
default:
|
||||
freq_mhz = 80;
|
||||
/* no break */
|
||||
case 80:
|
||||
freq = CPU_80M;
|
||||
break;
|
||||
}
|
||||
|
||||
// freq will be changed to freq in rtc_set_cpu_freq,
|
||||
// wait uart tx finish, otherwise some uart output will be lost
|
||||
uart_tx_wait_idle(0);
|
||||
|
||||
rtc_set_cpu_freq(XTAL_AUTO, freq);
|
||||
ets_update_cpu_frequency(freq_mhz);
|
||||
}
|
||||
|
||||
+98
-158
@@ -20,8 +20,10 @@
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/uart.h"
|
||||
|
||||
#include "soc/cpu.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
@@ -39,194 +41,132 @@
|
||||
#include "esp_event.h"
|
||||
#include "esp_spi_flash.h"
|
||||
#include "esp_ipc.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static void IRAM_ATTR user_start_cpu0(void);
|
||||
static void IRAM_ATTR call_user_start_cpu1();
|
||||
static void IRAM_ATTR user_start_cpu1(void);
|
||||
void Cache_Read_Enable();
|
||||
extern void ets_setup_syscalls(void);
|
||||
extern esp_err_t app_main(void *ctx);
|
||||
|
||||
|
||||
extern int __cpu1_entry_point;
|
||||
extern int _bss_start;
|
||||
extern int _bss_end;
|
||||
extern int _init_start;
|
||||
extern int _init_end;
|
||||
extern int _iram_romjumptable_start;
|
||||
extern int _iram_romjumptable_end;
|
||||
extern int _iram_text_start;
|
||||
extern int _iram_text_end;
|
||||
|
||||
/*
|
||||
We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized,
|
||||
flash cache is down and the app CPU is in reset. We do have a stack, so we can do the initialization in C.
|
||||
*/
|
||||
|
||||
static bool app_cpu_started = false;
|
||||
|
||||
void IRAM_ATTR call_user_start_cpu0() {
|
||||
//Kill wdt
|
||||
REG_CLR_BIT(0x3ff4808c, BIT(10)); //RTCCNTL+8C RTC_WDTCONFIG0 RTC_
|
||||
REG_CLR_BIT(0x6001f048, BIT(14)); //DR_REG_BB_BASE+48
|
||||
|
||||
//Move exception vectors to IRAM
|
||||
asm volatile (\
|
||||
"wsr %0, vecbase\n" \
|
||||
::"r"(&_init_start));
|
||||
|
||||
uartAttach();
|
||||
ets_install_uart_printf();
|
||||
|
||||
//Make page 0 access raise an exception
|
||||
//Also some other unused pages so we can catch weirdness
|
||||
//ToDo: this but nicer.
|
||||
asm volatile (\
|
||||
"movi a4,0x00000000\n" \
|
||||
"movi a5,0xf\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0x80000000\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0xa0000000\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0xc0000000\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0xe0000000\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0x20000000\n" \
|
||||
"movi a5,0x0\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0x40000000\n" \
|
||||
"movi a5,0x2\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"isync\n" \
|
||||
:::"a4","a5");
|
||||
|
||||
memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
|
||||
|
||||
//Initialize heap allocator
|
||||
heap_alloc_caps_init();
|
||||
|
||||
ets_printf("Pro cpu up.\n");
|
||||
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
ets_printf("Starting app cpu, entry point is %p\n", call_user_start_cpu1);
|
||||
|
||||
SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL);
|
||||
SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
|
||||
CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
|
||||
ets_set_appcpu_boot_addr((uint32_t)call_user_start_cpu1);
|
||||
|
||||
while (!app_cpu_started) {
|
||||
ets_delay_us(100);
|
||||
}
|
||||
#else
|
||||
CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
|
||||
#endif
|
||||
ets_printf("Pro cpu start user code\n");
|
||||
user_start_cpu0();
|
||||
}
|
||||
|
||||
|
||||
extern int _init_start;
|
||||
|
||||
void IRAM_ATTR call_user_start_cpu1() {
|
||||
asm volatile (\
|
||||
"wsr %0, vecbase\n" \
|
||||
::"r"(&_init_start));
|
||||
|
||||
//Make page 0 access raise an exception
|
||||
//Also some other unused pages so we can catch weirdness
|
||||
//ToDo: this but nicer.
|
||||
asm volatile (\
|
||||
"movi a4,0x00000000\n" \
|
||||
"movi a5,0xf\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0x80000000\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0xa0000000\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0xc0000000\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0xe0000000\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0x20000000\n" \
|
||||
"movi a5,0x0\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0x40000000\n" \
|
||||
"movi a5,0x2\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"isync\n" \
|
||||
:::"a4","a5");
|
||||
|
||||
ets_printf("App cpu up.\n");
|
||||
app_cpu_started = 1;
|
||||
user_start_cpu1();
|
||||
}
|
||||
|
||||
extern volatile int port_xSchedulerRunning[2];
|
||||
|
||||
void IRAM_ATTR user_start_cpu1(void) {
|
||||
// Wait for FreeRTOS initialization to finish on PRO CPU
|
||||
while (port_xSchedulerRunning[0] == 0) {
|
||||
;
|
||||
}
|
||||
ets_printf("Starting scheduler on APP CPU.\n");
|
||||
xPortStartScheduler();
|
||||
}
|
||||
|
||||
extern void (*__init_array_start)(void);
|
||||
extern void (*__init_array_end)(void);
|
||||
extern volatile int port_xSchedulerRunning[2];
|
||||
|
||||
static void do_global_ctors(void) {
|
||||
void (**p)(void);
|
||||
for(p = &__init_array_start; p != &__init_array_end; ++p)
|
||||
(*p)();
|
||||
static const char* TAG = "cpu_start";
|
||||
static bool app_cpu_started = false;
|
||||
|
||||
/*
|
||||
* We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized,
|
||||
* and the app CPU is in reset. We do have a stack, so we can do the initialization in C.
|
||||
*/
|
||||
|
||||
void IRAM_ATTR call_user_start_cpu0()
|
||||
{
|
||||
//Kill wdt
|
||||
REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
|
||||
REG_CLR_BIT(0x6001f048, BIT(14)); //DR_REG_BB_BASE+48
|
||||
|
||||
cpu_configure_region_protection();
|
||||
|
||||
//Move exception vectors to IRAM
|
||||
asm volatile (\
|
||||
"wsr %0, vecbase\n" \
|
||||
::"r"(&_init_start));
|
||||
|
||||
uartAttach();
|
||||
ets_install_uart_printf();
|
||||
|
||||
memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
|
||||
|
||||
// Initialize heap allocator
|
||||
heap_alloc_caps_init();
|
||||
|
||||
ESP_EARLY_LOGI(TAG, "Pro cpu up.");
|
||||
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_user_start_cpu1);
|
||||
|
||||
SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL);
|
||||
SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
|
||||
CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
|
||||
ets_set_appcpu_boot_addr((uint32_t)call_user_start_cpu1);
|
||||
|
||||
while (!app_cpu_started) {
|
||||
ets_delay_us(100);
|
||||
}
|
||||
#else
|
||||
ESP_EARLY_LOGI(TAG, "Single core mode");
|
||||
CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
|
||||
#endif
|
||||
ESP_EARLY_LOGI(TAG, "Pro cpu start user code");
|
||||
user_start_cpu0();
|
||||
}
|
||||
|
||||
extern esp_err_t app_main(void *ctx);
|
||||
|
||||
void user_start_cpu0(void) {
|
||||
ets_setup_syscalls();
|
||||
do_global_ctors();
|
||||
esp_ipc_init();
|
||||
spi_flash_init();
|
||||
void IRAM_ATTR call_user_start_cpu1()
|
||||
{
|
||||
asm volatile (\
|
||||
"wsr %0, vecbase\n" \
|
||||
::"r"(&_init_start));
|
||||
|
||||
cpu_configure_region_protection();
|
||||
|
||||
ESP_EARLY_LOGI(TAG, "App cpu up.");
|
||||
app_cpu_started = 1;
|
||||
user_start_cpu1();
|
||||
}
|
||||
|
||||
void IRAM_ATTR user_start_cpu1(void)
|
||||
{
|
||||
// Wait for FreeRTOS initialization to finish on PRO CPU
|
||||
while (port_xSchedulerRunning[0] == 0) {
|
||||
;
|
||||
}
|
||||
ESP_LOGI(TAG, "Starting scheduler on APP CPU.");
|
||||
xPortStartScheduler();
|
||||
}
|
||||
|
||||
static void do_global_ctors(void)
|
||||
{
|
||||
void (**p)(void);
|
||||
for (p = &__init_array_start; p != &__init_array_end; ++p) {
|
||||
(*p)();
|
||||
}
|
||||
}
|
||||
|
||||
void user_start_cpu0(void)
|
||||
{
|
||||
esp_set_cpu_freq(); // set CPU frequency configured in menuconfig
|
||||
uart_div_modify(0, (APB_CLK_FREQ << 4) / 115200);
|
||||
ets_setup_syscalls();
|
||||
do_global_ctors();
|
||||
esp_ipc_init();
|
||||
spi_flash_init();
|
||||
|
||||
#if CONFIG_WIFI_ENABLED
|
||||
esp_err_t ret = nvs_flash_init(5, 3);
|
||||
if (ret != ESP_OK) {
|
||||
printf("nvs_flash_init failed, ret=%d\n", ret);
|
||||
ESP_LOGE(TAG, "nvs_flash_init failed, ret=%d", ret);
|
||||
}
|
||||
|
||||
system_init();
|
||||
|
||||
esp_event_init(NULL, NULL);
|
||||
|
||||
tcpip_adapter_init();
|
||||
#endif
|
||||
|
||||
#if CONFIG_WIFI_ENABLED && CONFIG_WIFI_AUTO_STARTUP
|
||||
#include "esp_wifi.h"
|
||||
esp_wifi_startup(app_main, NULL);
|
||||
esp_wifi_startup(app_main, NULL);
|
||||
#else
|
||||
app_main(NULL);
|
||||
app_main(NULL);
|
||||
#endif
|
||||
|
||||
ets_printf("Starting scheduler on PRO CPU.\n");
|
||||
vTaskStartScheduler();
|
||||
ESP_LOGI(TAG, "Starting scheduler on PRO CPU.");
|
||||
vTaskStartScheduler();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
|
||||
#include "heap_alloc_caps.h"
|
||||
#include "spiram.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char* TAG = "heap_alloc_caps";
|
||||
|
||||
/*
|
||||
This file, combined with a region allocator that supports tags, solves the problem that the ESP32 has RAM that's
|
||||
@@ -147,7 +150,7 @@ static void disable_mem_region(void *from, void *to) {
|
||||
regions[i].xSizeInBytes-=(uint8_t *)regEnd-(uint8_t *)from;
|
||||
} else if (regStart<from && regEnd>to) {
|
||||
//Range punches a hole in the region! We do not support this.
|
||||
ets_printf("%s: region %d: hole punching is not supported!\n", i);
|
||||
ESP_EARLY_LOGE(TAG, "region %d: hole punching is not supported!", i);
|
||||
regions[i].xTag=-1; //Just disable memory region. That'll teach them!
|
||||
}
|
||||
}
|
||||
@@ -204,12 +207,13 @@ void heap_alloc_caps_init() {
|
||||
}
|
||||
}
|
||||
|
||||
#if 1 //Change to 1 to show the regions the heap allocator is initialized with.
|
||||
ets_printf("Initializing heap allocator:\n");
|
||||
ESP_EARLY_LOGI(TAG, "Initializing heap allocator:");
|
||||
for (i=0; regions[i].xSizeInBytes!=0; i++) {
|
||||
if ( regions[i].xTag != -1 ) ets_printf("Region %02d: %08X len %08X tag %d\n", i, (int)regions[i].pucStartAddress, regions[i].xSizeInBytes, regions[i].xTag);
|
||||
if (regions[i].xTag != -1) {
|
||||
ESP_EARLY_LOGI(TAG, "Region %02d: %08X len %08X tag %d", i,
|
||||
(int)regions[i].pucStartAddress, regions[i].xSizeInBytes, regions[i].xTag);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//Initialize the malloc implementation.
|
||||
vPortDefineHeapRegionsTagged( regions );
|
||||
}
|
||||
|
||||
@@ -33,4 +33,49 @@ static inline bool cpu_in_interrupt_context(void)
|
||||
return (ps & PS_UM) == 0;
|
||||
}
|
||||
|
||||
/* Functions to set page attributes for Region Protection option in the CPU.
|
||||
* See Xtensa ISA Reference manual for explanation of arguments (section 4.6.3.2).
|
||||
*/
|
||||
|
||||
static inline void cpu_write_dtlb(uint32_t vpn, unsigned attr)
|
||||
{
|
||||
asm volatile ("wdtlb %1, %0; dsync\n" :: "r" (vpn), "r" (attr));
|
||||
}
|
||||
|
||||
|
||||
static inline void cpu_write_itlb(unsigned vpn, unsigned attr)
|
||||
{
|
||||
asm volatile ("witlb %1, %0; isync\n" :: "r" (vpn), "r" (attr));
|
||||
}
|
||||
|
||||
/* Make page 0 access raise an exception.
|
||||
* Also protect some other unused pages so we can catch weirdness.
|
||||
* Useful attribute values:
|
||||
* 0 — cached, RW
|
||||
* 2 — bypass cache, RWX (default value after CPU reset)
|
||||
* 15 — no access, raise exception
|
||||
*/
|
||||
|
||||
static inline void cpu_configure_region_protection()
|
||||
{
|
||||
const uint32_t pages_to_protect[] = {0x00000000, 0x80000000, 0xa0000000, 0xc0000000, 0xe0000000};
|
||||
for (int i = 0; i < sizeof(pages_to_protect)/sizeof(pages_to_protect[0]); ++i) {
|
||||
cpu_write_dtlb(pages_to_protect[i], 0xf);
|
||||
cpu_write_itlb(pages_to_protect[i], 0xf);
|
||||
}
|
||||
cpu_write_dtlb(0x20000000, 0);
|
||||
cpu_write_itlb(0x20000000, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* @brief Set CPU frequency to the value defined in menuconfig
|
||||
*
|
||||
* Called from cpu_start.c, not intended to be called from other places.
|
||||
* This is a temporary function which will be replaced once dynamic
|
||||
* CPU frequency changing is implemented.
|
||||
*/
|
||||
void esp_set_cpu_freq(void);
|
||||
|
||||
#endif
|
||||
|
||||
+1
-1
Submodule components/esp32/lib updated: 1303c92c10...9f26b9a190
@@ -367,6 +367,23 @@ void IRAM_ATTR _lock_release_recursive(_lock_t *lock) {
|
||||
lock_release_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
// This function is not part on newlib API, it is defined in libc/stdio/local.h
|
||||
// It is called as part of _reclaim_reent via a pointer in __cleanup member
|
||||
// of struct _reent.
|
||||
// This function doesn't call _fclose_r for _stdin, _stdout, _stderr members
|
||||
// of struct reent. Not doing so causes a memory leak each time a task is
|
||||
// terminated. We replace __cleanup member with _extra_cleanup_r (below) to work
|
||||
// around this.
|
||||
extern void _cleanup_r(struct _reent* r);
|
||||
|
||||
void _extra_cleanup_r(struct _reent* r)
|
||||
{
|
||||
_cleanup_r(r);
|
||||
_fclose_r(r, r->_stdout);
|
||||
_fclose_r(r, r->_stderr);
|
||||
_fclose_r(r, r->_stdin);
|
||||
}
|
||||
|
||||
static struct _reent s_reent;
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user