examples: Add example for fastest startup time

Example includes README and sdkconfig.defaults with notes about trade-offs
made for minimum boot time.
This commit is contained in:
Angus Gratton 2021-03-11 21:17:48 +11:00
parent 29348270e7
commit cdef1ea38a
13 changed files with 176 additions and 0 deletions

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(startup_time)

View File

@ -0,0 +1,8 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := startup_time
include $(IDF_PATH)/make/project.mk

View File

@ -0,0 +1,63 @@
# Startup Time Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates the configuration settings to obtain the minimum possible startup time for an ESP-IDF application (i.e. time from initial reset until the `app_main()` function is running).
Note that some of the configuration settings in `sdkconfig.defaults` have trade-offs that may not be suitable for your project, see the "Applying To Your Own Project" section at the bottom for more details.
## How to use example
### Hardware Required
This example should be able to run on any commonly available ESP32 development board.
### Configure the project
This step is optional, the default settings in `sdkconfig.defaults` are already set to minimize startup time.
```
idf.py menuconfig
```
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(Replace PORT with the name of the serial port to use.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
The example should have log output similar to the following:
```
W (34) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (37) example: App started!
```
All early log output is disabled in order to save time (it's also possible to disable the ROM log output immediately after reset, see below.)
Note that boot time reported in the log timestamp may vary depending on the chip target, chip revision, and eFuse configuration.
## Applying To Your Own Project
The file `sdkconfig.defaults` contains a range of setting which can be applied to any project in order for it to boot more rapidly.
However, note that some of these settings may have tradeoffs - for example not all hardware may support all flash modes and speeds, some applications would prefer the reliability of checking the application on every boot rather than waiting for a crash and then checking the application, and some applications will use features such as Secure Boot which require additional overhead on boot.
The `sdkconfig.defaults` file in this directory contains comments above each of the settings to optimize boot speed. To add the settings
to your own project, either search for the setting name in `menuconfig` or exit `menuconfig` and then copy-paste the setting lines at the end of your project's `sdkconfig` file.
## Additional Startup Speed
Removing the default boot log output printed by the ROM can shave several milliseconds off the SoC boot time. The default configuration doesn't make this change, as it is done via eFuse the change is permanent.
If you wish to make this change run `idf.py menuconfig`, navigate to "Boot ROM Behavior" and set the "Permanently change Boot ROM output" option.

View File

@ -0,0 +1,30 @@
from __future__ import print_function
import re
import ttfw_idf
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32', 'esp32s2', 'esp32c3'])
def test_startup_time_example(env, extra_data):
app_name = 'startup_time'
dut = env.get_dut(app_name, 'examples/system/startup_time')
dut.start_app()
res = dut.expect(re.compile(r'\((\d+)\) [^:]+: App started!'))
time = int(res[0])
# Allow ci-dashboard to track startup times
print('------ startup time info ------\n'
'[app_name] {}\n'
'[startup_time] {}\n'
'[config] {}\n'
'[target] {}\n'
'------ startup time end ------'.format(app_name,
time,
dut.app.config_name,
dut.TARGET))
if __name__ == '__main__':
test_startup_time_example()

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "hello_world_main.c"
INCLUDE_DIRS "")

View File

@ -0,0 +1,4 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@ -0,0 +1,23 @@
/* Startup time example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "esp_log.h"
static const char *TAG = "example";
/* The purpose of this app is to demonstrate fast startup time only, so feel free
to replace this app_main() with your own code or copy the sdkconfig.defaults contents
into a different project's sdkconfig file.
*/
void app_main(void)
{
// Calling this function restores all Info-level logging at runtime (as "Log Maximum Verbosity" set to "Info")
esp_log_level_set("*", ESP_LOG_INFO);
ESP_LOGI(TAG, "App started!");
}

View File

@ -0,0 +1,19 @@
# Set flash configuration as fast as possible (Quad I/O 80MHz)
#
# (Not all hardware may support this configuration.)
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
# These two settings mean that no logs are printed
# during startup, but it's possible to use esp_log_level_set("*", ESP_LOG_INFO)
# at runtime to get Info-level logging back
CONFIG_LOG_DEFAULT_LEVEL_WARN=y
CONFIG_LOG_MAXIMUM_LEVEL_INFO=y
CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
# at risk of not detecting flash corruption, skip bootloader
# verification of the app unless a soft reset or crash happened
#
# note: the larger the application, the bigger the time saved by
# from this option
CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON=y

View File

@ -0,0 +1,5 @@
# Not calibrating RTC_SLOW_CLK saves a small amount of time during boot.
#
# Setting option to zero is only recommended if not using sleep modes, or
# if you don't need accurate sleep times.
CONFIG_ESP32_RTC_CLK_CAL_CYCLES=0

View File

@ -0,0 +1,5 @@
# Not calibrating RTC_SLOW_CLK saves a small amount of time during boot.
#
# Setting option to zero is only recommended if not using sleep modes, or
# if you don't need accurate sleep times.
CONFIG_ESP32C3_RTC_CLK_CAL_CYCLES=0

View File

@ -0,0 +1,5 @@
# Not calibrating RTC_SLOW_CLK saves a small amount of time during boot.
#
# Setting option to zero is only recommended if not using sleep modes, or
# if you don't need accurate sleep times.
CONFIG_ESP32S2_RTC_CLK_CAL_CYCLES=0

View File

@ -0,0 +1,5 @@
# Not calibrating RTC_SLOW_CLK saves a small amount of time during boot.
#
# Setting option to zero is only recommended if not using sleep modes, or
# if you don't need accurate sleep times.
CONFIG_ESP32S3_RTC_CLK_CAL_CYCLES=0

View File

@ -145,6 +145,7 @@ examples/system/ota/otatool/otatool_example.py
examples/system/ota/simple_ota_example/example_test.py
examples/system/perfmon/example_test.py
examples/system/select/example_test.py
examples/system/startup_time/example_test.py
examples/system/sysview_tracing/example_test.py
examples/system/sysview_tracing_heap_log/example_test.py
examples/system/task_watchdog/example_test.py