Compare commits

..

71 Commits

Author SHA1 Message Date
Angus Gratton
f44dcf4878 Merge branch 'bugfix/macros_trailing_semicolon' into 'master'
Remove trialing semicolon from function-like macros

See merge request idf/esp-idf!4397
2019-03-13 13:15:12 +08:00
Angus Gratton
e18c7cb98d Merge branch 'bugfix/mdns_incorrect_semaphore_use' into 'master'
mdns: use binary semaphore instead of mutex when searching

See merge request idf/esp-idf!4464
2019-03-13 13:11:45 +08:00
Angus Gratton
8120efc6ed Merge branch 'bugfix/modify_dhcpserver_and_tcpip_adapter' into 'master'
modify the behavior for dhcpserver and tcpip_adapter

Closes IDFGH-557 and IDFGH-563

See merge request idf/esp-idf!4453
2019-03-13 12:54:55 +08:00
Angus Gratton
76fd26c9fb Merge branch 'bugfix/build_fails_when_editor_assoc_with_py_scripts' into 'master'
Fix issues with CMake builds when python scripts are associated with an editor

See merge request idf/esp-idf!4459
2019-03-13 07:47:27 +08:00
Angus Gratton
b6ddebb861 Merge branch 'bugfix/blink-increase-task-size' into 'master'
examples: Increase task size for blink demo

See merge request idf/esp-idf!4342
2019-03-13 07:44:48 +08:00
Renz Christian Bagaporo
5fb1c1ad3e ci: test full build never runs '/usr/bin/env python' or similar 2019-03-12 17:26:54 +08:00
Ivan Grokhotkov
eef0b5090a mdns: use binary semaphore instead of mutex when searching
mdns_search_once_t::lock is used to synchronize tasks (taken by one
task and given by the other) so it should not be a mutex.
Convert to semaphore, and rename to indicate its purpose.
2019-03-12 09:33:06 +01:00
Renz Christian Bagaporo
d0b2d5ec95 cmake: Fix for Python files executed directly, not via PYTHON variable
A problem if the Python interpreter used for idf.py (or set via PYTHON
variable) didn't match
"/usr/bin/env python" (or the associated executable for .py files, on
Windows).

Closes https://github.com/espressif/esp-idf/issues/3160
Possibly also fix for https://github.com/espressif/esp-idf/issues/2936

Adds build system test to catch any future direct execution of Python in
the standard build process.
2019-03-12 13:31:44 +08:00
Angus Gratton
86c9b63546 Merge branch 'feature/sync_issues_to_jira' into 'master'
github: Add workflow file to sync issues to JIRA

See merge request idf/esp-idf!4443
2019-03-12 06:31:48 +08:00
Angus Gratton
2f83aea8f3 Merge branch 'bugfix/freemodbus_remove_critical_section' into 'master'
freemodbus: Fix remove critical_sections

See merge request idf/esp-idf!4289
2019-03-12 06:30:50 +08:00
Ivan Grokhotkov
fc4823c885 Merge branch 'bugfix/coredump_improvements_refactoring_delete_include' into 'master'
esp32: coredump refactoring fix bug (remove duplicated include)

See merge request idf/esp-idf!4328
2019-03-11 19:00:39 +08:00
Angus Gratton
79ca95ddf6 Merge branch 'doc/jtag_debug_zh_CN' into 'master'
zh_CN translation of JTAG debugging

See merge request idf/esp-idf!3709
2019-03-11 16:35:04 +08:00
Angus Gratton
9679be19c5 Merge branch 'bugfix/efuse_virtual_mode' into 'master'
efuse: When Virtual eFuses are enabled, seed the virtual values as part of startup code

Closes WIFI-338

See merge request idf/esp-idf!4454
2019-03-11 16:33:32 +08:00
Angus Gratton
048b405296 Merge branch 'bugfix/doc_ubuntu_packages' into 'master'
docs: Update package dependencies

Closes IDFGH-360

See merge request idf/esp-idf!4406
2019-03-11 15:53:57 +08:00
Angus Gratton
de7daa14a9 Merge branch 'bugfix/msys_cancel_idfpy' into 'master'
tools: re-run idf.py in MSYS with winpty

Closes #67

See merge request idf/esp-idf!4341
2019-03-11 12:27:36 +08:00
Angus Gratton
af1ea9b1b9 efuse: When Virtual eFuses are enabled, seed the virtual values as part of startup code 2019-03-11 15:20:40 +11:00
zhangyanjiao
27cc0d1f91 modify the behavior for dhcpserver and tcpip_adapter:
1. dhcp_server: suppress send_offer debug output
2. tcpip_adapter: zero-initialize system_event_t structures
3. tcpip_adapter: pass client IP address along with SYSTEM_EVENT_AP_STAIPASSIGNED

Closes https://github.com/espressif/esp-idf/issues/2924
Closes https://github.com/espressif/esp-idf/issues/2949
2019-03-11 12:11:05 +08:00
He Yin Ling
f42ae05d1e Merge branch 'test/fix_unit_test_job_pass_even_no_test_executed' into 'master'
test: fix CI UT job pass even ut app bootup fail

See merge request idf/esp-idf!4208
2019-03-11 10:19:15 +08:00
He Yin Ling
8f3fe52b5a test: temp disable spi master slave mode test 2019-03-10 06:21:37 +00:00
He Yin Ling
1a9f019d2a unit-test-app: increase factory partition size 2019-03-10 06:21:37 +00:00
He Yin Ling
323a790f01 test: fix CI UT job pass even ut app bootup fail 2019-03-10 06:21:37 +00:00
Jiang Jiang Jian
09e72776dc Merge branch 'bugfix/autoip_memoey_leak_debug' into 'master'
fix the bug in auto Ip memory leak

See merge request idf/esp-idf!4395
2019-03-08 19:54:25 +08:00
aleks
13e1c0b32f esp32: coredump header (fix linker.lf)
remove duplicated include from components/esp32/incliude/esp_core_dump.h
espcoredump/incliude/esp_core_dump.h:
fix signature of the functions esp_core_dump_to_uart() and esp_core_dump_to_uart();
add espcoredump into COMPONENT_PRIV_REQUIRES list
fix linker.lf file
2019-03-08 09:49:37 +00:00
Angus Gratton
d0e3564603 github: Add workflow file to sync issues to JIRA 2019-03-08 18:39:30 +11:00
Angus Gratton
bba89e1514 Merge branch 'bugfix/console_join_example' into 'master'
console: fix wrong timeout settiing in join command

Closes IDF-168

See merge request idf/esp-idf!4366
2019-03-08 12:02:57 +08:00
Angus Gratton
3a410d6a3d Merge branch 'bugfix/httpd_sess_ctx' into 'master'
esp_http_server: Provide apps an option to let http_server ignore sess_ctx changes

See merge request idf/esp-idf!4417
2019-03-08 06:55:44 +08:00
Roland Dobai
ef250ced1b tools: re-run idf.py in MSYS with winpty
This is done in order to cancel subprocesses on keyboard interrupt
(CTRL+C).
2019-03-07 14:47:19 +01:00
Roland Dobai
f0194f2a5e docs: Update package dependencies
Closes https://github.com/espressif/esp-idf/issues/2384
2019-03-07 14:46:59 +01:00
aleks
aaa1cb6eec freemodbus: change critical sections to semaphore mutex
revert changes made in mbrtu.c, mbascii.c
change critical section type to semaphore mutex instead of spin lock

Closes: https://github.com/espressif/esp-idf/issues/3009
2019-03-07 09:59:40 +01:00
Konstantin Kondrashov
1ef7d093e1 freemodbus: Fix remove critical_sections
Closes: https://github.com/espressif/esp-idf/issues/3009
2019-03-07 08:00:45 +00:00
Ivan Grokhotkov
5f3bd38d3d Merge branch 'bugfix/cmakeSpaceProcessForCOMPONENT_SRCS' into 'master'
add spaces2list for COMPONENT_SRCS

See merge request idf/esp-idf!4427
2019-03-07 15:11:51 +08:00
Anton Maklakov
5156645348 Merge branch 'bugfix/ci_submodule_paths' into 'master'
CI - Fix the parsing of submodule paths

See merge request idf/esp-idf!4429
2019-03-07 13:58:04 +08:00
morris
9297b07a97 cmake: add spaces2list for COMPONENT_SRCS
According to ESP-IDF Cmake build system document, COMPONENT_SRCS should support using spaces to sperate source files.

Closes https://github.com/espressif/esp-idf/issues/3130
2019-03-06 20:55:38 +08:00
Anton Maklakov
88ec05cba2 ci: Fix the parsing of submodule paths 2019-03-06 19:37:34 +08:00
morris
378f8f72f0 console: fix wrong timeout settiing in join command
1. Fix wrong timeout setting in join command, also alter the default timeout value to 10 seconds
2. Don't clear the CONNECTED_BIT when connected to AP.
2019-03-06 18:25:10 +08:00
Ivan Grokhotkov
ea0a1c3030 Merge branch 'bugfix/docs_PROJECT_VER' into 'master'
Updated documentation concerning 'PROJECT_VER' and 'PROJECT_NAME'.

See merge request idf/esp-idf!4410
2019-03-06 17:29:10 +08:00
xiehang
b88b9f4e03 fix the bug in auto Ip memory leak
Closes https://jira.espressif.com:8443/browse/WIFI-266
2019-03-06 14:44:06 +08:00
Jiang Jiang Jian
c1e50c8a27 Merge branch 'bugfix/btdm_fix_iOS_and_win10_compatibility_error_for_HID' into 'master'
Component/bt: fix iOS and win10 compatibility error  for HID

See merge request idf/esp-idf!4396
2019-03-06 14:11:38 +08:00
Ivan Grokhotkov
42c906140e Merge branch 'bugfix/level5_intr_alloc' into 'master'
esp32: esp_intr_alloc: Fixed issue with level 5 not being called

Closes IDFGH-616

See merge request idf/esp-idf!4405
2019-03-06 11:18:36 +08:00
Ivan Grokhotkov
d474018725 Merge branch 'feature/gdbstub_task_list' into 'master'
Add support for listing tasks to gdb in gdbstub

Closes IDFGH-498

See merge request idf/esp-idf!4357
2019-03-06 11:12:46 +08:00
Ivan Grokhotkov
ff020c3a18 Merge branch 'docs/correct_typos_in_interrupt_handling_docs' into 'master'
docs: fix typo and link in high level interrupt documentation

See merge request idf/esp-idf!4419
2019-03-06 11:11:43 +08:00
krzychb
88b153fcf7 Fixed fancy quotes 2019-03-05 19:21:50 +01:00
krzychb
e243ee972d Updated documentation concerning 'PROJECT_VER' and 'PROJECT_NAME'.
Closes https://github.com/espressif/esp-idf/issues/3115.
2019-03-05 19:21:50 +01:00
Jiang Jiang Jian
0f927791be Merge branch 'bugfix/coex_decouple_wifi_and_bt_code_with_coexist' into 'master'
Decouple WiFi and BT with coexist to reduce bin size

Closes IDF-469

See merge request idf/esp-idf!4363
2019-03-05 15:14:16 +08:00
Ivan Grokhotkov
ddd08a6e13 Merge branch 'doc/add_build_system_cmake_translation' into 'master'
zh_CN translation of build system (cmake version)

See merge request idf/esp-idf!4122
2019-03-05 15:02:48 +08:00
Wang Fang
19939e5b60 zh_CN translation of build system (cmake version) 2019-03-05 15:02:48 +08:00
Angus Gratton
48d3a5804d Merge branch 'bugfix/simple_ota_example' into 'master'
bugfix(simple_ota_example): Compatible with V3.1 and V3.2,because the NVS format is different

See merge request idf/esp-idf!3983
2019-03-05 13:05:53 +08:00
Mahavir Jain
2a9d2d5be9 docs: fix typo and link in high level interrupt documentation 2019-03-05 10:27:35 +05:30
Ivan Grokhotkov
c22e572ad0 gdbstub: minor cleanup
1. Add Kconfig options to control task listing support.
2. Convert magic values (-1, -2) to named constants.
3. Convert spaces to tabs to match the rest of the file.
4. Rename getAllTasksHandle to getTaskInfo to reflect its purpose.
5. Add some curly braces for single line statements.
2019-03-05 12:11:45 +08:00
X-Ryl669
b797f05558 Add support for listing tasks to gdb in gdbstub
…and changing the active task and fetching each task's stack

Merges https://github.com/espressif/esp-idf/pull/2828
2019-03-05 12:00:22 +08:00
Angus Gratton
e053fdafc6 Merge branch 'doc/linker_script_generation_zh_CN' into 'master'
zh_CN translation of linker script generation

See merge request idf/esp-idf!4226
2019-03-05 11:02:31 +08:00
XiaXiaotian
b9b401ee39 Decouple WiFi and BT with coexist to reduce bin size
1. Do not link WiFi code when only BT or BLE is used and WiFi is not
used.

2. Do not link coexist code when CONFIG_SW_COEXIST_ENABLE is disabled.
2019-03-05 10:38:14 +08:00
Jiang Jiang Jian
bf2c46674d Merge branch 'bugfix/fix_some_wifi_bugs_0301' into 'master'
esp32: fix some WiFi bugs

See merge request idf/esp-idf!4399
2019-03-05 10:35:22 +08:00
Krzysztof Budzynski
89ae5908d6 Merge branch 'feature/upgrade_sphinx_and_breathe' into 'master'
docs: Preparation for upgrade of Sphinx and Breathe packages to versions 1.8.4 and 4.11.1. Updated check of Sphinx warnings to account for the filename instead of the whole path, that for the same errors may be different between English and Chinese docs.

See merge request idf/esp-idf!4282
2019-03-05 03:42:34 +08:00
Piyush Shah
f28f4016cb esp_http_server: Provide apps an option to let http_server ignore sess_ctx changes
By default, if a URI handler changes the http session context,
the webserver internally clears the older context after the handler
returns. However, if applications want to change this behavior and
manage the allocation/de-allocation/freeing themselves and let the
server handle only the "socket close" case, this commit provides such
an option.
2019-03-05 00:21:03 +05:30
Ivan Grokhotkov
dace2d6bc5 Merge branch 'bugfix/uart_fix_critical_section_api_from_isr' into 'master'
uart: use correct critical section API from ISR context

See merge request idf/esp-idf!4301
2019-03-04 16:24:22 +08:00
Ivan Grokhotkov
b3ee815ec1 Merge branch 'feature/esp_http_client_global_ca_store' into 'master'
esp_http_client: add support for using certs from global ca store

See merge request idf/esp-idf!4302
2019-03-04 16:24:07 +08:00
Christian Hoene
025deab4d2 esp32: esp_intr_alloc: Fixed issue with level 5 not being called
Closes https://github.com/espressif/esp-idf/issues/3039
Merges https://github.com/espressif/esp-idf/issues/3040
2019-03-01 17:11:51 +11:00
Liu Zhi Fu
2f547ca7c8 esp32: fix some WiFi bugs
Fix following WiFi bugs:
1. Fix the bug that STA incorrectly deletes BA when receiving DelBA request
2. Add out of memory check
3. Fix the bug that STA incorrectly receives packets when scanning in connected status
2019-03-01 11:25:36 +08:00
Jiang Jiang Jian
ebdcbe8c60 Merge branch 'doc/crc_apis_usage' into 'master'
Add CRC APIs usage

See merge request idf/esp-idf!4351
2019-03-01 10:03:03 +08:00
Darian Leung
59d1ecc78b esp32: Remove trialing semicolon from function-like macros
This commit removes trailing semicolons following a while(0) from
function-like macros in IDF. This will force those macros to be called
with a semicolon when called.
2019-02-28 21:58:47 +08:00
zhiweijian
d71df18d92 Component/bt: fix iOS and win10 compatibility error for HID 2019-02-28 20:39:12 +08:00
Anuj Deshpande
94594af13f examples: Move blink code to main task 2019-02-28 12:12:24 +05:30
krzychb
e1e8c36492 docs: Preparation for upgrade of Sphinx and Breathe packages to versions 1.8.4 and 4.11.1. Updated check of Sphinx warnings to account for the filename instead of the whole path, that for the same errors may be different between English and Chinese docs. 2019-02-27 22:11:59 +01:00
Mahavir Jain
27e00cf7aa esp_http_client: add support for using certs from global ca store
Closes https://github.com/espressif/esp-idf/issues/3062
2019-02-27 14:19:06 +05:30
Mahavir Jain
e9652e8ef3 uart: use correct critical section API (portENTER_CRITICAL_ISR) from ISR context 2019-02-27 08:36:47 +00:00
jack
299e4ca716 Add CRC APIs usage 2019-02-26 18:12:14 +08:00
morris
94e5fba46b doc: zh_CN translation of linker script generation
Translate linker-script-generation to zh_CN.
2019-02-26 10:22:30 +08:00
zhuying
5b938199ab doc(esp-idf) | JTAG debugging EN update 2019-01-30 11:34:04 +08:00
morris
7ffd0f95d2 doc/jtag_debug: translation of jtag debugging
translate JTAG Debugging to zh_CN
2019-01-30 11:34:04 +08:00
InfiniteYuan1
0fa31d3e31 bugfix(simple_ota): Compatible with V3.1 and V3.2 2018-12-18 14:41:12 +08:00
119 changed files with 4965 additions and 682 deletions

17
.github/main.workflow vendored Normal file
View File

@@ -0,0 +1,17 @@
workflow "Sync issues to JIRA" {
on = "issues"
resolves = ["Sync to JIRA"]
}
workflow "Sync issue comments to JIRA" {
on = "issue_comment"
resolves = ["Sync to JIRA"]
}
action "Sync to JIRA" {
uses = "espressif/github-actions/sync_issues_to_jira@master"
secrets = ["GITHUB_TOKEN", "JIRA_URL", "JIRA_USER", "JIRA_PASS"]
env = {
JIRA_PROJECT = "IDFGH"
}
}

View File

@@ -19,7 +19,7 @@ variables:
GET_SOURCES_ATTEMPTS: "10"
ARTIFACT_DOWNLOAD_ATTEMPTS: "10"
# We use get_sources.sh script to fetch the submodules and/or re-fetch the repo
# We use get-full-sources.sh script to fetch the submodules and/or re-fetch the repo
# if it was corrupted (if submodule update fails this can happen)
GIT_STRATEGY: fetch
GIT_SUBMODULE_STRATEGY: none
@@ -1299,6 +1299,12 @@ UT_001_42:
- ESP32_IDF
- UT_T1_1
UT_001_43:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
UT_002_01:
<<: *unit_test_template
tags:

View File

@@ -428,6 +428,13 @@ menu Bluetooth
help
This option can be close when the app not used the ble security connect.
config SMP_SLAVE_CON_PARAMS_UPD_ENABLE
bool "Slave enable connection parameters update during pairing"
depends on BLE_SMP_ENABLE
default n
help
In order to reduce the pairing time, slave actively initiates connection parameters update during pairing.
config BT_STACK_NO_LOG
bool "Disable BT debug logs (minimize bin size)"
depends on BLUEDROID_ENABLED

View File

@@ -133,6 +133,16 @@
#define BLE_PRIVACY_SPT FALSE
#endif /* CONFIG_SMP_ENABLE */
#ifdef CONFIG_SMP_SLAVE_CON_PARAMS_UPD_ENABLE
#if(CONFIG_SMP_SLAVE_CON_PARAMS_UPD_ENABLE)
#define SMP_SLAVE_CON_PARAMS_UPD_ENABLE TRUE
#else
#define SMP_SLAVE_CON_PARAMS_UPD_ENABLE FALSE
#endif
#else
#define SMP_SLAVE_CON_PARAMS_UPD_ENABLE FALSE
#endif
#if (CONFIG_BT_ACL_CONNECTIONS)
#define MAX_ACL_CONNECTIONS CONFIG_BT_ACL_CONNECTIONS
#define GATT_MAX_PHY_CHANNEL CONFIG_BT_ACL_CONNECTIONS

View File

@@ -1468,13 +1468,14 @@ tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, void *p_ref_data, UINT8 lin
break;
}
}
#if (SMP_SLAVE_CON_PARAMS_UPD_ENABLE == TRUE)
// already have encrypted information, do not need to update connection parameters
if(link_role == BTM_ROLE_SLAVE && (p_rec->ble.key_type & BTM_LE_KEY_PENC)) {
p_rec->ble.skip_update_conn_param = true;
} else {
p_rec->ble.skip_update_conn_param = false;
}
#endif
if (SMP_Pair(bd_addr) == SMP_STARTED) {
cmd = BTM_CMD_STARTED;
p_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;

View File

@@ -488,7 +488,9 @@ typedef struct {
#if SMP_INCLUDED == TRUE
tBTM_LE_KEY_TYPE key_type; /* bit mask of valid key types in record */
tBTM_SEC_BLE_KEYS keys; /* LE device security info in slave rode */
#if (SMP_SLAVE_CON_PARAMS_UPD_ENABLE == TRUE)
bool skip_update_conn_param; /* skip update connection paraams or not*/
#endif
UINT16 auth_mode; /* Authentication mode */
#endif
#if (BLE_PRIVACY_SPT == TRUE)

View File

@@ -1478,16 +1478,23 @@ void smp_idle_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
*******************************************************************************/
void smp_fast_conn_param(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
{
tBTM_SEC_DEV_REC *p_rec = btm_find_dev (p_cb->pairing_bda);
if(p_rec && p_rec->ble.skip_update_conn_param) {
//do nothing
return;
if(p_cb->role == BTM_ROLE_MASTER) {
L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, FALSE);
}
#if (SMP_SLAVE_CON_PARAMS_UPD_ENABLE == TRUE)
else {
tBTM_SEC_DEV_REC *p_rec = btm_find_dev (p_cb->pairing_bda);
if(p_rec && p_rec->ble.skip_update_conn_param) {
//do nothing
return;
}
/* Disable L2CAP connection parameter updates while bonding since
some peripherals are not able to revert to fast connection parameters
during the start of service discovery. Connection paramter updates
get enabled again once service discovery completes. */
L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, FALSE);
}
/* Disable L2CAP connection parameter updates while bonding since
some peripherals are not able to revert to fast connection parameters
during the start of service discovery. Connection paramter updates
get enabled again once service discovery completes. */
L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, FALSE);
#endif
}
/*******************************************************************************

View File

@@ -996,6 +996,7 @@ void smp_proc_pairing_cmpl(tSMP_CB *p_cb)
memcpy (pairing_bda, p_cb->pairing_bda, BD_ADDR_LEN);
#if (SMP_SLAVE_CON_PARAMS_UPD_ENABLE == TRUE)
if (p_cb->role == HCI_ROLE_SLAVE) {
if(p_rec && p_rec->ble.skip_update_conn_param) {
//clear flag
@@ -1004,6 +1005,7 @@ void smp_proc_pairing_cmpl(tSMP_CB *p_cb)
L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, TRUE);
}
}
#endif
smp_reset_control_value(p_cb);
if (p_callback) {

View File

@@ -43,6 +43,7 @@
#include "soc/rtc_cntl_reg.h"
#include "soc/soc_memory_layout.h"
#include "esp_clk.h"
#include "esp_coexist_internal.h"
#if CONFIG_BT_ENABLED
@@ -166,6 +167,11 @@ struct osi_funcs_t {
void (* _btdm_sleep_exit_phase1)(void); /* called from ISR */
void (* _btdm_sleep_exit_phase2)(void); /* called from ISR */
void (* _btdm_sleep_exit_phase3)(void); /* called from task */
int (* _coex_bt_request)(uint32_t event, uint32_t latency, uint32_t duration);
int (* _coex_bt_release)(uint32_t event);
int (* _coex_register_bt_cb)(coex_func_cb_t cb);
uint32_t (* _coex_bb_reset_lock)(void);
void (* _coex_bb_reset_unlock)(uint32_t restore);
uint32_t _magic;
};
@@ -205,6 +211,12 @@ extern int bredr_txpwr_set(int min_power_level, int max_power_level);
extern int bredr_txpwr_get(int *min_power_level, int *max_power_level);
extern void bredr_sco_datapath_set(uint8_t data_path);
extern void btdm_controller_scan_duplicate_list_clear(void);
/* Coexistence */
extern int coex_bt_request_wrapper(uint32_t event, uint32_t latency, uint32_t duration);
extern int coex_bt_release_wrapper(uint32_t event);
extern int coex_register_bt_cb_wrapper(coex_func_cb_t cb);
extern uint32_t coex_bb_reset_lock_wrapper(void);
extern void coex_bb_reset_unlock_wrapper(uint32_t restore);
extern char _bss_start_btdm;
extern char _bss_end_btdm;
@@ -311,6 +323,11 @@ static const struct osi_funcs_t osi_funcs_ro = {
._btdm_sleep_exit_phase1 = btdm_sleep_exit_phase1_wrapper,
._btdm_sleep_exit_phase2 = NULL,
._btdm_sleep_exit_phase3 = btdm_sleep_exit_phase3_wrapper,
._coex_bt_request = coex_bt_request_wrapper,
._coex_bt_release = coex_bt_release_wrapper,
._coex_register_bt_cb = coex_register_bt_cb_wrapper,
._coex_bb_reset_lock = coex_bb_reset_lock_wrapper,
._coex_bb_reset_unlock = coex_bb_reset_unlock_wrapper,
._magic = OSI_MAGIC_VALUE,
};

View File

@@ -465,9 +465,9 @@ static const ptest_func_t slave_test_func = {
.def_param = spitest_def_param,
};
#define TEST_SPI_MASTER_SLAVE(name, param_group) \
#define TEST_SPI_MASTER_SLAVE(name, param_group, extra_tag) \
PARAM_GROUP_DECLARE(name, param_group) \
TEST_MASTER_SLAVE(name, param_group, "[spi_ms][test_env=Example_SPI_Multi_device][timeout=120]", &master_test_func, &slave_test_func)
TEST_MASTER_SLAVE(name, param_group, "[spi_ms][test_env=Example_SPI_Multi_device][timeout=120]"#extra_tag, &master_test_func, &slave_test_func)
/************ Master Code ***********************************************/
static void test_master_init(void** arg)
@@ -789,7 +789,7 @@ static spitest_param_set_t timing_conf[] = {
.slave_tv_ns = TV_WITH_ESP_SLAVE_GPIO,
},
};
TEST_SPI_MASTER_SLAVE(TIMING, timing_conf)
TEST_SPI_MASTER_SLAVE(TIMING, timing_conf, "")
/************ Mode Test ***********************************************/
#define FREQ_LIMIT_MODE SPI_MASTER_FREQ_16M
@@ -976,4 +976,4 @@ spitest_param_set_t mode_conf[] = {
.slave_dma_chan = 1,
},
};
TEST_SPI_MASTER_SLAVE(MODE, mode_conf)
TEST_SPI_MASTER_SLAVE(MODE, mode_conf, "[ignore]")

View File

@@ -333,6 +333,21 @@ esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask)
return ESP_OK;
}
static void uart_disable_intr_mask_from_isr(uart_port_t uart_num, uint32_t disable_mask)
{
UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(uart_num), disable_mask);
UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
}
static void uart_enable_intr_mask_from_isr(uart_port_t uart_num, uint32_t enable_mask)
{
UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
SET_PERI_REG_MASK(UART_INT_CLR_REG(uart_num), enable_mask);
SET_PERI_REG_MASK(UART_INT_ENA_REG(uart_num), enable_mask);
UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
}
static esp_err_t uart_pattern_link_free(uart_port_t uart_num)
{
UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL);
@@ -730,7 +745,7 @@ static void uart_rx_intr_handler_default(void *param)
uart_event.type = UART_EVENT_MAX;
if(uart_intr_status & UART_TXFIFO_EMPTY_INT_ST_M) {
uart_clear_intr_status(uart_num, UART_TXFIFO_EMPTY_INT_CLR_M);
uart_disable_intr_mask(uart_num, UART_TXFIFO_EMPTY_INT_ENA_M);
uart_disable_intr_mask_from_isr(uart_num, UART_TXFIFO_EMPTY_INT_ENA_M);
if(p_uart->tx_waiting_brk) {
continue;
}
@@ -832,7 +847,7 @@ static void uart_rx_intr_handler_default(void *param)
}
if (en_tx_flg) {
uart_clear_intr_status(uart_num, UART_TXFIFO_EMPTY_INT_CLR_M);
uart_enable_intr_mask(uart_num, UART_TXFIFO_EMPTY_INT_ENA_M);
uart_enable_intr_mask_from_isr(uart_num, UART_TXFIFO_EMPTY_INT_ENA_M);
}
}
}
@@ -876,7 +891,7 @@ static void uart_rx_intr_handler_default(void *param)
//Mainly for applications that uses flow control or small ring buffer.
if(pdFALSE == xRingbufferSendFromISR(p_uart->rx_ring_buf, p_uart->rx_data_buf, p_uart->rx_stash_len, &HPTaskAwoken)) {
p_uart->rx_buffer_full_flg = true;
uart_disable_intr_mask(uart_num, UART_RXFIFO_TOUT_INT_ENA_M | UART_RXFIFO_FULL_INT_ENA_M);
uart_disable_intr_mask_from_isr(uart_num, UART_RXFIFO_TOUT_INT_ENA_M | UART_RXFIFO_FULL_INT_ENA_M);
if (uart_event.type == UART_PATTERN_DET) {
if (rx_fifo_len < pat_num) {
//some of the characters are read out in last interrupt
@@ -912,7 +927,7 @@ static void uart_rx_intr_handler_default(void *param)
portYIELD_FROM_ISR();
}
} else {
uart_disable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M);
uart_disable_intr_mask_from_isr(uart_num, UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M);
uart_clear_intr_status(uart_num, UART_RXFIFO_FULL_INT_CLR_M | UART_RXFIFO_TOUT_INT_CLR_M);
if(uart_intr_status & UART_AT_CMD_CHAR_DET_INT_ST_M) {
uart_reg->int_clr.at_cmd_char_det = 1;
@@ -971,7 +986,7 @@ static void uart_rx_intr_handler_default(void *param)
}
}
} else if(uart_intr_status & UART_TX_BRK_IDLE_DONE_INT_ST_M) {
uart_disable_intr_mask(uart_num, UART_TX_BRK_IDLE_DONE_INT_ENA_M);
uart_disable_intr_mask_from_isr(uart_num, UART_TX_BRK_IDLE_DONE_INT_ENA_M);
uart_clear_intr_status(uart_num, UART_TX_BRK_IDLE_DONE_INT_CLR_M);
} else if(uart_intr_status & UART_AT_CMD_CHAR_DET_INT_ST_M) {
uart_reg->int_clr.at_cmd_char_det = 1;
@@ -988,7 +1003,7 @@ static void uart_rx_intr_handler_default(void *param)
UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
uart_event.type = UART_EVENT_MAX;
} else if(uart_intr_status & UART_TX_DONE_INT_ST_M) {
uart_disable_intr_mask(uart_num, UART_TX_DONE_INT_ENA_M);
uart_disable_intr_mask_from_isr(uart_num, UART_TX_DONE_INT_ENA_M);
uart_clear_intr_status(uart_num, UART_TX_DONE_INT_CLR_M);
// If RS485 half duplex mode is enable then reset FIFO and
// reset RTS pin to start receiver driver

View File

@@ -32,6 +32,10 @@ static const char *TAG = "efuse";
// Array for emulate efuse registers.
#ifdef CONFIG_EFUSE_VIRTUAL
static uint32_t virt_blocks[COUNT_EFUSE_BLOCKS][COUNT_EFUSE_REG_PER_BLOCK];
/* Call the update function to seed virtual efuses during initialization */
__attribute__((constructor)) void esp_efuse_utility_update_virt_blocks();
#endif
/**
@@ -181,7 +185,7 @@ void esp_efuse_utility_reset(void)
void esp_efuse_utility_burn_efuses(void)
{
#ifdef CONFIG_EFUSE_VIRTUAL
ESP_LOGE(TAG, "Not really burning any efuses!");
ESP_LOGW(TAG, "Virtual efuses enabled: Not really burning eFuses");
for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) {
esp_efuse_coding_scheme_t scheme = esp_efuse_get_coding_scheme(num_block);
if (scheme == EFUSE_CODING_SCHEME_3_4) {
@@ -229,7 +233,7 @@ void esp_efuse_utility_erase_virt_blocks()
void esp_efuse_utility_update_virt_blocks()
{
#ifdef CONFIG_EFUSE_VIRTUAL
ESP_LOGI(TAG, "Emulate efuse is enabled");
ESP_LOGI(TAG, "Loading virtual efuse blocks from real efuses");
for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) {
int subblock = 0;
for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4) {

View File

@@ -19,6 +19,7 @@ else()
"dbg_stubs.c"
"dport_access.c"
"dport_panic_highint_hdl.S"
"esp_adapter.c"
"esp_err_to_name.c"
"esp_timer.c"
"esp_timer_esp32.c"
@@ -48,7 +49,6 @@ else()
"system_api.c"
"task_wdt.c"
"wifi_init.c"
"wifi_os_adapter.c"
"hwcrypto/aes.c"
"hwcrypto/sha.c")
set(COMPONENT_ADD_INCLUDEDIRS "include")
@@ -59,7 +59,7 @@ else()
# app_update is added here because cpu_start.c uses esp_ota_get_app_description() function.
set(COMPONENT_PRIV_REQUIRES
app_trace app_update bootloader_support ethernet log mbedtls nvs_flash
pthread smartconfig_ack spi_flash vfs wpa_supplicant xtensa-debug-module)
pthread smartconfig_ack spi_flash vfs wpa_supplicant xtensa-debug-module espcoredump)
set(COMPONENT_ADD_LDFRAGMENTS linker.lf ld/esp32_fragments.lf)

View File

@@ -544,6 +544,23 @@ menu "ESP32-specific"
of the crash.
endchoice
config GDBSTUB_SUPPORT_TASKS
bool "GDBStub: enable listing FreeRTOS tasks"
default y
depends on ESP32_PANIC_GDBSTUB
help
If enabled, GDBStub can supply the list of FreeRTOS tasks to GDB.
Thread list can be queried from GDB using 'info threads' command.
Note that if GDB task lists were corrupted, this feature may not work.
If GDBStub fails, try disabling this feature.
config GDBSTUB_MAX_TASKS
int "GDBStub: maximum number of tasks supported"
default 32
depends on GDBSTUB_SUPPORT_TASKS
help
Set the number of tasks which GDB Stub will support.
config ESP32_DEBUG_OCDAWARE
bool "Make exception and panic handlers JTAG/OCD aware"
default y
@@ -924,6 +941,8 @@ menu Wi-Fi
If enabled, WiFi & Bluetooth coexistence is controlled by software rather than hardware.
Recommended for heavy traffic scenarios. Both coexistence configuration options are
automatically managed, no user intervention is required.
If only Bluetooth is used, it is recommended to disable this option to reduce binary file
size.
choice SW_COEXIST_PREFERENCE
prompt "WiFi/Bluetooth coexistence performance preference"

View File

@@ -13,7 +13,7 @@
// limitations under the License.
#include "esp_coexist.h"
#include "coexist_internal.h"
#include "esp_coexist_internal.h"
const char *esp_coex_version_get(void)
{

View File

@@ -1,77 +0,0 @@
// Copyright 2018-2018 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.
#ifndef __COEXIST_INTERNAL_H__
#define __COEXIST_INTERNAL_H__
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
COEX_PREFER_WIFI = 0,
COEX_PREFER_BT,
COEX_PREFER_BALANCE,
COEX_PREFER_NUM,
} coex_prefer_t;
/**
* @brief Init software coexist
* extern function for internal use.
*
* @return Init ok or failed.
*/
esp_err_t coex_init(void);
/**
* @brief De-init software coexist
* extern function for internal use.
*/
void coex_deinit(void);
/**
* @brief Pause software coexist
* extern function for internal use.
*/
void coex_pause(void);
/**
* @brief Resume software coexist
* extern function for internal use.
*/
void coex_resume(void);
/**
* @brief Get software coexist version string
* extern function for internal use.
* @return : version string
*/
const char *coex_version_get(void);
/**
* @brief Coexist performance preference set from libbt.a
* extern function for internal use.
*
* @param prefer : the prefer enumeration value
* @return : ESP_OK - success, other - failed
*/
esp_err_t coex_preference_set(coex_prefer_t prefer);
#ifdef __cplusplus
}
#endif
#endif /* __COEXIST_INTERNAL_H__ */

View File

@@ -59,7 +59,7 @@
#include "esp_task_wdt.h"
#include "esp_phy_init.h"
#include "esp_cache_err_int.h"
#include "esp_coexist.h"
#include "esp_coexist_internal.h"
#include "esp_panic.h"
#include "esp_core_dump.h"
#include "esp_app_trace.h"
@@ -412,6 +412,10 @@ void start_cpu0_default(void)
}
#endif
#if CONFIG_SW_COEXIST_ENABLE
esp_coex_adapter_register(&g_coex_adapter_funcs);
#endif
portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main",
ESP_TASK_MAIN_STACK, NULL,
ESP_TASK_MAIN_PRIO, NULL, 0);

View File

@@ -46,6 +46,8 @@
#include "os.h"
#include "esp_smartconfig.h"
#include "smartconfig_ack.h"
#include "esp_coexist_internal.h"
#include "esp_coexist_adapter.h"
extern void esp_dport_access_stall_other_cpu_start_wrap(void);
@@ -100,38 +102,38 @@ static void * IRAM_ATTR wifi_zalloc_wrapper(size_t size)
}
wifi_static_queue_t* wifi_create_queue( int queue_len, int item_size)
{
{
wifi_static_queue_t *queue = NULL;
queue = (wifi_static_queue_t*)heap_caps_malloc(sizeof(wifi_static_queue_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
if (!queue) {
return NULL;
}
#if CONFIG_SPIRAM_USE_MALLOC
queue->storage = heap_caps_calloc(1, sizeof(StaticQueue_t) + (queue_len*item_size), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
if (!queue->storage) {
goto _error;
}
queue->handle = xQueueCreateStatic( queue_len, item_size, ((uint8_t*)(queue->storage)) + sizeof(StaticQueue_t), (StaticQueue_t*)(queue->storage));
if (!queue->handle) {
goto _error;
}
return queue;
_error:
if (queue) {
if (queue->storage) {
free(queue->storage);
}
free(queue);
}
return NULL;
#else
queue->handle = xQueueCreate( queue_len, item_size);
@@ -154,26 +156,26 @@ void wifi_delete_queue(wifi_static_queue_t *queue)
}
}
static void * IRAM_ATTR wifi_create_queue_wrapper(int queue_len, int item_size)
static void * wifi_create_queue_wrapper(int queue_len, int item_size)
{
return wifi_create_queue(queue_len, item_size);
}
static void IRAM_ATTR wifi_delete_queue_wrapper(void *queue)
static void wifi_delete_queue_wrapper(void *queue)
{
wifi_delete_queue(queue);
}
static void IRAM_ATTR set_isr_wrapper(int32_t n, void *f, void *arg)
static void set_isr_wrapper(int32_t n, void *f, void *arg)
{
xt_set_interrupt_handler(n, (xt_handler)f, arg);
}
static void * IRAM_ATTR spin_lock_create_wrapper(void)
static void * spin_lock_create_wrapper(void)
{
portMUX_TYPE tmp = portMUX_INITIALIZER_UNLOCKED;
void *mux = malloc(sizeof(portMUX_TYPE));
if (mux) {
memcpy(mux,&tmp,sizeof(portMUX_TYPE));
return mux;
@@ -184,10 +186,10 @@ static void * IRAM_ATTR spin_lock_create_wrapper(void)
static uint32_t IRAM_ATTR wifi_int_disable_wrapper(void *wifi_int_mux)
{
if (xPortInIsrContext()) {
portENTER_CRITICAL_ISR(wifi_int_mux);
} else {
portENTER_CRITICAL(wifi_int_mux);
}
portENTER_CRITICAL_ISR(wifi_int_mux);
} else {
portENTER_CRITICAL(wifi_int_mux);
}
return 0;
}
@@ -195,10 +197,10 @@ static uint32_t IRAM_ATTR wifi_int_disable_wrapper(void *wifi_int_mux)
static void IRAM_ATTR wifi_int_restore_wrapper(void *wifi_int_mux, uint32_t tmp)
{
if (xPortInIsrContext()) {
portEXIT_CRITICAL_ISR(wifi_int_mux);
} else {
portEXIT_CRITICAL(wifi_int_mux);
}
portEXIT_CRITICAL_ISR(wifi_int_mux);
} else {
portEXIT_CRITICAL(wifi_int_mux);
}
}
static void IRAM_ATTR task_yield_from_isr_wrapper(void)
@@ -206,12 +208,12 @@ static void IRAM_ATTR task_yield_from_isr_wrapper(void)
portYIELD_FROM_ISR();
}
static void *IRAM_ATTR semphr_create_wrapper(uint32_t max, uint32_t init)
static void * semphr_create_wrapper(uint32_t max, uint32_t init)
{
return (void *)xSemaphoreCreateCounting(max, init);
}
static void IRAM_ATTR semphr_delete_wrapper(void *semphr)
static void semphr_delete_wrapper(void *semphr)
{
vSemaphoreDelete(semphr);
}
@@ -226,7 +228,7 @@ static int32_t IRAM_ATTR semphr_give_from_isr_wrapper(void *semphr, void *hptw)
return (int32_t)xSemaphoreGiveFromISR(semphr, hptw);
}
static int32_t IRAM_ATTR semphr_take_wrapper(void *semphr, uint32_t block_time_tick)
static int32_t semphr_take_wrapper(void *semphr, uint32_t block_time_tick)
{
if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) {
return (int32_t)xSemaphoreTake(semphr, portMAX_DELAY);
@@ -235,22 +237,22 @@ static int32_t IRAM_ATTR semphr_take_wrapper(void *semphr, uint32_t block_time_t
}
}
static int32_t IRAM_ATTR semphr_give_wrapper(void *semphr)
static int32_t semphr_give_wrapper(void *semphr)
{
return (int32_t)xSemaphoreGive(semphr);
}
static void *IRAM_ATTR recursive_mutex_create_wrapper(void)
static void * recursive_mutex_create_wrapper(void)
{
return (void *)xSemaphoreCreateRecursiveMutex();
}
static void *IRAM_ATTR mutex_create_wrapper(void)
static void * mutex_create_wrapper(void)
{
return (void *)xSemaphoreCreateMutex();
}
static void IRAM_ATTR mutex_delete_wrapper(void *mutex)
static void mutex_delete_wrapper(void *mutex)
{
vSemaphoreDelete(mutex);
}
@@ -265,12 +267,12 @@ static int32_t IRAM_ATTR mutex_unlock_wrapper(void *mutex)
return (int32_t)xSemaphoreGiveRecursive(mutex);
}
static void *IRAM_ATTR queue_create_wrapper(uint32_t queue_len, uint32_t item_size)
static void * queue_create_wrapper(uint32_t queue_len, uint32_t item_size)
{
return (void *)xQueueCreate(queue_len, item_size);
}
static int32_t IRAM_ATTR queue_send_wrapper(void *queue, void *item, uint32_t block_time_tick)
static int32_t queue_send_wrapper(void *queue, void *item, uint32_t block_time_tick)
{
if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) {
return (int32_t)xQueueSend(queue, item, portMAX_DELAY);
@@ -284,17 +286,17 @@ static int32_t IRAM_ATTR queue_send_from_isr_wrapper(void *queue, void *item, vo
return (int32_t)xQueueSendFromISR(queue, item, hptw);
}
static int32_t IRAM_ATTR queue_send_to_back_wrapper(void *queue, void *item, uint32_t block_time_tick)
static int32_t queue_send_to_back_wrapper(void *queue, void *item, uint32_t block_time_tick)
{
return (int32_t)xQueueGenericSend(queue, item, block_time_tick, queueSEND_TO_BACK);
return (int32_t)xQueueGenericSend(queue, item, block_time_tick, queueSEND_TO_BACK);
}
static int32_t IRAM_ATTR queue_send_to_front_wrapper(void *queue, void *item, uint32_t block_time_tick)
static int32_t queue_send_to_front_wrapper(void *queue, void *item, uint32_t block_time_tick)
{
return (int32_t)xQueueGenericSend(queue, item, block_time_tick, queueSEND_TO_FRONT);
}
static int32_t IRAM_ATTR queue_recv_wrapper(void *queue, void *item, uint32_t block_time_tick)
static int32_t queue_recv_wrapper(void *queue, void *item, uint32_t block_time_tick)
{
if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) {
return (int32_t)xQueueReceive(queue, item, portMAX_DELAY);
@@ -303,7 +305,7 @@ static int32_t IRAM_ATTR queue_recv_wrapper(void *queue, void *item, uint32_t bl
}
}
static uint32_t IRAM_ATTR event_group_wait_bits_wrapper(void *event, uint32_t bits_to_wait_for, int clear_on_exit, int wait_for_all_bits, uint32_t block_time_tick)
static uint32_t event_group_wait_bits_wrapper(void *event, uint32_t bits_to_wait_for, int clear_on_exit, int wait_for_all_bits, uint32_t block_time_tick)
{
if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) {
return (uint32_t)xEventGroupWaitBits(event, bits_to_wait_for, clear_on_exit, wait_for_all_bits, portMAX_DELAY);
@@ -312,12 +314,12 @@ static uint32_t IRAM_ATTR event_group_wait_bits_wrapper(void *event, uint32_t bi
}
}
static int32_t IRAM_ATTR task_create_pinned_to_core_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id)
static int32_t task_create_pinned_to_core_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id)
{
return (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, (core_id < portNUM_PROCESSORS ? core_id : tskNO_AFFINITY));
}
static int32_t IRAM_ATTR task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle)
static int32_t task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle)
{
return (uint32_t)xTaskCreate(task_func, name, stack_depth, param, prio, task_handle);
}
@@ -328,16 +330,11 @@ static int32_t IRAM_ATTR task_ms_to_tick_wrapper(uint32_t ms)
}
static int32_t IRAM_ATTR task_get_max_priority_wrapper(void)
static int32_t task_get_max_priority_wrapper(void)
{
return (int32_t)(configMAX_PRIORITIES);
}
static int32_t IRAM_ATTR phy_rf_init_wrapper(const void* init_data, uint32_t mode, void* calibration_data, uint32_t module)
{
return esp_phy_rf_init( init_data, mode, calibration_data, module);
}
static void IRAM_ATTR timer_arm_wrapper(void *timer, uint32_t tmout, bool repeat)
{
ets_timer_arm(timer, tmout, repeat);
@@ -348,12 +345,12 @@ static void IRAM_ATTR timer_disarm_wrapper(void *timer)
ets_timer_disarm(timer);
}
static void IRAM_ATTR timer_done_wrapper(void *ptimer)
static void timer_done_wrapper(void *ptimer)
{
ets_timer_done(ptimer);
}
static void IRAM_ATTR timer_setfn_wrapper(void *ptimer, void *pfunction, void *parg)
static void timer_setfn_wrapper(void *ptimer, void *pfunction, void *parg)
{
ets_timer_setfn(ptimer, pfunction, parg);
}
@@ -363,7 +360,7 @@ static void IRAM_ATTR timer_arm_us_wrapper(void *ptimer, uint32_t us, bool repea
ets_timer_arm_us(ptimer, us, repeat);
}
static int IRAM_ATTR get_time_wrapper(void *t)
static int get_time_wrapper(void *t)
{
return os_get_time(t);
}
@@ -373,7 +370,7 @@ static void * IRAM_ATTR malloc_internal_wrapper(size_t size)
return heap_caps_malloc(size, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL);
}
static void * IRAM_ATTR realloc_internal_wrapper(void *ptr, size_t size)
static void * IRAM_ATTR realloc_internal_wrapper(void *ptr, size_t size)
{
return heap_caps_realloc(ptr, size, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL);
}
@@ -392,11 +389,81 @@ static void * IRAM_ATTR zalloc_internal_wrapper(size_t size)
return ptr;
}
static void IRAM_ATTR sc_ack_send_wrapper(void *param)
static void sc_ack_send_wrapper(void *param)
{
return sc_ack_send((sc_ack_t *)param);
}
static uint32_t coex_status_get_wrapper(void)
{
#if CONFIG_SW_COEXIST_ENABLE
return coex_status_get();
#else
return 0;
#endif
}
static int coex_wifi_request_wrapper(uint32_t event, uint32_t latency, uint32_t duration)
{
#if CONFIG_SW_COEXIST_ENABLE
return coex_wifi_request(event, latency, duration);
#else
return 0;
#endif
}
static int coex_wifi_release_wrapper(uint32_t event)
{
#if CONFIG_SW_COEXIST_ENABLE
return coex_wifi_release(event);
#else
return 0;
#endif
}
int IRAM_ATTR coex_bt_request_wrapper(uint32_t event, uint32_t latency, uint32_t duration)
{
#if CONFIG_SW_COEXIST_ENABLE
return coex_bt_request(event, latency, duration);
#else
return 0;
#endif
}
int IRAM_ATTR coex_bt_release_wrapper(uint32_t event)
{
#if CONFIG_SW_COEXIST_ENABLE
return coex_bt_release(event);
#else
return 0;
#endif
}
int coex_register_bt_cb_wrapper(coex_func_cb_t cb)
{
#if CONFIG_SW_COEXIST_ENABLE
return coex_register_bt_cb(cb);
#else
return 0;
#endif
}
uint32_t IRAM_ATTR coex_bb_reset_lock_wrapper(void)
{
#if CONFIG_SW_COEXIST_ENABLE
return coex_bb_reset_lock();
#else
return 0;
#endif
}
void IRAM_ATTR coex_bb_reset_unlock_wrapper(uint32_t restore)
{
#if CONFIG_SW_COEXIST_ENABLE
coex_bb_reset_unlock(restore);
#endif
}
wifi_osi_funcs_t g_wifi_osi_funcs = {
._version = ESP_WIFI_OS_ADAPTER_VERSION,
._set_isr = set_isr_wrapper,
@@ -406,12 +473,9 @@ wifi_osi_funcs_t g_wifi_osi_funcs = {
._spin_lock_delete = free,
._wifi_int_disable = wifi_int_disable_wrapper,
._wifi_int_restore = wifi_int_restore_wrapper,
._task_yield = vPortYield,
._task_yield_from_isr = task_yield_from_isr_wrapper,
._semphr_create = semphr_create_wrapper,
._semphr_delete = semphr_delete_wrapper,
._semphr_take_from_isr = semphr_take_from_isr_wrapper,
._semphr_give_from_isr = semphr_give_from_isr_wrapper,
._semphr_take = semphr_take_wrapper,
._semphr_give = semphr_give_wrapper,
._mutex_create = mutex_create_wrapper,
@@ -426,7 +490,6 @@ wifi_osi_funcs_t g_wifi_osi_funcs = {
._queue_send_to_back = queue_send_to_back_wrapper,
._queue_send_to_front = queue_send_to_front_wrapper,
._queue_recv = queue_recv_wrapper,
._queue_recv_from_isr = xQueueReceiveFromISR,
._queue_msg_waiting = uxQueueMessagesWaiting,
._event_group_create = xEventGroupCreate,
._event_group_delete = vEventGroupDelete,
@@ -440,19 +503,15 @@ wifi_osi_funcs_t g_wifi_osi_funcs = {
._task_ms_to_tick = task_ms_to_tick_wrapper,
._task_get_current_task = xTaskGetCurrentTaskHandle,
._task_get_max_priority = task_get_max_priority_wrapper,
._is_in_isr = xPortInIsrContext,
._malloc = malloc,
._free = free,
._get_free_heap_size = esp_get_free_heap_size,
._rand = esp_random,
._dport_access_stall_other_cpu_start_wrap = esp_dport_access_stall_other_cpu_start_wrap,
._dport_access_stall_other_cpu_end_wrap = esp_dport_access_stall_other_cpu_end_wrap,
._phy_rf_init = phy_rf_init_wrapper,
._phy_rf_deinit = esp_phy_rf_deinit,
._phy_load_cal_and_init = esp_phy_load_cal_and_init,
._read_mac = esp_read_mac,
._timer_init = ets_timer_init,
._timer_deinit = ets_timer_deinit,
._timer_arm = timer_arm_wrapper,
._timer_disarm = timer_disarm_wrapper,
._timer_done = timer_done_wrapper,
@@ -481,7 +540,7 @@ wifi_osi_funcs_t g_wifi_osi_funcs = {
._malloc_internal = malloc_internal_wrapper,
._realloc_internal = realloc_internal_wrapper,
._calloc_internal = calloc_internal_wrapper,
._zalloc_internal = zalloc_internal_wrapper,
._zalloc_internal = zalloc_internal_wrapper,
._wifi_malloc = wifi_malloc,
._wifi_realloc = wifi_realloc,
._wifi_calloc = wifi_calloc,
@@ -494,5 +553,32 @@ wifi_osi_funcs_t g_wifi_osi_funcs = {
._modem_sleep_deregister = esp_modem_sleep_deregister,
._sc_ack_send = sc_ack_send_wrapper,
._sc_ack_send_stop = sc_ack_send_stop,
._coex_status_get = coex_status_get_wrapper,
._coex_wifi_request = coex_wifi_request_wrapper,
._coex_wifi_release = coex_wifi_release_wrapper,
._magic = ESP_WIFI_OS_ADAPTER_MAGIC,
};
coex_adapter_funcs_t g_coex_adapter_funcs = {
._version = COEX_ADAPTER_VERSION,
._spin_lock_create = spin_lock_create_wrapper,
._spin_lock_delete = free,
._int_disable = wifi_int_disable_wrapper,
._int_enable = wifi_int_restore_wrapper,
._task_yield_from_isr = task_yield_from_isr_wrapper,
._semphr_create = semphr_create_wrapper,
._semphr_delete = semphr_delete_wrapper,
._semphr_take_from_isr = semphr_take_from_isr_wrapper,
._semphr_give_from_isr = semphr_give_from_isr_wrapper,
._semphr_take = semphr_take_wrapper,
._semphr_give = semphr_give_wrapper,
._is_in_isr = xPortInIsrContext,
._malloc_internal = malloc_internal_wrapper,
._free = free,
._timer_disarm = timer_disarm_wrapper,
._timer_done = timer_done_wrapper,
._timer_setfn = timer_setfn_wrapper,
._timer_arm_us = timer_arm_us_wrapper,
._esp_timer_get_time = esp_timer_get_time,
._magic = COEX_ADAPTER_MAGIC,
};

View File

@@ -13,16 +13,21 @@
// limitations under the License.
/******************************************************************************
* Description: A stub to make the ESP32 debuggable by GDB over the serial
* Description: A stub to make the ESP32 debuggable by GDB over the serial
* port, at least enough to do a backtrace on panic. This gdbstub is read-only:
* it allows inspecting the ESP32 state
* it allows inspecting the ESP32 state
*******************************************************************************/
#include <string.h>
#include "rom/ets_sys.h"
#include "soc/uart_reg.h"
#include "soc/io_mux_reg.h"
#include "esp_gdbstub.h"
#include "esp_panic.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
//Length of buffer used to reserve GDB commands. Has to be at least able to fit the G command, which
//implies a minimum size of about 320 bytes.
@@ -187,7 +192,7 @@ typedef struct {
GdbRegFile gdbRegFile;
/*
/*
//Register format as the Xtensa HAL has it:
STRUCT_FIELD (long, 4, XT_STK_EXIT, exit)
STRUCT_FIELD (long, 4, XT_STK_PC, pc)
@@ -201,7 +206,7 @@ STRUCT_FIELD (long, 4, XT_STK_EXCVADDR, excvaddr)
STRUCT_FIELD (long, 4, XT_STK_LBEG, lbeg)
STRUCT_FIELD (long, 4, XT_STK_LEND, lend)
STRUCT_FIELD (long, 4, XT_STK_LCOUNT, lcount)
// Temporary space for saving stuff during window spill
// Temporary space for saving stuff during window spill
STRUCT_FIELD (long, 4, XT_STK_TMP0, tmp0)
STRUCT_FIELD (long, 4, XT_STK_TMP1, tmp1)
STRUCT_FIELD (long, 4, XT_STK_TMP2, tmp2)
@@ -211,24 +216,13 @@ STRUCT_FIELD (long, 4, XT_STK_OVLY, ovly)
STRUCT_END(XtExcFrame)
*/
static void dumpHwToRegfile(XtExcFrame *frame) {
int i;
long *frameAregs=&frame->a0;
gdbRegFile.pc=frame->pc;
for (i=0; i<16; i++) gdbRegFile.a[i]=frameAregs[i];
for (i=16; i<64; i++) gdbRegFile.a[i]=0xDEADBEEF;
gdbRegFile.lbeg=frame->lbeg;
gdbRegFile.lend=frame->lend;
gdbRegFile.lcount=frame->lcount;
gdbRegFile.sar=frame->sar;
//All windows have been spilled to the stack by the ISR routines. The following values should indicate that.
gdbRegFile.sar=frame->sar;
static void commonRegfile() {
if (gdbRegFile.a[0] & 0x8000000U) gdbRegFile.a[0] = (gdbRegFile.a[0] & 0x3fffffffU) | 0x40000000U;
if (!esp_stack_ptr_is_sane(gdbRegFile.a[1])) gdbRegFile.a[1] = 0xDEADBEEF;
gdbRegFile.windowbase=0; //0
gdbRegFile.windowstart=0x1; //1
gdbRegFile.configid0=0xdeadbeef; //ToDo
gdbRegFile.configid1=0xdeadbeef; //ToDo
gdbRegFile.ps=frame->ps-PS_EXCM_MASK;
gdbRegFile.threadptr=0xdeadbeef; //ToDo
gdbRegFile.br=0xdeadbeef; //ToDo
gdbRegFile.scompare1=0xdeadbeef; //ToDo
@@ -238,9 +232,23 @@ static void dumpHwToRegfile(XtExcFrame *frame) {
gdbRegFile.m1=0xdeadbeef; //ToDo
gdbRegFile.m2=0xdeadbeef; //ToDo
gdbRegFile.m3=0xdeadbeef; //ToDo
gdbRegFile.expstate=frame->exccause; //ToDo
}
static void dumpHwToRegfile(XtExcFrame *frame) {
int i;
long *frameAregs=&frame->a0;
gdbRegFile.pc=(frame->pc & 0x3fffffffU)|0x40000000U;
for (i=0; i<16; i++) gdbRegFile.a[i]=frameAregs[i];
for (i=16; i<64; i++) gdbRegFile.a[i]=0xDEADBEEF;
gdbRegFile.lbeg=frame->lbeg;
gdbRegFile.lend=frame->lend;
gdbRegFile.lcount=frame->lcount;
gdbRegFile.ps=(frame->ps & PS_UM) ? (frame->ps & ~PS_EXCM) : frame->ps;
//All windows have been spilled to the stack by the ISR routines. The following values should indicate that.
gdbRegFile.sar=frame->sar;
commonRegfile();
gdbRegFile.expstate=frame->exccause; //ToDo
}
//Send the reason execution is stopped to GDB.
static void sendReason() {
@@ -251,13 +259,114 @@ static void sendReason() {
gdbPacketChar('T');
i=gdbRegFile.expstate&0x7f;
if (i<sizeof(exceptionSignal)) {
gdbPacketHex(exceptionSignal[i], 8);
gdbPacketHex(exceptionSignal[i], 8);
} else {
gdbPacketHex(11, 8);
}
gdbPacketEnd();
}
static int sendPacket(const char * text) {
gdbPacketStart();
if (text != NULL) gdbPacketStr(text);
gdbPacketEnd();
return ST_OK;
}
#if CONFIG_GDBSTUB_SUPPORT_TASKS
#define STUB_TASKS_NUM CONFIG_GDBSTUB_MAX_TASKS
//Remember the exception frame that caused panic since it's not saved in TCB
static XtExcFrame paniced_frame;
//Allows GDBStub to disable task support after a crash
//(e.g. if GDBStub crashes while trying to get task list, e.g. due to corrupted list structures)
static enum {
HANDLER_NOT_STARTED,
HANDLER_STARTED,
HANDLER_TASK_SUPPORT_DISABLED
} handlerState;
static void dumpTaskToRegfile(XtSolFrame *frame) {
int i;
long *frameAregs=&frame->a0;
gdbRegFile.pc=(frame->pc & 0x3fffffffU)|0x40000000U;
for (i=0; i<4; i++) gdbRegFile.a[i]=frameAregs[i];
for (i=4; i<64; i++) gdbRegFile.a[i]=0xDEADBEEF;
gdbRegFile.lbeg=0;
gdbRegFile.lend=0;
gdbRegFile.lcount=0;
gdbRegFile.ps=(frame->ps & PS_UM) ? (frame->ps & ~PS_EXCM) : frame->ps;
//All windows have been spilled to the stack by the ISR routines. The following values should indicate that.
gdbRegFile.sar=0;
commonRegfile();
gdbRegFile.expstate=0; //ToDo
}
// Fetch the task status. Returns the total number of tasks.
static unsigned getTaskInfo(unsigned index, unsigned * handle, const char ** name, unsigned * coreId) {
static unsigned taskCount = 0;
static TaskSnapshot_t tasks[STUB_TASKS_NUM];
if (!taskCount) {
unsigned tcbSize = 0;
taskCount = uxTaskGetSnapshotAll(tasks, STUB_TASKS_NUM, &tcbSize);
}
if (index < taskCount) {
TaskHandle_t h = (TaskHandle_t)tasks[index].pxTCB;
if (handle) *handle = (unsigned)h;
if (name) *name = pcTaskGetTaskName(h);
if (coreId) *coreId = xTaskGetAffinity(h);
}
return taskCount;
}
typedef struct
{
uint8_t * topOfStack;
} DumpTCB;
static void dumpTCBToRegFile(unsigned handle) {
// A task handle is a pointer to a TCB in FreeRTOS
DumpTCB * tcb = (DumpTCB*)handle;
uint8_t * pxTopOfStack = tcb->topOfStack;
//Deduced from coredump code
XtExcFrame * frame = (XtExcFrame*)pxTopOfStack;
if (frame->exit) {
// It's an exception frame
dumpHwToRegfile(frame);
} else {
XtSolFrame * taskFrame = (XtSolFrame*)pxTopOfStack;
dumpTaskToRegfile(taskFrame);
}
}
#define CUR_TASK_INDEX_NOT_SET -2
#define CUR_TASK_INDEX_UNKNOWN -1
// Get the index of the task currently running on the current CPU, and cache the result
static int findCurrentTaskIndex() {
static int curTaskIndex = CUR_TASK_INDEX_NOT_SET;
if (curTaskIndex == CUR_TASK_INDEX_NOT_SET) {
unsigned curHandle = (unsigned)xTaskGetCurrentTaskHandleForCPU(xPortGetCoreID());
unsigned handle;
unsigned count = getTaskInfo(0, 0, 0, 0);
for(int k=0; k<(int)count; k++) {
if (getTaskInfo(k, &handle, 0, 0) && curHandle == handle) {
curTaskIndex = k;
return curTaskIndex;
}
}
curTaskIndex = CUR_TASK_INDEX_UNKNOWN;
}
return curTaskIndex;
}
#endif // CONFIG_GDBSTUB_SUPPORT_TASKS
//Handle a command as received from GDB.
static int gdbHandleCommand(unsigned char *cmd, int len) {
//Handle a command
@@ -270,10 +379,8 @@ static int gdbHandleCommand(unsigned char *cmd, int len) {
gdbPacketEnd();
} else if (cmd[0]=='G') { //receive content for all registers from gdb
int *p=(int*)&gdbRegFile;
for (i=0; i<sizeof(GdbRegFile)/4; i++) *p++=iswap(gdbGetHexVal(&data, 32));;
gdbPacketStart();
gdbPacketStr("OK");
gdbPacketEnd();
for (i=0; i<sizeof(GdbRegFile)/4; i++) *p++=iswap(gdbGetHexVal(&data, 32));
sendPacket("OK");
} else if (cmd[0]=='m') { //read memory to gdb
i=gdbGetHexVal(&data, -1);
data++;
@@ -285,11 +392,91 @@ static int gdbHandleCommand(unsigned char *cmd, int len) {
gdbPacketEnd();
} else if (cmd[0]=='?') { //Reply with stop reason
sendReason();
#if CONFIG_GDBSTUB_SUPPORT_TASKS
} else if (handlerState != HANDLER_TASK_SUPPORT_DISABLED) {
if (cmd[0]=='H') { //Continue with task
if (cmd[1]=='g' || cmd[1]=='c') {
const char * ret = "OK";
data++;
i=gdbGetHexVal(&data, -1);
handlerState = HANDLER_STARTED; //Hg0 is the first packet received after connect
j = findCurrentTaskIndex();
if (i == j || (j == CUR_TASK_INDEX_UNKNOWN && i == 0)) {
//GDB has asked us for the current task on this CPU.
//This task either was executing when we have entered the panic handler,
//or was already switched out and we have paniced during the context switch.
//Either way we are interested in the stack frame where panic has happened,
//so obtain the state from the exception frame rather than the TCB.
dumpHwToRegfile(&paniced_frame);
} else {
unsigned handle, count;
//Get the handle for that task
count = getTaskInfo(i, &handle, 0, 0);
//Then extract TCB and gdbRegFile from it
if (i < count) dumpTCBToRegFile(handle);
else ret = "E00";
}
return sendPacket(ret);
}
return sendPacket(NULL);
} else if (cmd[0]=='T') { //Task alive check
unsigned count;
data++;
i=gdbGetHexVal(&data, -1);
count = getTaskInfo(i, 0, 0, 0);
return sendPacket(i < count ? "OK": "E00");
} else if (cmd[0]=='q') { //Extended query
// React to qThreadExtraInfo or qfThreadInfo or qsThreadInfo or qC, without using strcmp
if (len > 16 && cmd[1] == 'T' && cmd[2] == 'h' && cmd[3] == 'r' && cmd[7] == 'E' && cmd[12] == 'I' && cmd[16] == ',') {
data=&cmd[17];
i=gdbGetHexVal(&data, -1);
unsigned handle = 0, coreId = 3;
const char * name = 0;
// Extract the task name and CPU from freeRTOS
unsigned tCount = getTaskInfo(i, &handle, &name, &coreId);
if (i < tCount) {
gdbPacketStart();
for(k=0; name[k]; k++) gdbPacketHex(name[k], 8);
gdbPacketStr("20435055"); // CPU
gdbPacketStr(coreId == 0 ? "30": coreId == 1 ? "31" : "78"); // 0 or 1 or x
gdbPacketEnd();
return ST_OK;
}
} else if (len >= 12 && (cmd[1] == 'f' || cmd[1] == 's') && (cmd[2] == 'T' && cmd[3] == 'h' && cmd[4] == 'r' && cmd[5] == 'e' && cmd[6] == 'a' && cmd[7] == 'd' && cmd[8] == 'I')) {
// Only react to qfThreadInfo and qsThreadInfo, not using strcmp here since it can be in ROM
// Extract the number of task from freeRTOS
static int taskIndex = 0;
unsigned tCount = 0;
if (cmd[1] == 'f') {
taskIndex = 0;
handlerState = HANDLER_STARTED; //It seems it's the first request GDB is sending
}
tCount = getTaskInfo(0, 0, 0, 0);
if (taskIndex < tCount) {
gdbPacketStart();
gdbPacketStr("m");
gdbPacketHex(taskIndex, 32);
gdbPacketEnd();
taskIndex++;
} else return sendPacket("l");
} else if (len >= 2 && cmd[1] == 'C') {
// Get current task id
gdbPacketStart();
k = findCurrentTaskIndex();
if (k != CUR_TASK_INDEX_UNKNOWN) {
gdbPacketStr("QC");
gdbPacketHex(k, 32);
} else gdbPacketStr("bad");
gdbPacketEnd();
return ST_OK;
}
return sendPacket(NULL);
}
#endif // CONFIG_GDBSTUB_SUPPORT_TASKS
} else {
//We don't recognize or support whatever GDB just sent us.
gdbPacketStart();
gdbPacketEnd();
return ST_ERR;
return sendPacket(NULL);
}
return ST_OK;
}
@@ -297,7 +484,7 @@ static int gdbHandleCommand(unsigned char *cmd, int len) {
//Lower layer: grab a command packet and check the checksum
//Calls gdbHandleCommand on the packet if the checksum is OK
//Returns ST_OK on success, ST_ERR when checksum fails, a
//Returns ST_OK on success, ST_ERR when checksum fails, a
//character if it is received instead of the GDB packet
//start char.
static int gdbReadCommand() {
@@ -344,9 +531,21 @@ static int gdbReadCommand() {
}
void esp_gdbstub_panic_handler(XtExcFrame *frame) {
#if CONFIG_GDBSTUB_SUPPORT_TASKS
if (handlerState == HANDLER_STARTED) {
//We have re-entered GDB Stub. Try disabling task support.
handlerState = HANDLER_TASK_SUPPORT_DISABLED;
gdbPacketEnd(); // Ends up any pending GDB packet (this creates a garbage value)
} else if (handlerState == HANDLER_NOT_STARTED) {
//Need to remember the frame that panic'd since gdb will ask for all threads before ours
memcpy(&paniced_frame, frame, sizeof(paniced_frame));
dumpHwToRegfile(&paniced_frame);
}
#else // CONFIG_GDBSTUB_SUPPORT_TASKS
dumpHwToRegfile(frame);
#endif // CONFIG_GDBSTUB_SUPPORT_TASKS
//Make sure txd/rxd are enabled
gpio_pullup_dis(1);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD);
@@ -356,4 +555,3 @@ void esp_gdbstub_panic_handler(XtExcFrame *frame) {
while(gdbReadCommand()!=ST_CONT);
while(1);
}

View File

@@ -0,0 +1,59 @@
// Copyright 2019 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.
#ifndef __ESP_COEXIST_ADAPTER_H__
#define __ESP_COEXIST_ADAPTER_H__
#include <stdarg.h>
#ifdef __cplusplus
extern "C" {
#endif
#define COEX_ADAPTER_VERSION 0x00000001
#define COEX_ADAPTER_MAGIC 0xDEADBEAF
#define COEX_ADAPTER_FUNCS_TIME_BLOCKING 0xffffffff
typedef struct {
int32_t _version;
void *(* _spin_lock_create)(void);
void (* _spin_lock_delete)(void *lock);
uint32_t (*_int_disable)(void *mux);
void (*_int_enable)(void *mux, uint32_t tmp);
void (*_task_yield_from_isr)(void);
void *(*_semphr_create)(uint32_t max, uint32_t init);
void (*_semphr_delete)(void *semphr);
int32_t (*_semphr_take_from_isr)(void *semphr, void *hptw);
int32_t (*_semphr_give_from_isr)(void *semphr, void *hptw);
int32_t (*_semphr_take)(void *semphr, uint32_t block_time_tick);
int32_t (*_semphr_give)(void *semphr);
int32_t (* _is_in_isr)(void);
void * (* _malloc_internal)(size_t size);
void (* _free)(void *p);
void (* _timer_disarm)(void *timer);
void (* _timer_done)(void *ptimer);
void (* _timer_setfn)(void *ptimer, void *pfunction, void *parg);
void (* _timer_arm_us)(void *ptimer, uint32_t us, bool repeat);
int64_t (* _esp_timer_get_time)(void);
int32_t _magic;
} coex_adapter_funcs_t;
extern coex_adapter_funcs_t g_coex_adapter_funcs;
#ifdef __cplusplus
}
#endif
#endif /* __ESP_COEXIST_ADAPTER_H__ */

View File

@@ -0,0 +1,163 @@
// Copyright 2018-2018 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.
#ifndef __ESP_COEXIST_INTERNAL_H__
#define __ESP_COEXIST_INTERNAL_H__
#include <stdbool.h>
#include "esp_coexist_adapter.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
COEX_PREFER_WIFI = 0,
COEX_PREFER_BT,
COEX_PREFER_BALANCE,
COEX_PREFER_NUM,
} coex_prefer_t;
typedef void (* coex_func_cb_t)(uint32_t event, int sched_cnt);
/**
* @brief Init software coexist
* extern function for internal use.
*
* @return Init ok or failed.
*/
esp_err_t coex_init(void);
/**
* @brief De-init software coexist
* extern function for internal use.
*/
void coex_deinit(void);
/**
* @brief Pause software coexist
* extern function for internal use.
*/
void coex_pause(void);
/**
* @brief Resume software coexist
* extern function for internal use.
*/
void coex_resume(void);
/**
* @brief Get software coexist version string
* extern function for internal use.
* @return : version string
*/
const char *coex_version_get(void);
/**
* @brief Coexist performance preference set from libbt.a
* extern function for internal use.
*
* @param prefer : the prefer enumeration value
* @return : ESP_OK - success, other - failed
*/
esp_err_t coex_preference_set(coex_prefer_t prefer);
/**
* @brief Get software coexist status.
* @return : software coexist status
*/
uint32_t coex_status_get(void);
/**
* @brief WiFi requests coexistence.
*
* @param event : WiFi event
* @param latency : WiFi will request coexistence after latency
* @param duration : duration for WiFi to request coexistence
* @return : 0 - success, other - failed
*/
int coex_wifi_request(uint32_t event, uint32_t latency, uint32_t duration);
/**
* @brief WiFi release coexistence.
*
* @param event : WiFi event
* @return : 0 - success, other - failed
*/
int coex_wifi_release(uint32_t event);
/**
* @brief Blue tooth requests coexistence.
*
* @param event : blue tooth event
* @param latency : blue tooth will request coexistence after latency
* @param duration : duration for blue tooth to request coexistence
* @return : 0 - success, other - failed
*/
int coex_bt_request(uint32_t event, uint32_t latency, uint32_t duration);
/**
* @brief Blue tooth release coexistence.
*
* @param event : blue tooth event
* @return : 0 - success, other - failed
*/
int coex_bt_release(uint32_t event);
/**
* @brief Register callback function for blue tooth.
*
* @param cb : callback function
* @return : 0 - success, other - failed
*/
int coex_register_bt_cb(coex_func_cb_t cb);
/**
* @brief Lock before reset base band.
*
* @return : lock value
*/
uint32_t coex_bb_reset_lock(void);
/**
* @brief Unlock after reset base band.
*
* @param restore : lock value
*/
void coex_bb_reset_unlock(uint32_t restore);
/**
* @brief Register coexistence adapter functions.
*
* @param funcs : coexistence adapter functions
* @return : ESP_OK - success, other - failed
*/
esp_err_t esp_coex_adapter_register(coex_adapter_funcs_t *funcs);
/**
* @brief Check the MD5 values of the coexistence adapter header files in IDF and WiFi library
*
* @attention 1. It is used for internal CI version check
*
* @return
* - ESP_OK : succeed
* - ESP_WIFI_INVALID_ARG : MD5 check fail
*/
esp_err_t esp_coex_adapter_funcs_md5_check(const char *md5);
#ifdef __cplusplus
}
#endif
#endif /* __ESP_COEXIST_INTERNAL_H__ */

View File

@@ -1,85 +0,0 @@
// 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.
#ifndef ESP_CORE_DUMP_H_
#define ESP_CORE_DUMP_H_
/**************************************************************************************/
/******************************** EXCEPTION MODE API **********************************/
/**************************************************************************************/
/**
* @brief Initializes core dump module internal data.
*
* @note Should be called at system startup.
*/
void esp_core_dump_init();
/**
* @brief Saves core dump to flash.
*
* The structure of data stored in flash is as follows:
*
* | TOTAL_LEN | TASKS_NUM | TCB_SIZE |
* | TCB_ADDR_1 | STACK_TOP_1 | STACK_END_1 | TCB_1 | STACK_1 |
* . . . .
* . . . .
* | TCB_ADDR_N | STACK_TOP_N | STACK_END_N | TCB_N | STACK_N |
* | CRC32 |
*
* Core dump in flash consists of header and data for every task in the system at the moment of crash.
* For flash data integrity control CRC is used at the end of core the dump data.
* The structure of core dump data is described below in details.
* 1) Core dump starts with header:
* 1.1) TOTAL_LEN is total length of core dump data in flash including CRC. Size is 4 bytes.
* 1.2) TASKS_NUM is the number of tasks for which data are stored. Size is 4 bytes.
* 1.3) TCB_SIZE is the size of task's TCB structure. Size is 4 bytes.
* 2) Core dump header is followed by the data for every task in the system.
* Task data are started with task header:
* 2.1) TCB_ADDR is the address of TCB in memory. Size is 4 bytes.
* 2.2) STACK_TOP is the top of task's stack (address of the topmost stack item). Size is 4 bytes.
* 2.2) STACK_END is the end of task's stack (address from which task's stack starts). Size is 4 bytes.
* 3) Task header is followed by TCB data. Size is TCB_SIZE bytes.
* 4) Task's stack is placed after TCB data. Size is (STACK_END - STACK_TOP) bytes.
* 5) CRC is placed at the end of the data.
*/
void esp_core_dump_to_flash();
/**
* @brief Print base64-encoded core dump to UART.
*
* The structure of core dump data is the same as for data stored in flash (@see esp_core_dump_to_flash) with some notes:
* 1) CRC is not present in core dump printed to UART.
* 2) Since CRC is omitted TOTAL_LEN does not include its size.
* 3) Printed base64 data are surrounded with special messages to help user recognize the start and end of actual data.
*/
void esp_core_dump_to_uart();
/**************************************************************************************/
/*********************************** USER MODE API ************************************/
/**************************************************************************************/
/**
* @brief Retrieves address and size of coredump data in flash.
* This function is always available, even when core dump is disabled in menuconfig.
*
* @param out_addr pointer to store image address in flash.
* @param out_size pointer to store image size in flash (including CRC). In bytes.
*
* @return ESP_OK on success, otherwise \see esp_err_t
*/
esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size);
#endif

View File

@@ -104,14 +104,14 @@ void _esp_error_check_failed_without_abort(esp_err_t rc, const char *file, int l
#define ESP_ERROR_CHECK(x) do { \
esp_err_t __err_rc = (x); \
(void) sizeof(__err_rc); \
} while(0);
} while(0)
#elif defined(CONFIG_OPTIMIZATION_ASSERTIONS_SILENT)
#define ESP_ERROR_CHECK(x) do { \
esp_err_t __err_rc = (x); \
if (__err_rc != ESP_OK) { \
abort(); \
} \
} while(0);
} while(0)
#else
#define ESP_ERROR_CHECK(x) do { \
esp_err_t __err_rc = (x); \
@@ -119,7 +119,7 @@ void _esp_error_check_failed_without_abort(esp_err_t rc, const char *file, int l
_esp_error_check_failed(__err_rc, __FILE__, __LINE__, \
__ASSERT_FUNC, #x); \
} \
} while(0);
} while(0)
#endif
/**

View File

@@ -120,6 +120,10 @@ typedef struct {
uint8_t mac[6]; /**< MAC address of the station which send probe request */
} system_event_ap_probe_req_rx_t;
typedef struct {
ip4_addr_t ip;
} system_event_ap_staipassigned_t;
typedef union {
system_event_sta_connected_t connected; /**< ESP32 station connected to AP */
system_event_sta_disconnected_t disconnected; /**< ESP32 station disconnected to AP */
@@ -131,6 +135,7 @@ typedef union {
system_event_ap_staconnected_t sta_connected; /**< a station connected to ESP32 soft-AP */
system_event_ap_stadisconnected_t sta_disconnected; /**< a station disconnected to ESP32 soft-AP */
system_event_ap_probe_req_rx_t ap_probereqrecved; /**< ESP32 soft-AP receive probe request packet */
system_event_ap_staipassigned_t ap_staipassigned; /**< ESP32 soft-AP assign an IP to the station*/
system_event_got_ip6_t got_ip6; /**< ESP32 station or ap or ethernet ipv6 addr state change to preferred */
} system_event_info_t;

View File

@@ -249,6 +249,15 @@ void *wifi_realloc( void *ptr, size_t size );
*/
void *wifi_calloc( size_t n, size_t size );
/**
* @brief Update WiFi MAC time
*
* @param uint32_t time_delta : time duration since the WiFi/BT common clock is disabled
*
* @return Always returns ESP_OK
*/
typedef esp_err_t (* wifi_mac_time_update_cb_t)( uint32_t time_delta );
/**
* @brief Update WiFi MAC time
*

View File

@@ -21,7 +21,7 @@
extern "C" {
#endif
#define ESP_WIFI_OS_ADAPTER_VERSION 0x00000001
#define ESP_WIFI_OS_ADAPTER_VERSION 0x00000002
#define ESP_WIFI_OS_ADAPTER_MAGIC 0xDEADBEAF
#define OSI_FUNCS_TIME_BLOCKING 0xffffffff
@@ -39,12 +39,9 @@ typedef struct {
void (* _spin_lock_delete)(void *lock);
uint32_t (*_wifi_int_disable)(void *wifi_int_mux);
void (*_wifi_int_restore)(void *wifi_int_mux, uint32_t tmp);
void (*_task_yield)(void);
void (*_task_yield_from_isr)(void);
void *(*_semphr_create)(uint32_t max, uint32_t init);
void (*_semphr_delete)(void *semphr);
int32_t (*_semphr_take_from_isr)(void *semphr, void *hptw);
int32_t (*_semphr_give_from_isr)(void *semphr, void *hptw);
int32_t (*_semphr_take)(void *semphr, uint32_t block_time_tick);
int32_t (*_semphr_give)(void *semphr);
void *(*_mutex_create)(void);
@@ -59,7 +56,6 @@ typedef struct {
int32_t (* _queue_send_to_back)(void *queue, void *item, uint32_t block_time_tick);
int32_t (* _queue_send_to_front)(void *queue, void *item, uint32_t block_time_tick);
int32_t (* _queue_recv)(void *queue, void *item, uint32_t block_time_tick);
int32_t (* _queue_recv_from_isr)(void *queue, void * const item, int32_t * const hptw);
uint32_t (* _queue_msg_waiting)(void *queue);
void *(* _event_group_create)(void);
void (* _event_group_delete)(void *event);
@@ -73,19 +69,15 @@ typedef struct {
int32_t (* _task_ms_to_tick)(uint32_t ms);
void *(* _task_get_current_task)(void);
int32_t (* _task_get_max_priority)(void);
int32_t (* _is_in_isr)(void);
void *(* _malloc)(uint32_t size);
void (* _free)(void *p);
uint32_t (* _get_free_heap_size)(void);
uint32_t (* _rand)(void);
void (* _dport_access_stall_other_cpu_start_wrap)(void);
void (* _dport_access_stall_other_cpu_end_wrap)(void);
int32_t (* _phy_rf_init)(const void * init_data, uint32_t mode, void * calibration_data, uint32_t module);
int32_t (* _phy_rf_deinit)(uint32_t module);
void (* _phy_load_cal_and_init)(uint32_t module);
int32_t (* _read_mac)(uint8_t* mac, uint32_t type);
void (* _timer_init)(void);
void (* _timer_deinit)(void);
void (* _timer_arm)(void *timer, uint32_t tmout, bool repeat);
void (* _timer_disarm)(void *timer);
void (* _timer_done)(void *ptimer);
@@ -127,6 +119,9 @@ typedef struct {
int32_t (* _modem_sleep_deregister)(uint32_t module);
void (* _sc_ack_send)(void *param);
void (* _sc_ack_send_stop)(void);
uint32_t (* _coex_status_get)(void);
int32_t (* _coex_wifi_request)(uint32_t event, uint32_t latency, uint32_t duration);
int32_t (* _coex_wifi_release)(uint32_t event);
int32_t _magic;
} wifi_osi_funcs_t;

View File

@@ -30,15 +30,48 @@ extern "C" {
*/
/* Standard CRC8/16/32 algorithms. */
// CRC-8 x8+x2+x1+1 0x07
// CRC16-CCITT x16+x12+x5+1 1021 ISO HDLC, ITU X.25, V.34/V.41/V.42, PPP-FCS
// CRC32:
//G(x) = x32 +x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x1 + 1
//If your buf is not continuous, you can use the first result to be the second parameter.
/* Notes about CRC APIs usage
* The ESP32 ROM include some CRC tables and CRC APIs to speed up CRC calculation.
* The CRC APIs include CRC8, CRC16, CRC32 algorithms for both little endian and big endian modes.
* Here are the polynomials for the algorithms:
* CRC-8 x8+x2+x1+1 0x07
* CRC16-CCITT x16+x12+x5+1 0x1021
* CRC32 x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x1+1 0x04c11db7
*
* These group of CRC APIs are designed to calculate the data in buffers either continuous or not.
* To make it easy, we had added a `~` at the beginning and the end of the functions.
* To calculate non-continuous buffers, we can write the code like this:
* init = ~init;
* crc = crc32_le(init, buf0, length0);
* crc = crc32_le(crc, buf1, length1);
* crc = ~crc;
*
* However, it is not easy to select which API to use and give the correct parameters.
* A specific CRC algorithm will include this parameters: width, polynomials, init, refin, refout, xorout
* refin and refout show the endian of the algorithm:
* if both of them are true, please use the little endian API.
* if both of them are false, please use the big endian API.
* xorout is the value which you need to be xored to the raw result.
* However, these group of APIs need one '~' before and after the APIs.
*
* Here are some examples for CRC16:
* CRC-16/CCITT, poly = 0x1021, init = 0x0000, refin = true, refout = true, xorout = 0x0000
* crc = ~crc16_le((uint16_t)~0x0000, buf, length);
*
* CRC-16/CCITT-FALSE, poly = 0x1021, init = 0xffff, refin = false, refout = false, xorout = 0x0000
* crc = ~crc16_be((uint16_t)~0xffff, buf, length);
*
* CRC-16/X25, poly = 0x1021, init = 0xffff, refin = true, refout = true, xorout = 0xffff
* crc = (~crc16_le((uint16_t)~(0xffff), buf, length))^0xffff;
*
* CRC-16/XMODEM, poly= 0x1021, init = 0x0000, refin = false, refout = false, xorout = 0x0000
* crc = ~crc16_be((uint16_t)~0x0000, buf, length);
*
*
*/
/**
* @brief Crc32 value that is in little endian.
* @brief CRC32 value that is in little endian.
*
* @param uint32_t crc : init crc value, use 0 at the first use.
*
@@ -51,7 +84,7 @@ extern "C" {
uint32_t crc32_le(uint32_t crc, uint8_t const *buf, uint32_t len);
/**
* @brief Crc32 value that is in big endian.
* @brief CRC32 value that is in big endian.
*
* @param uint32_t crc : init crc value, use 0 at the first use.
*
@@ -64,7 +97,7 @@ uint32_t crc32_le(uint32_t crc, uint8_t const *buf, uint32_t len);
uint32_t crc32_be(uint32_t crc, uint8_t const *buf, uint32_t len);
/**
* @brief Crc16 value that is in little endian.
* @brief CRC16 value that is in little endian.
*
* @param uint16_t crc : init crc value, use 0 at the first use.
*
@@ -77,7 +110,7 @@ uint32_t crc32_be(uint32_t crc, uint8_t const *buf, uint32_t len);
uint16_t crc16_le(uint16_t crc, uint8_t const *buf, uint32_t len);
/**
* @brief Crc16 value that is in big endian.
* @brief CRC16 value that is in big endian.
*
* @param uint16_t crc : init crc value, use 0 at the first use.
*
@@ -90,7 +123,7 @@ uint16_t crc16_le(uint16_t crc, uint8_t const *buf, uint32_t len);
uint16_t crc16_be(uint16_t crc, uint8_t const *buf, uint32_t len);
/**
* @brief Crc8 value that is in little endian.
* @brief CRC8 value that is in little endian.
*
* @param uint8_t crc : init crc value, use 0 at the first use.
*
@@ -103,7 +136,7 @@ uint16_t crc16_be(uint16_t crc, uint8_t const *buf, uint32_t len);
uint8_t crc8_le(uint8_t crc, uint8_t const *buf, uint32_t len);
/**
* @brief Crc8 value that is in big endian.
* @brief CRC8 value that is in big endian.
*
* @param uint32_t crc : init crc value, use 0 at the first use.
*

View File

@@ -268,7 +268,7 @@ void ets_install_uart_printf(void);
ets_printf("%s %u \n", __FILE__, __LINE__); \
while (1) {}; \
} \
} while (0);
} while (0)
/**
* @}

View File

@@ -118,7 +118,7 @@ const static int_desc_t int_desc[32]={
{ 3, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //23
{ 4, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_NORMAL} }, //24
{ 4, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //25
{ 5, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //26
{ 5, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_RESVD } }, //26
{ 3, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //27
{ 4, INTTP_EDGE, {INTDESC_NORMAL, INTDESC_NORMAL} }, //28
{ 3, INTTP_NA, {INTDESC_SPECIAL,INTDESC_SPECIAL}}, //29

View File

@@ -36,10 +36,11 @@
#include "freertos/portmacro.h"
#include "phy.h"
#include "phy_init_data.h"
#include "coexist_internal.h"
#include "esp_coexist_internal.h"
#include "driver/periph_ctrl.h"
#include "esp_wifi_internal.h"
extern wifi_mac_time_update_cb_t s_wifi_mac_time_update_cb;
static const char* TAG = "phy_init";
@@ -92,7 +93,9 @@ static inline void phy_update_wifi_mac_time(bool en_clock_stopped, int64_t now)
if (s_common_clock_disable_time) {
uint32_t diff = (uint64_t)now - s_common_clock_disable_time;
esp_wifi_internal_update_mac_time(diff);
if (s_wifi_mac_time_update_cb) {
s_wifi_mac_time_update_cb(diff);
}
s_common_clock_disable_time = 0;
ESP_LOGD(TAG, "wifi mac time delta: %u", diff);
}
@@ -159,14 +162,6 @@ esp_err_t esp_phy_rf_init(const esp_phy_init_data_t* init_data, esp_phy_calibrat
#endif
}
extern esp_err_t wifi_osi_funcs_register(wifi_osi_funcs_t *osi_funcs);
status = wifi_osi_funcs_register(&g_wifi_osi_funcs);
if(status != ESP_OK) {
ESP_LOGE(TAG, "failed to register wifi os adapter, ret(%d)", status);
_lock_release(&s_phy_rf_init_lock);
return ESP_FAIL;
}
coex_bt_high_prio();
}
}

View File

@@ -39,7 +39,7 @@ void esp_pm_trace_exit(esp_pm_trace_event_t event, int core_id);
#else // CONFIG_PM_TRACE
#define ESP_PM_TRACE_ENTER(type, core_id) do { (void) core_id; } while(0);
#define ESP_PM_TRACE_EXIT(type, core_id) do { (void) core_id; } while(0);
#define ESP_PM_TRACE_ENTER(type, core_id) do { (void) core_id; } while(0)
#define ESP_PM_TRACE_EXIT(type, core_id) do { (void) core_id; } while(0)
#endif // CONFIG_PM_TRACE

View File

@@ -21,9 +21,16 @@ execute_process(COMMAND md5sum ${IDF_PATH}/components/esp32/include/esp_wifi_cry
COMMAND cut -c 1-7
OUTPUT_VARIABLE WIFI_CRYPTO_MD5
OUTPUT_STRIP_TRAILING_WHITESPACE)
# Calculate MD5 value of header file esp_coexist_adapter.h
execute_process(COMMAND md5sum ${IDF_PATH}/components/esp32/include/esp_coexist_adapter.h
COMMAND cut -c 1-7
OUTPUT_VARIABLE COEX_ADAPTER_MD5
OUTPUT_STRIP_TRAILING_WHITESPACE)
add_definitions(-DWIFI_OS_ADAPTER_MD5=\"${WIFI_OS_ADAPTER_MD5}\")
add_definitions(-DWIFI_CRYPTO_MD5=\"${WIFI_CRYPTO_MD5}\")
add_definitions(-DCOEX_ADAPTER_MD5=\"${COEX_ADAPTER_MD5}\")
add_custom_target(esp32_test_logo DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/test_tjpgd_logo.h")

View File

@@ -16,6 +16,9 @@ CFLAGS+=-DWIFI_OS_ADAPTER_MD5=$(WIFI_OS_ADAPTER_MD5_VAL)
WIFI_CRYPTO_MD5_VAL=\"$(shell md5sum $(IDF_PATH)/components/esp32/include/esp_wifi_crypto_types.h | cut -c 1-7)\"
CFLAGS+=-DWIFI_CRYPTO_MD5=$(WIFI_CRYPTO_MD5_VAL)
# Calculate MD5 value of header file esp_coexist_adapter.h
COEX_ADAPTER_MD5_VAL=\"$(shell md5sum $(IDF_PATH)/components/esp32/include/esp_coexist_adapter.h | cut -c 1-7)\"
CFLAGS+=-DCOEX_ADAPTER_MD5=$(COEX_ADAPTER_MD5_VAL)
test_tjpgd.o: test_tjpgd_logo.h

View File

@@ -4,6 +4,7 @@
#include "unity.h"
#include "esp_log.h"
#include "esp_wifi_internal.h"
#include "esp_coexist_internal.h"
static const char* TAG = "test_header_files_md5";
@@ -26,3 +27,13 @@ TEST_CASE("wifi crypto types MD5","[wifi]")
ESP_LOGI(TAG, "test passed...");
}
TEST_CASE("coexist adapter MD5","[coex]")
{
const char *test_coex_adapter_funcs_md5 = COEX_ADAPTER_MD5;
ESP_LOGI(TAG, "test coexist adapter MD5...");
TEST_ESP_OK(esp_coex_adapter_funcs_md5_check(test_coex_adapter_funcs_md5));
ESP_LOGI(TAG, "test passed...");
}

View File

@@ -27,6 +27,9 @@ mesh_event_cb_t g_mesh_event_cb = NULL;
static esp_pm_lock_handle_t s_wifi_modem_sleep_lock;
#endif
/* Callback function to update WiFi MAC time */
wifi_mac_time_update_cb_t s_wifi_mac_time_update_cb = NULL;
static void __attribute__((constructor)) s_set_default_wifi_log_level()
{
/* WiFi libraries aren't compiled to know CONFIG_LOG_DEFAULT_LEVEL,
@@ -97,7 +100,10 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config)
#endif
esp_event_set_default_wifi_handlers();
esp_err_t result = esp_wifi_init_internal(config);
esp_wifi_set_debug_log();
if (result == ESP_OK) {
esp_wifi_set_debug_log();
s_wifi_mac_time_update_cb = esp_wifi_internal_update_mac_time;
}
return result;
}

View File

@@ -487,7 +487,9 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co
goto error;
}
if (config->cert_pem) {
if (config->use_global_ca_store == true) {
esp_transport_ssl_enable_global_ca_store(ssl);
} else if (config->cert_pem) {
esp_transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem));
}

View File

@@ -117,6 +117,7 @@ typedef struct {
int buffer_size; /*!< HTTP buffer size (both send and receive) */
void *user_data; /*!< HTTP user_data context */
bool is_async; /*!< Set asynchronous mode, only supported with HTTPS for now */
bool use_global_ca_store; /*!< Use a global ca_store for all the connections in which this bool is set. */
} esp_http_client_config_t;

View File

@@ -362,6 +362,18 @@ typedef struct httpd_req {
* function for freeing the session context, please specify that here.
*/
httpd_free_ctx_fn_t free_ctx;
/**
* Flag indicating if Session Context changes should be ignored
*
* By default, if you change the sess_ctx in some URI handler, the http server
* will internally free the earlier context (if non NULL), after the URI handler
* returns. If you want to manage the allocation/reallocation/freeing of
* sess_ctx yourself, set this flag to true, so that the server will not
* perform any checks on it. The context will be cleared by the server
* (by calling free_ctx or free()) only if the socket gets closed.
*/
bool ignore_sess_ctx_changes;
} httpd_req_t;
/**

View File

@@ -60,6 +60,7 @@ struct thread_data {
struct sock_db {
int fd; /*!< The file descriptor for this socket */
void *ctx; /*!< A custom context for this socket */
bool ignore_sess_ctx_changes; /*!< Flag indicating if session context changes should be ignored */
void *transport_ctx; /*!< A custom 'transport' context for this socket, to be used by send/recv/pending */
httpd_handle_t handle; /*!< Server handle */
httpd_free_ctx_fn_t free_ctx; /*!< Function for freeing the context */

View File

@@ -588,6 +588,7 @@ static void init_req(httpd_req_t *r, httpd_config_t *config)
r->user_ctx = 0;
r->sess_ctx = 0;
r->free_ctx = 0;
r->ignore_sess_ctx_changes = 0;
}
static void init_req_aux(struct httpd_req_aux *ra, httpd_config_t *config)
@@ -607,13 +608,14 @@ static void httpd_req_cleanup(httpd_req_t *r)
{
struct httpd_req_aux *ra = r->aux;
/* Retrieve session info from the request into the socket database */
if (ra->sd->ctx != r->sess_ctx) {
/* Free previous context */
/* Check if the context has changed and needs to be cleared */
if ((r->ignore_sess_ctx_changes == false) && (ra->sd->ctx != r->sess_ctx)) {
httpd_sess_free_ctx(ra->sd->ctx, ra->sd->free_ctx);
ra->sd->ctx = r->sess_ctx;
}
/* Retrieve session info from the request into the socket database. */
ra->sd->ctx = r->sess_ctx;
ra->sd->free_ctx = r->free_ctx;
ra->sd->ignore_sess_ctx_changes = r->ignore_sess_ctx_changes;
/* Clear out the request and request_aux structures */
ra->sd = NULL;
@@ -641,6 +643,7 @@ esp_err_t httpd_req_new(struct httpd_data *hd, struct sock_db *sd)
/* Copy session info to the request */
r->sess_ctx = sd->ctx;
r->free_ctx = sd->free_ctx;
r->ignore_sess_ctx_changes = sd->ignore_sess_ctx_changes;
/* Parse request */
esp_err_t err = httpd_parse_req(hd);
if (err != ESP_OK) {

View File

@@ -36,8 +36,8 @@ esp_err_t esp_https_ota(const esp_http_client_config_t *config)
}
#if !CONFIG_OTA_ALLOW_HTTP
if (!config->cert_pem) {
ESP_LOGE(TAG, "Server certificate not found in esp_http_client config");
if (!config->cert_pem && !config->use_global_ca_store) {
ESP_LOGE(TAG, "Server certificate not found, either through configuration or global CA store");
return ESP_ERR_INVALID_ARG;
}
#endif

View File

@@ -14,6 +14,10 @@
#ifndef ESP_CORE_DUMP_H_
#define ESP_CORE_DUMP_H_
#include <stddef.h>
#include "esp_err.h"
#include "freertos/xtensa_context.h"
/**************************************************************************************/
/******************************** EXCEPTION MODE API **********************************/
/**************************************************************************************/
@@ -54,7 +58,7 @@ void esp_core_dump_init();
* 4) Task's stack is placed after TCB data. Size is (STACK_END - STACK_TOP) bytes.
* 5) CRC is placed at the end of the data.
*/
void esp_core_dump_to_flash();
void esp_core_dump_to_flash(XtExcFrame *frame);
/**
* @brief Print base64-encoded core dump to UART.
@@ -64,7 +68,7 @@ void esp_core_dump_to_flash();
* 2) Since CRC is omitted TOTAL_LEN does not include its size.
* 3) Printed base64 data are surrounded with special messages to help user recognize the start and end of actual data.
*/
void esp_core_dump_to_uart();
void esp_core_dump_to_uart(XtExcFrame *frame);
/**************************************************************************************/

View File

@@ -3,4 +3,5 @@ archive: libespcoredump.a
entries:
core_dump_uart (noflash_text)
core_dump_flash (noflash_text)
core_dump_common (noflash_text)
core_dump_common (noflash_text)
core_dump_port (noflash_text)

View File

@@ -5,9 +5,9 @@ endif()
# Set some global esptool.py variables
#
# Many of these are read when generating flash_app_args & flash_project_args
set(ESPTOOLPY "${CMAKE_CURRENT_LIST_DIR}/esptool/esptool.py" --chip esp32)
set(ESPSECUREPY "${CMAKE_CURRENT_LIST_DIR}/esptool/espsecure.py")
set(ESPEFUSEPY "${CMAKE_CURRENT_LIST_DIR}/esptool/espefuse.py")
set(ESPTOOLPY ${PYTHON} "${CMAKE_CURRENT_LIST_DIR}/esptool/esptool.py" --chip esp32)
set(ESPSECUREPY ${PYTHON} "${CMAKE_CURRENT_LIST_DIR}/esptool/espsecure.py")
set(ESPEFUSEPY ${PYTHON} "${CMAKE_CURRENT_LIST_DIR}/esptool/espefuse.py")
set(ESPFLASHMODE ${CONFIG_ESPTOOLPY_FLASHMODE})
set(ESPFLASHFREQ ${CONFIG_ESPTOOLPY_FLASHFREQ})

View File

@@ -60,8 +60,11 @@
#define MB_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux)
#define MB_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux)
#define ENTER_CRITICAL_SECTION( ) ( vMBPortEnterCritical() )
#define EXIT_CRITICAL_SECTION( ) ( vMBPortExitCritical() )
#define ENTER_CRITICAL_SECTION( ) { ESP_LOGD(MB_PORT_TAG,"%s: Port enter critical.", __func__); \
vMBPortEnterCritical(); }
#define EXIT_CRITICAL_SECTION( ) { vMBPortExitCritical(); \
ESP_LOGD(MB_PORT_TAG,"%s: Port exit critical", __func__); }
typedef char BOOL;

View File

@@ -32,16 +32,16 @@
#include <stdlib.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/semphr.h>
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
#include "sys/lock.h"
/* ----------------------- Modbus includes ----------------------------------*/
/* ----------------------- Variables ----------------------------------------*/
static portMUX_TYPE mb_mutex = portMUX_INITIALIZER_UNLOCKED;
static _lock_t s_port_lock;
/* ----------------------- Start implementation -----------------------------*/
@@ -52,16 +52,16 @@ bMBPortIsWithinException( void )
return bIsWithinException;
}
void
inline void
vMBPortEnterCritical( void )
{
portENTER_CRITICAL(&mb_mutex);
_lock_acquire(&s_port_lock);
}
void
inline void
vMBPortExitCritical( void )
{
portEXIT_CRITICAL(&mb_mutex);
_lock_release(&s_port_lock);
}
void

View File

@@ -74,7 +74,6 @@ static USHORT uiRxBufferPos = 0; // position in the receiver buffer
void vMBPortSerialEnable(BOOL bRxEnable, BOOL bTxEnable)
{
// This function can be called from xMBRTUTransmitFSM() of different task
ENTER_CRITICAL_SECTION();
if (bRxEnable) {
//uart_enable_rx_intr(ucUartNumber);
bRxStateEnabled = TRUE;
@@ -88,7 +87,6 @@ void vMBPortSerialEnable(BOOL bRxEnable, BOOL bTxEnable)
} else {
bTxStateEnabled = FALSE;
}
EXIT_CRITICAL_SECTION();
}
static void vMBPortSerialRxPoll(size_t xEventSize)

View File

@@ -282,7 +282,7 @@ inline static uint32_t get_ccount(void)
if (!esp_ptr_executable(callers[N])) { \
return; \
} \
} while(0);
} while(0)
/* Static function to read the call stack for a traced heap call.

View File

@@ -475,7 +475,9 @@ static void send_offer(struct dhcps_msg *m, u16_t len)
u8_t *data;
u16_t cnt = 0;
u16_t i;
#if DHCPS_DEBUG
err_t SendOffer_err_t;
#endif
create_msg(m);
end = add_msg_type(&m->options[4], DHCPOFFER);
@@ -523,8 +525,12 @@ static void send_offer(struct dhcps_msg *m, u16_t len)
ip_addr_t ip_temp = IPADDR4_INIT(0x0);
ip4_addr_set(ip_2_ip4(&ip_temp), &broadcast_dhcps);
#if DHCPS_DEBUG
SendOffer_err_t = udp_sendto(pcb_dhcps, p, &ip_temp, DHCPS_CLIENT_PORT);
DHCPS_LOG("dhcps: send_offer>>udp_sendto result %x\n", SendOffer_err_t);
#else
udp_sendto(pcb_dhcps, p, &ip_temp, DHCPS_CLIENT_PORT);
#endif
if (p->ref != 0) {
#if DHCPS_DEBUG

View File

@@ -3074,7 +3074,7 @@ static void _mdns_search_free(mdns_search_once_t * search)
free(search->instance);
free(search->service);
free(search->proto);
vSemaphoreDelete(search->lock);
vSemaphoreDelete(search->done_semaphore);
free(search);
}
@@ -3090,8 +3090,8 @@ static mdns_search_once_t * _mdns_search_init(const char * name, const char * se
}
memset(search, 0, sizeof(mdns_search_once_t));
search->lock = xSemaphoreCreateMutex();
if (!search->lock) {
search->done_semaphore = xSemaphoreCreateBinary();
if (!search->done_semaphore) {
free(search);
return NULL;
}
@@ -3130,8 +3130,6 @@ static mdns_search_once_t * _mdns_search_init(const char * name, const char * se
search->started_at = xTaskGetTickCount() * portTICK_PERIOD_MS;
search->next = NULL;
xSemaphoreTake(search->lock, 0);
return search;
}
@@ -3142,7 +3140,7 @@ static void _mdns_search_finish(mdns_search_once_t * search)
{
search->state = SEARCH_OFF;
queueDetach(mdns_search_once_t, _mdns_server->search_once, search);
xSemaphoreGive(search->lock);
xSemaphoreGive(search->done_semaphore);
}
/**
@@ -4148,7 +4146,7 @@ void mdns_free()
free(h->instance);
free(h->service);
free(h->proto);
vSemaphoreDelete(h->lock);
vSemaphoreDelete(h->done_semaphore);
if (h->result) {
mdns_query_results_free(h->result);
}
@@ -4543,7 +4541,7 @@ esp_err_t mdns_query(const char * name, const char * service, const char * proto
_mdns_search_free(search);
return ESP_ERR_NO_MEM;
}
xSemaphoreTake(search->lock, portMAX_DELAY);
xSemaphoreTake(search->done_semaphore, portMAX_DELAY);
*results = search->result;
_mdns_search_free(search);

View File

@@ -115,9 +115,6 @@
#define PCB_STATE_IS_ANNOUNCING(s) (s->state > PCB_PROBE_3 && s->state < PCB_RUNNING)
#define PCB_STATE_IS_RUNNING(s) (s->state == PCB_RUNNING)
#define MDNS_SEARCH_LOCK() xSemaphoreTake(_mdns_server->search.lock, portMAX_DELAY)
#define MDNS_SEARCH_UNLOCK() xSemaphoreGive(_mdns_server->search.lock)
#ifndef HOOK_MALLOC_FAILED
#define HOOK_MALLOC_FAILED ESP_LOGE(TAG, "Cannot allocate memory (line: %d, free heap: %d bytes)", __LINE__, esp_get_free_heap_size());
#endif
@@ -318,7 +315,7 @@ typedef struct mdns_search_once_s {
uint32_t started_at;
uint32_t sent_at;
uint32_t timeout;
SemaphoreHandle_t lock;
SemaphoreHandle_t done_semaphore;
uint16_t type;
uint8_t max_results;
uint8_t num_results;

View File

@@ -40,6 +40,13 @@ esp_transport_handle_t esp_transport_ssl_init();
*/
void esp_transport_ssl_set_cert_data(esp_transport_handle_t t, const char *data, int len);
/**
* @brief Enable global CA store for SSL connection
*
* @param t ssl transport
*/
void esp_transport_ssl_enable_global_ca_store(esp_transport_handle_t t);
/**
* @brief Set SSL client certificate data for mutual authentication (as PEM format).
* Note that, this function stores the pointer to data, rather than making a copy.

View File

@@ -155,6 +155,14 @@ static int ssl_destroy(esp_transport_handle_t t)
return 0;
}
void esp_transport_ssl_enable_global_ca_store(esp_transport_handle_t t)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
if (t && ssl) {
ssl->cfg.use_global_ca_store = true;
}
}
void esp_transport_ssl_set_cert_data(esp_transport_handle_t t, const char *data, int len)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);

View File

@@ -91,7 +91,9 @@ static void tcpip_adapter_dhcps_cb(u8_t client_ip[4])
ESP_LOGI(TAG,"softAP assign IP to station,IP is: %d.%d.%d.%d",
client_ip[0],client_ip[1],client_ip[2],client_ip[3]);
system_event_t evt;
memset(&evt, 0, sizeof(system_event_t));
evt.event_id = SYSTEM_EVENT_AP_STAIPASSIGNED;
memcpy((char *)&evt.event_info.ap_staipassigned.ip.addr, (char *)client_ip, sizeof(evt.event_info.ap_staipassigned.ip.addr));
esp_event_send(&evt);
}
@@ -429,6 +431,7 @@ esp_err_t tcpip_adapter_set_ip_info(tcpip_adapter_if_t tcpip_if, const tcpip_ada
if (tcpip_if == TCPIP_ADAPTER_IF_STA || tcpip_if == TCPIP_ADAPTER_IF_ETH) {
if (!(ip4_addr_isany_val(ip_info->ip) || ip4_addr_isany_val(ip_info->netmask) || ip4_addr_isany_val(ip_info->gw))) {
system_event_t evt;
memset(&evt, 0, sizeof(system_event_t));
if (tcpip_if == TCPIP_ADAPTER_IF_STA) {
evt.event_id = SYSTEM_EVENT_STA_GOT_IP;
} else if (tcpip_if == TCPIP_ADAPTER_IF_ETH) {
@@ -461,6 +464,7 @@ static void tcpip_adapter_nd6_cb(struct netif *p_netif, uint8_t ip_idex)
tcpip_adapter_ip6_info_t *ip6_info;
system_event_t evt;
memset(&evt, 0, sizeof(system_event_t));
//notify event
evt.event_id = SYSTEM_EVENT_GOT_IP6;
@@ -896,6 +900,7 @@ static void tcpip_adapter_dhcpc_cb(struct netif *netif)
!ip4_addr_cmp(ip_2_ip4(&netif->netmask), (&ip_info->netmask)) ||
!ip4_addr_cmp(ip_2_ip4(&netif->gw), (&ip_info->gw)) ) {
system_event_t evt;
memset(&evt, 0, sizeof(system_event_t));
ip4_addr_set(&ip_info->ip, ip_2_ip4(&netif->ip_addr));
ip4_addr_set(&ip_info->netmask, ip_2_ip4(&netif->netmask));
@@ -971,6 +976,7 @@ static void tcpip_adapter_ip_lost_timer(void *arg)
if ( (!netif) || (netif && ip4_addr_cmp(ip_2_ip4(&netif->ip_addr), IP4_ADDR_ANY4))){
system_event_t evt;
memset(&evt, 0, sizeof(system_event_t));
ESP_LOGD(TAG, "if%d ip lost tmr: raise ip lost event", tcpip_if);
memset(&esp_ip_old[tcpip_if], 0, sizeof(tcpip_adapter_ip_info_t));

View File

@@ -28,7 +28,7 @@ if(NOT as_version STREQUAL as_supported_version)
the toolchain, or proceed at your own risk.")
endif()
set(ULP_MAP_GEN ${IDF_PATH}/components/ulp/esp32ulp_mapgen.py)
set(ULP_MAP_GEN ${PYTHON} ${IDF_PATH}/components/ulp/esp32ulp_mapgen.py)
set(ULP_LD_TEMPLATE ${IDF_PATH}/components/ulp/ld/esp32.ulp.ld)
get_filename_component(sdkconfig_dir ${SDKCONFIG} DIRECTORY)

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

View File

@@ -18,8 +18,7 @@ fi
# the Sphinx warning log
# (escape char removal from https://www.commandlinefu.com/commands/view/6141/remove-color-codes-special-characters-with-sed
sed -r 's:\x1B\[[0-9;]*[mK]::g' sphinx-warning-log.txt | \
sed -E "s~${IDF_PATH}~\${IDF_PATH}~" | \
sed -E "s/:[0-9]+:/:line:/" > sphinx-warning-log-sanitized.txt
sed -E "s/.*\/(.*):[0-9]+:/\1:line:/" > sphinx-warning-log-sanitized.txt
# diff sanitized warnings, ignoring lines which only appear in ../sphinx-known-warnings.txt

View File

@@ -1,6 +1,7 @@
Build System (CMake)
********************
:link_to_translation:`zh_CN:[中文]`
.. include:: ../cmake-warning.rst
.. include:: ../cmake-pending-features.rst
@@ -161,7 +162,7 @@ When adding custom non-build steps like "flash" to the IDE, it is recommended to
For more detailed information about integrating ESP-IDF with CMake into an IDE, see `Build System Metadata`_.
.. setting-python-interpreter:
.. _setting-python-interpreter:
Setting the Python Interpreter
------------------------------
@@ -232,7 +233,6 @@ Minimal Example CMakeLists
Minimal project::
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(myProject)
@@ -242,9 +242,9 @@ Minimal project::
Mandatory Parts
---------------
The inclusion of these four lines, in the order shown above, is necessary for every project:
The inclusion of these three lines, in the order shown above, is necessary for every project:
- ``cmake_minimum_required(VERSION 3.5)`` tells CMake what version is required to build the project. ESP-IDF is designed to work with CMake 3.5 or newer. This line must be the first line in the CMakeLists.txt file.
- ``cmake_minimum_required(VERSION 3.5)`` tells CMake the minimum version that is required to build the project. ESP-IDF is designed to work with CMake 3.5 or newer. This line must be the first line in the CMakeLists.txt file.
- ``include($ENV{IDF_PATH}/tools/cmake/project.cmake)`` pulls in the rest of the CMake functionality to configure the project, discover all the components, etc.
- ``project(myProject)`` creates the project itself, and specifies the project name. The project name is used for the final binary output files of the app - ie ``myProject.elf``, ``myProject.bin``. Only one project can be defined per CMakeLists file.
@@ -330,22 +330,22 @@ Preset Component Variables
The following component-specific variables are available for use inside component CMakeLists, but should not be modified:
- ``COMPONENT_PATH``: The component directory. Evaluates to the absolute path of the directory containing ``component.mk``. The component path cannot contain spaces. This is the same as the ``CMAKE_CURRENT_SOURCE_DIR`` variable.
- ``COMPONENT_PATH``: The component directory. Evaluates to the absolute path of the directory containing ``CMakeLists.txt``. The component path cannot contain spaces. This is the same as the ``CMAKE_CURRENT_SOURCE_DIR`` variable.
- ``COMPONENT_NAME``: Name of the component. Same as the name of the component directory.
- ``COMPONENT_TARGET``: Name of the library target created internally by the build system for the component.
The following variables are set at the project level, but available for use in component CMakeLists:
- ``PROJECT_NAME``: Name of the project, as set in project CMakeLists.txt file.
- ``PROJECT_PATH``: Absolute path of the project directory containing the project Makefile. Same as the ``CMAKE_SOURCE_DIR`` variable.
- ``PROJECT_PATH``: Absolute path of the project directory containing the project CMakeLists. Same as the ``CMAKE_SOURCE_DIR`` variable.
- ``COMPONENTS``: Names of all components that are included in this build, formatted as a semicolon-delimited CMake list.
- ``CONFIG_*``: Each value in the project configuration has a corresponding variable available in make. All names begin with ``CONFIG_``. :doc:`More information here </api-reference/kconfig>`.
- ``CONFIG_*``: Each value in the project configuration has a corresponding variable available in cmake. All names begin with ``CONFIG_``. :doc:`More information here </api-reference/kconfig>`.
- ``IDF_VER``: Git version of ESP-IDF (produced by ``git describe``)
- ``IDF_TARGET``: Name of the target for which the project is being built.
- ``PROJECT_VER``: Project version.
* If ``PROJECT_VER`` variable set in project CMakeLists.txt file, its value will be used.
* Else, if the ``$PROJECT_PATH/version.txt`` exists, its contents will be used as ``PROJECT_VER``.
* If ``PROJECT_VER`` variable is set in project CMakeLists.txt file, its value will be used.
* Else, if the ``$(PROJECT_PATH}/version.txt`` exists, its contents will be used as ``PROJECT_VER``.
* Else, if the project is located inside a Git repository, the output of git describe will be used.
* Otherwise, ``PROJECT_VER`` will be "1".
@@ -367,7 +367,7 @@ If you modify any of these variables inside ``CMakeLists.txt`` then this will no
Optional Component-Specific Variables
-------------------------------------
The following variables can be set inside ``component.mk`` to control the build of that component:
The following variables can be set inside ``CMakeLists.txt`` to control the build of that component:
- ``COMPONENT_PRIV_INCLUDEDIRS``: Directory paths, must be relative to
the component directory, which will be added to the include search
@@ -426,10 +426,8 @@ Preprocessor Definitions
The ESP-IDF build system adds the following C preprocessor definitions on the command line:
- ``ESP_PLATFORM`` Can be used to detect that build happens within ESP-IDF.
- ``IDF_VER`` Defined to a git version string. E.g. ``v2.0`` for a tagged release or ``v1.0-275-g0efaa4f`` for an arbitrary commit.
- ``PROJECT_VER``: The project version, see `Preset Component Variables`_ for more details.
- ``PROJECT_NAME``: Name of the project, as set in project CMakeLists.txt file.
- ``ESP_PLATFORM`` : Can be used to detect that build happens within ESP-IDF.
- ``IDF_VER`` : Defined to a git version string. E.g. ``v2.0`` for a tagged release or ``v1.0-275-g0efaa4f`` for an arbitrary commit.
Component Requirements
======================
@@ -458,6 +456,7 @@ When creating a project
- By default, every component is included in the build.
- If you set the ``COMPONENTS`` variable to a minimal list of components used directly by your project, then the build will include:
- Components mentioned explicitly in ``COMPONENTS``.
- Those components' requirements (evaluated recursively).
- The "common" components that every component depends on.
@@ -600,9 +599,9 @@ depending on the options selected in the project configuration.
if(CONFIG_FOO_ENABLE_BAR)
list(APPEND COMPONENT_SRCS "bar.c")
endif(CONFIG_FOO_ENABLE_BAR)
endif()
This example makes use of the CMake `if function <cmake if_>`_ and `list APPEND <cmake list_>`_ function.
This example makes use of the CMake `if <cmake if_>`_ function and `list APPEND <cmake list_>`_ function.
This can also be used to select or stub out an implementation, as such:
@@ -722,8 +721,8 @@ For an example of using this technique, see :example:`protocols/https_request` -
Code and Data Placements
------------------------
ESP-IDF has a feature called linker script generation that enables components to define where its code and data will be placed in memory through
linker fragment files. These files are processed by the build system, and is used to augment the linker script used for linking
ESP-IDF has a feature called linker script generation that enables components to define where its code and data will be placed in memory through
linker fragment files. These files are processed by the build system, and is used to augment the linker script used for linking
app binary. See :doc:`Linker Script Generation <linker-script-generation>` for a quick start guide as well as a detailed discussion
of the mechanism.
@@ -767,7 +766,7 @@ the ESP-IDF build system entirely by using a CMake feature called ExternalProjec
(The above CMakeLists.txt can be used to create a component named ``quirc`` that builds the quirc_ project using its own Makefile.)
- ``externalproject_add`` defines an external build system.
- ``SOURCE_DIR``, ``CONFIGURE_COMMAND``, ``BUILD_COMMAND`` and ``INSTALL_COMMAND`` should always be set. ``CONFIGURE_COMMAND`` can be set to an empty string if the build system has no "configure" step. ``INSTALL_COMMAND`` will generally be empty for ESP-IDF builds.
- Setting ``BUILD_IN_SOURCE`` means the build directory is the same as the source directory. Otherwise you can set ``BUILD_DIR``.
- Consult the ExternalProject_ documentation for more details about ``externalproject_add()``
@@ -875,7 +874,7 @@ Using Third-Party CMake Projects with Components
================================================
CMake is used for a lot of open-source C and C++ projects — code that users can tap into for their applications. One of the benefits of having a CMake build system
is the ability to import these third-party projects, sometimes even without modification! This allows for users to be able to get functionality that may
is the ability to import these third-party projects, sometimes even without modification! This allows for users to be able to get functionality that may
not yet be provided by a component, or use another library for the same functionality.
.. highlight:: cmake
@@ -888,7 +887,7 @@ Importing a library might look like this for a hypothetical library ``foo`` to b
# Set values of hypothetical variables that control the build of `foo`
set(FOO_BUILD_STATIC OFF)
set(FOO_BUILD_TESTS OFF)
# Create and import the library targets
add_subdirectory(foo)
@@ -904,7 +903,7 @@ For an actual example, take a look at :example:`build_system/cmake/import_lib`.
the library may vary. It is recommended to read up on the library's documentation for instructions on how to
import it from other projects. Studying the library's CMakeLists.txt and build structure can also be helpful.
It is also possible to wrap a third-party library to be used as a component in this manner. For example, the :component:`mbedtls` component is a wrapper for
It is also possible to wrap a third-party library to be used as a component in this manner. For example, the :component:`mbedtls` component is a wrapper for
Espressif's fork of `mbedtls <https://github.com/ARMmbed/mbedtls>`_. See its :component_file:`component CMakeLists.txt <mbedtls/CMakeLists.txt>`.
The CMake variable ``ESP_PLATFORM`` is set to 1 whenever the ESP-IDF build system is being used. Tests such as ``if (ESP_PLATFORM)`` can be used in generic CMake code if special IDF-specific logic is required.
@@ -915,7 +914,7 @@ Using ESP-IDF in Custom CMake Projects
ESP-IDF provides a template CMake project for easily creating an application. However, in some instances the user might already
have an existing CMake project or may want to create one. In these cases it is desirable to be able to consume IDF components
as libraries to be linked to the user's targets (libraries/ executables).
as libraries to be linked to the user's targets (libraries/ executables).
.. highlight:: cmake
@@ -957,7 +956,7 @@ parameters which can be set, the full list of which is as follows:
- ``IDF_COMPONENT_REQUIRES_COMMON``: List of components that every component requires. Components in this list (and their dependencies) are imported regardless of the value of ``IDF_COMPONENTS``. By default, this variable is set to the minimal set of core "system" components.
- ``IDF_SDKCONFIG_DEFAULTS``: Path to the configuration override file. If unset, components are built with default configurations.
- ``IDF_BUILD_TESTS``: Include component tests in the build. By default, all component tests are included. The component tests are filtered using ``IDF_TEST_COMPONENTS`` and ``IDF_TEST_EXCLUDE_COMPONENTS``.
- ``IDF_TEST_COMPONENTS``: If ``IDF_BUILD_TESTS`` is set, only component tests in this list will be included in the build. Ignored if ``IDF_BUILD_TESTS`` is not set.
- ``IDF_TEST_COMPONENTS``: If ``IDF_BUILD_TESTS`` is set, only component tests in this list will be included in the build. Ignored if ``IDF_BUILD_TESTS`` is not set.
- ``IDF_TEST_EXCLUDE_COMPONENTS``: If ``IDF_BUILD_TESTS`` is set, component tests in this list will not be included in the build. Ignored if ``IDF_BUILD_TESTS`` is not set. This variable takes precedence over ``IDF_TEST_COMPONENTS``. This means that a component test in this list will not be included in the build even if it is also present in ``IDF_TEST_COMPONENTS``.
The example in :example:`build_system/cmake/idf_as_lib` demonstrates the creation of an application equivalent to :example:`hello world application <get-started/hello_world>`
@@ -980,7 +979,7 @@ This preference reflects the `CMake best practice <https://gist.github.com/mbinn
set(COMPONENT_SRCDIRS library platform)
This uses globbing behind the scenes to find source files in the specified directories. Be aware, however, that if a new source file is added and this method is used, then CMake won't know to automatically re-run and this file won't be added to the build.
This uses globbing behind the scenes to find source files in the specified directories. Be aware, however, that if a new source file is added and this method is used, then CMake won't know to automatically re-run and this file won't be added to the build.
The trade-off is acceptable when you're adding the file yourself, because you can trigger a clean build or run ``idf.py reconfigure`` to manually re-run CMake_. However, the problem gets harder when you share your project with others who may check out a new version using a source control tool like Git...
@@ -1127,7 +1126,7 @@ Flashing from make
.. _esptool.py: https://github.com/espressif/esptool/#readme
.. _CMake v3.5 documentation: https://cmake.org/cmake/help/v3.5/index.html
.. _cmake command line documentation: https://cmake.org/cmake/help/v3.5/manual/cmake.1.html#options
.. _cmake add_library: https://cmake.org/cmake/help/v3.5/command/project.html
.. _cmake add_library: https://cmake.org/cmake/help/v3.5/command/add_library.html
.. _cmake if: https://cmake.org/cmake/help/v3.5/command/if.html
.. _cmake list: https://cmake.org/cmake/help/v3.5/command/list.html
.. _cmake project: https://cmake.org/cmake/help/v3.5/command/project.html
@@ -1144,4 +1143,3 @@ Flashing from make
.. _quirc: https://github.com/dlbeer/quirc
.. _pyenv: https://github.com/pyenv/pyenv#README
.. _virtualenv: https://virtualenv.pypa.io/en/stable/

View File

@@ -190,10 +190,10 @@ The following variables are set at the project level, but exported for use in th
- ``IDF_VER``: ESP-IDF version, retrieved from either ``$(IDF_PATH)/version.txt`` file (if present) else using git command ``git describe``. Recommended format here is single liner that specifies major IDF release version, e.g. ``v2.0`` for a tagged release or ``v2.0-275-g0efaa4f`` for an arbitrary commit. Application can make use of this by calling :cpp:func:`esp_get_idf_version`.
- ``PROJECT_VER``: Project version.
* If ``PROJECT_VER`` variable set in project Makefile file, its value will be used.
* Else, if the ``$PROJECT_PATH/version.txt`` exists, its contents will be used as ``PROJECT_VER``.
* Else, if the project is located inside a Git repository, the output of git describe will be used.
* Otherwise, ``PROJECT_VER`` will be "1".
* If ``PROJECT_VER`` variable is set in project Makefile file, its value will be used.
* Else, if the ``$PROJECT_PATH/version.txt`` exists, its contents will be used as ``PROJECT_VER``.
* Else, if the project is located inside a Git repository, the output of git describe will be used.
* Otherwise, ``PROJECT_VER`` will be "1".
If you modify any of these variables inside ``component.mk`` then this will not prevent other components from building but it may make your component hard to build and/or debug.
@@ -309,8 +309,6 @@ ESP-IDF build systems adds the following C preprocessor definitions on the comma
- ``ESP_PLATFORM`` — Can be used to detect that build happens within ESP-IDF.
- ``IDF_VER`` — ESP-IDF version, see `Preset Component Variables`_ for more details.
- ``PROJECT_VER``: The project version, see `Preset Component Variables`_ for more details.
- ``PROJECT_NAME``: Name of the project, as set in project Makefile.
Build Process Internals
-----------------------

View File

@@ -32,7 +32,7 @@ Using these symbols is done by creating an assembly file (suffix .S) and definin
rfi 5
For a real-life example, see the components/esp32/panic_highint_hdl.S file; the panic handler iunterrupt is implemented there.
For a real-life example, see the :component_file:`esp32/dport_panic_highint_hdl.S` file; the panic handler interrupt is implemented there.
Notes
-----

View File

@@ -1,8 +1,9 @@
***************************************
Building OpenOCD from Sources for Linux
***************************************
:link_to_translation:`zh_CN:[中文]`
The following instructions are alternative to downloading binary OpenOCD from Espressif website. To quickly setup the binary OpenOCD, instead of compiling it yourself, backup and proceed to section :doc:`setup-openocd-linux`.
The following instructions are alternative to downloading binary OpenOCD from `Espressif GitHub <https://github.com/espressif/openocd-esp32/releases>`_. To quickly setup the binary OpenOCD, instead of compiling it yourself, backup and proceed to section :doc:`setup-openocd-linux`.
.. highlight:: bash

View File

@@ -1,8 +1,9 @@
***************************************
Building OpenOCD from Sources for MacOS
***************************************
:link_to_translation:`zh_CN:[中文]`
The following instructions are alternative to downloading binary OpenOCD from Espressif website. To quickly setup the binary OpenOCD, instead of compiling it yourself, backup and proceed to section :doc:`setup-openocd-macos`.
The following instructions are alternative to downloading binary OpenOCD from `Espressif GitHub <https://github.com/espressif/openocd-esp32/releases>`_. To quickly setup the binary OpenOCD, instead of compiling it yourself, backup and proceed to section :doc:`setup-openocd-macos`.
.. highlight:: bash
@@ -22,7 +23,7 @@ Install Dependencies
Install packages that are required to compile OpenOCD using Homebrew::
brew install automake libtool libusb wget gcc@4.9 pkg-config
brew install automake libtool libusb wget gcc@4.9 pkg-config
Build OpenOCD
=============
@@ -51,4 +52,4 @@ Next Steps
To carry on with debugging environment setup, proceed to section :ref:`jtag-debugging-configuring-esp32-target`.

View File

@@ -1,8 +1,9 @@
*****************************************
Building OpenOCD from Sources for Windows
*****************************************
:link_to_translation:`zh_CN:[中文]`
The following instructions are alternative to downloading binary OpenOCD from Espressif website. To quickly setup the binary OpenOCD, instead of compiling it yourself, backup and proceed to section :doc:`setup-openocd-windows`.
The following instructions are alternative to downloading binary OpenOCD from `Espressif GitHub <https://github.com/espressif/openocd-esp32/releases>`_. To quickly setup the binary OpenOCD, instead of compiling it yourself, backup and proceed to section :doc:`setup-openocd-windows`.
.. highlight:: bash
@@ -29,16 +30,16 @@ Install packages that are required to compile OpenOCD:
::
pacman -S libtool
pacman -S autoconf
pacman -S automake
pacman -S texinfo
pacman -S mingw-w64-i686-libusb-compat-git
pacman -S pkg-config
pacman -S libtool
pacman -S autoconf
pacman -S automake
pacman -S texinfo
pacman -S mingw-w64-i686-libusb-compat-git
pacman -S pkg-config
.. note::
Installation of ``pkg-config`` is breaking operation of esp-idf toolchain. After building of OpenOCD it should be uninstalled. It be covered at the end of this instruction. To build OpenOCD again, you will need to run ``pacman -S pkg-config`` once more. This issue does not concern other packages installed in this step (before ``pkg-config``).
Installation of ``pkg-config`` is breaking operation of esp-idf toolchain. After building of OpenOCD it should be uninstalled. It be covered at the end of this instruction. To build OpenOCD again, you will need to run ``pacman -S pkg-config`` once more. This issue does not concern other packages installed in this step (before ``pkg-config``).
Build OpenOCD
@@ -65,7 +66,7 @@ Once ``make`` process is successfully completed, the executable of OpenOCD will
Remove ``pkg-config``, as discussed during installation of dependencies::
pacman -Rs pkg-config
pacman -Rs pkg-config
Next Steps

View File

@@ -1,5 +1,6 @@
Configure Other JTAG Interface
==============================
:link_to_translation:`zh_CN:[中文]`
Refer to section :ref:`jtag-debugging-selecting-jtag-adapter` for guidance what JTAG interface to select, so it is able to operate with OpenOCD and ESP32. Then follow three configuration steps below to get it working.

View File

@@ -1,7 +1,8 @@
Configure WROVER JTAG Interface
===============================
:link_to_translation:`zh_CN:[中文]`
All versions of ESP32 WROVER KIT boards have JTAG functionality build in. Putting it to work requires setting jumpers to enable JTAG functionality, setting SPI flash voltage and configuring USB drivers. Please refer to step by step instructions below.
All versions of ESP-WROVER-KIT boards have JTAG functionality build in. Putting it to work requires setting jumpers to enable JTAG functionality, setting SPI flash voltage and configuring USB drivers. Please refer to step by step instructions below.
Configure Hardware
@@ -29,17 +30,17 @@ Configure Hardware
Configure USB Drivers
^^^^^^^^^^^^^^^^^^^^^
Install and configure USB drivers, so OpenOCD is able to communicate with JTAG interface on ESP32 WROVER KIT board as well as with UART interface used to upload application for flash. Follow steps below specific to your operating system.
Install and configure USB drivers, so OpenOCD is able to communicate with JTAG interface on ESP-WROVER-KIT board as well as with UART interface used to upload application for flash. Follow steps below specific to your operating system.
.. note:: ESP32 WROVER KIT uses an FT2232 adapter. The following instructions can also be used for other FT2232 based JTAG adapters.
.. note:: ESP-WROVER-KIT uses an FT2232 adapter. The following instructions can also be used for other FT2232 based JTAG adapters.
Windows
"""""""
1. Using standard USB A / micro USB B cable connect ESP32 WROVER KIT to the computer. Switch the WROVER KIT on.
1. Using standard USB A / micro USB B cable connect ESP-WROVER-KIT to the computer. Switch the WROVER KIT on.
2. Wait until USB ports of WROVER KIT are recognized by Windows and drives are installed. If they do not install automatically, then then download them from http://www.ftdichip.com/Drivers/D2XX.htm and install manually.
2. Wait until USB ports of WROVER KIT are recognized by Windows and drives are installed. If they do not install automatically, then download them from http://www.ftdichip.com/Drivers/D2XX.htm and install manually.
3. Download Zadig tool (Zadig_X.X.exe) from http://zadig.akeo.ie/ and run it.
@@ -60,13 +61,13 @@ Windows
Do not change the second device "Dual RS232-HS (Interface 1)". It is routed to ESP32's serial port (UART) used for upload of application to ESP32's flash.
Now ESP32 WROVER KIT's JTAG interface should be available to the OpenOCD. To carry on with debugging environment setup, proceed to section :ref:`jtag-debugging-run-openocd`.
Now ESP-WROVER-KIT's JTAG interface should be available to the OpenOCD. To carry on with debugging environment setup, proceed to section :ref:`jtag-debugging-run-openocd`.
Linux
"""""
1. Using standard USB A / micro USB B cable connect ESP32 WROVER KIT board to the computer. Power on the board.
1. Using standard USB A / micro USB B cable connect ESP-WROVER-KIT board to the computer. Power on the board.
.. highlight:: none
@@ -79,7 +80,7 @@ Linux
crw-rw---- 1 root dialout 188, 1 Jul 10 19:04 /dev/ttyUSB1
3. Following section "Permissions delegation" in OpenOCD's README, set up the access permissions to both USB ports.
3. Following section "Permissions delegation" in `OpenOCD's README <https://sourceforge.net/p/openocd/code/ci/master/tree/README>`_, set up the access permissions to both USB ports.
4. Log off and login, then cycle the power to the board to make the changes effective. In terminal enter again ``ls -l /dev/ttyUSB*`` command to verify, if group-owner has changed from ``dialout`` to ``plugdev``:
@@ -93,13 +94,13 @@ Linux
The ``/dev/ttyUSBn`` interface with lower number is used for JTAG communication. The other interface is routed to ESP32's serial port (UART) used for upload of application to ESP32's flash.
Now ESP32 WROVER KIT's JTAG interface should be available to the OpenOCD. To carry on with debugging environment setup, proceed to section :ref:`jtag-debugging-run-openocd`.
Now ESP-WROVER-KIT's JTAG interface should be available to the OpenOCD. To carry on with debugging environment setup, proceed to section :ref:`jtag-debugging-run-openocd`.
MacOS
"""""
On macOS, using FT2232 for JTAG and serial port at the same time needs some additional steps. When the OS loads FTDI serial port driver, it does so for both channels of FT2232 chip. However only one of these channels is used as a serial port, while the other is used as JTAG. If the OS has loaded FTDI serial port driver for the channel used for JTAG, OpenOCD will not be able to connect to to the chip. There are two ways around this:
On macOS, using FT2232 for JTAG and serial port at the same time needs some additional steps. When the OS loads FTDI serial port driver, it does so for both channels of FT2232 chip. However only one of these channels is used as a serial port, while the other is used as JTAG. If the OS has loaded FTDI serial port driver for the channel used for JTAG, OpenOCD will not be able to connect to the chip. There are two ways around this:
1. Manually unload the FTDI serial port driver before starting OpenOCD, start OpenOCD, then load the serial port driver.
@@ -195,4 +196,3 @@ In a nutshell, this approach requires modification to FTDI driver configuration
After these steps, serial port and JTAG can be used at the same time.
To carry on with debugging environment setup, proceed to section :ref:`jtag-debugging-run-openocd`.

View File

@@ -1,5 +1,6 @@
Debugging Examples
==================
:link_to_translation:`zh_CN:[中文]`
This section describes debugging with GDB from :ref:`jtag-debugging-examples-eclipse` as well as from :ref:`jtag-debugging-examples-command-line`.
@@ -34,8 +35,8 @@ Examples in this section
.. _jtag-debugging-examples-eclipse-01:
Navigating though the code, call stack and threads
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Navigating through the code, call stack and threads
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When the target is halted, debugger shows the list of threads in "Debug" window. The line of code where program halted is highlighted in another window below, as shown on the following picture. The LED stops blinking.
@@ -59,7 +60,7 @@ By expanding threads you can navigate throughout the application. Expand Thread
In another window on right, you can see the disassembled machine code no matter if your project provides it in source or only the binary form.
Go back to the ``app_main()`` in Thread #1 to familiar code of ``blink.c`` file that will be examined in more details in the following examples. Debugger makes it easy to navigate through the code of entire application. This comes handy when stepping though the code and working with breakpoints and will be discussed below.
Go back to the ``app_main()`` in Thread #1 to familiar code of ``blink.c`` file that will be examined in more details in the following examples. Debugger makes it easy to navigate through the code of entire application. This comes handy when stepping through the code and working with breakpoints and will be discussed below.
.. _jtag-debugging-examples-eclipse-02:
@@ -163,7 +164,7 @@ Now resume program by pressing F8 and observe "Monitor" tab.
:alt: Observing memory location 0x3FF44004 changing one bit to ON"
:figclass: align-center
Observing memory location 0x3FF44004 changing one bit to ON"
Observing memory location 0x3FF44004 changing one bit to "ON"
You should see one bit being flipped over at memory location ``0x3FF44004`` (and LED changing the state) each time F8 is pressed.
@@ -172,7 +173,7 @@ You should see one bit being flipped over at memory location ``0x3FF44004`` (and
:alt: Observing memory location 0x3FF44004 changing one bit to ON"
:figclass: align-center
Observing memory location 0x3FF44004 changing one bit to ON"
Observing memory location 0x3FF44004 changing one bit to "OFF"
To set memory use the same "Monitor" tab and the same memory location. Type in alternate bit pattern as previously observed. Immediately after pressing enter you will see LED changing the state.
@@ -182,7 +183,7 @@ To set memory use the same "Monitor" tab and the same memory location. Type in a
Watching and setting program variables
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A common debugging tasks is checking the value of a program variable as the program runs. To be able to demonstrate this functionality, update file ``blink.c`` by adding a declaration of a global variable ``int i`` above definition of function ``blink_task``. Then add ``i++`` inside ``loop(1)`` of this function to get ``i`` incremented on each blink.
A common debugging tasks is checking the value of a program variable as the program runs. To be able to demonstrate this functionality, update file ``blink.c`` by adding a declaration of a global variable ``int i`` above definition of function ``blink_task``. Then add ``i++`` inside ``while(1)`` of this function to get ``i`` incremented on each blink.
Exit debugger, so it is not confused with new code, build and flash the code to the ESP and restart debugger. There is no need to restart OpenOCD.
@@ -227,9 +228,9 @@ Command Line
Verify if your target is ready and loaded with :example:`get-started/blink` example. Configure and start debugger following steps in section :ref:`jtag-debugging-using-debugger-command-line`. Pick up where target was left by debugger, i.e. having the application halted at breakpoint established at ``app_main()``::
Temporary breakpoint 1, app_main () at /home/user-name/esp/blink/main/./blink.c:43
43 xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
(gdb)
Temporary breakpoint 1, app_main () at /home/user-name/esp/blink/main/./blink.c:43
43 xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
(gdb)
@@ -247,123 +248,123 @@ Examples in this section
.. _jtag-debugging-examples-command-line-01:
Navigating though the code, call stack and threads
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Navigating through the code, call stack and threads
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When you see the ``(gdb)`` prompt, the application is halted. LED should not be blinking.
To find out where exactly the code is halted, enter ``l`` or ``list``, and debugger will show couple of lines of code around the halt point (line 43 of code in file ``blink.c``) ::
(gdb) l
38 }
39 }
40
41 void app_main()
42 {
43 xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
44 }
(gdb)
(gdb) l
38 }
39 }
40
41 void app_main()
42 {
43 xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
44 }
(gdb)
Check how code listing works by entering, e.g. ``l 30, 40`` to see particular range of lines of code.
You can use ``bt`` or ``backtrace`` to see what function calls lead up to this code::
(gdb) bt
#0 app_main () at /home/user-name/esp/blink/main/./blink.c:43
#1 0x400d057e in main_task (args=0x0) at /home/user-name/esp/esp-idf/components/esp32/./cpu_start.c:339
(gdb)
(gdb) bt
#0 app_main () at /home/user-name/esp/blink/main/./blink.c:43
#1 0x400d057e in main_task (args=0x0) at /home/user-name/esp/esp-idf/components/esp32/./cpu_start.c:339
(gdb)
Line #0 of output provides the last function call before the application halted, i.e. ``app_main ()`` we have listed previously. The ``app_main ()`` was in turn called by function ``main_task`` from line 339 of code located in file ``cpu_start.c``.
To get to the context of ``main_task`` in file ``cpu_start.c``, enter ``frame N``, where N = 1, because the ``main_task`` is listed under #1)::
(gdb) frame 1
#1 0x400d057e in main_task (args=0x0) at /home/user-name/esp/esp-idf/components/esp32/./cpu_start.c:339
339 app_main();
(gdb)
(gdb) frame 1
#1 0x400d057e in main_task (args=0x0) at /home/user-name/esp/esp-idf/components/esp32/./cpu_start.c:339
339 app_main();
(gdb)
Enter ``l`` and this will reveal the piece of code that called ``app_main()`` (in line 339)::
(gdb) l
334 ;
335 }
336 #endif
337 //Enable allocation in region where the startup stacks were located.
338 heap_caps_enable_nonos_stack_heaps();
339 app_main();
340 vTaskDelete(NULL);
341 }
342
(gdb)
(gdb) l
334 ;
335 }
336 #endif
337 //Enable allocation in region where the startup stacks were located.
338 heap_caps_enable_nonos_stack_heaps();
339 app_main();
340 vTaskDelete(NULL);
341 }
342
(gdb)
By listing some lines before, you will see the function name ``main_task`` we have been looking for::
(gdb) l 326, 341
326 static void main_task(void* args)
327 {
328 // Now that the application is about to start, disable boot watchdogs
329 REG_CLR_BIT(TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN_S);
330 REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
331 #if !CONFIG_FREERTOS_UNICORE
332 // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack
333 while (port_xSchedulerRunning[1] == 0) {
334 ;
335 }
336 #endif
337 //Enable allocation in region where the startup stacks were located.
338 heap_caps_enable_nonos_stack_heaps();
339 app_main();
340 vTaskDelete(NULL);
341 }
(gdb)
(gdb) l 326, 341
326 static void main_task(void* args)
327 {
328 // Now that the application is about to start, disable boot watchdogs
329 REG_CLR_BIT(TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN_S);
330 REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
331 #if !CONFIG_FREERTOS_UNICORE
332 // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack
333 while (port_xSchedulerRunning[1] == 0) {
334 ;
335 }
336 #endif
337 //Enable allocation in region where the startup stacks were located.
338 heap_caps_enable_nonos_stack_heaps();
339 app_main();
340 vTaskDelete(NULL);
341 }
(gdb)
To see the other code, enter ``i threads``. This will show the list of threads running on target::
(gdb) i threads
Id Target Id Frame
8 Thread 1073411336 (dport) 0x400d0848 in dport_access_init_core (arg=<optimized out>)
at /home/user-name/esp/esp-idf/components/esp32/./dport_access.c:170
7 Thread 1073408744 (ipc0) xQueueGenericReceive (xQueue=0x3ffae694, pvBuffer=0x0, xTicksToWait=1644638200,
xJustPeeking=0) at /home/user-name/esp/esp-idf/components/freertos/./queue.c:1452
6 Thread 1073431096 (Tmr Svc) prvTimerTask (pvParameters=0x0)
at /home/user-name/esp/esp-idf/components/freertos/./timers.c:445
5 Thread 1073410208 (ipc1 : Running) 0x4000bfea in ?? ()
4 Thread 1073432224 (dport) dport_access_init_core (arg=0x0)
at /home/user-name/esp/esp-idf/components/esp32/./dport_access.c:150
3 Thread 1073413156 (IDLE) prvIdleTask (pvParameters=0x0)
at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:3282
2 Thread 1073413512 (IDLE) prvIdleTask (pvParameters=0x0)
at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:3282
* 1 Thread 1073411772 (main : Running) app_main () at /home/user-name/esp/blink/main/./blink.c:43
(gdb)
(gdb) i threads
Id Target Id Frame
8 Thread 1073411336 (dport) 0x400d0848 in dport_access_init_core (arg=<optimized out>)
at /home/user-name/esp/esp-idf/components/esp32/./dport_access.c:170
7 Thread 1073408744 (ipc0) xQueueGenericReceive (xQueue=0x3ffae694, pvBuffer=0x0, xTicksToWait=1644638200,
xJustPeeking=0) at /home/user-name/esp/esp-idf/components/freertos/./queue.c:1452
6 Thread 1073431096 (Tmr Svc) prvTimerTask (pvParameters=0x0)
at /home/user-name/esp/esp-idf/components/freertos/./timers.c:445
5 Thread 1073410208 (ipc1 : Running) 0x4000bfea in ?? ()
4 Thread 1073432224 (dport) dport_access_init_core (arg=0x0)
at /home/user-name/esp/esp-idf/components/esp32/./dport_access.c:150
3 Thread 1073413156 (IDLE) prvIdleTask (pvParameters=0x0)
at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:3282
2 Thread 1073413512 (IDLE) prvIdleTask (pvParameters=0x0)
at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:3282
* 1 Thread 1073411772 (main : Running) app_main () at /home/user-name/esp/blink/main/./blink.c:43
(gdb)
The thread list shows the last function calls per each thread together with the name of C source file if available.
You can navigate to specific thread by entering ``thread N``, where ``N`` is the thread Id. To see how it works go to thread thread 5::
(gdb) thread 5
[Switching to thread 5 (Thread 1073410208)]
#0 0x4000bfea in ?? ()
(gdb)
(gdb) thread 5
[Switching to thread 5 (Thread 1073410208)]
#0 0x4000bfea in ?? ()
(gdb)
Then check the backtrace::
(gdb) bt
#0 0x4000bfea in ?? ()
#1 0x40083a85 in vPortCPUReleaseMutex (mux=<optimized out>) at /home/user-name/esp/esp-idf/components/freertos/./port.c:415
#2 0x40083fc8 in vTaskSwitchContext () at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:2846
#3 0x4008532b in _frxt_dispatch ()
#4 0x4008395c in xPortStartScheduler () at /home/user-name/esp/esp-idf/components/freertos/./port.c:222
#5 0x4000000c in ?? ()
#6 0x4000000c in ?? ()
#7 0x4000000c in ?? ()
#8 0x4000000c in ?? ()
(gdb)
(gdb) bt
#0 0x4000bfea in ?? ()
#1 0x40083a85 in vPortCPUReleaseMutex (mux=<optimized out>) at /home/user-name/esp/esp-idf/components/freertos/./port.c:415
#2 0x40083fc8 in vTaskSwitchContext () at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:2846
#3 0x4008532b in _frxt_dispatch ()
#4 0x4008395c in xPortStartScheduler () at /home/user-name/esp/esp-idf/components/freertos/./port.c:222
#5 0x4000000c in ?? ()
#6 0x4000000c in ?? ()
#7 0x4000000c in ?? ()
#8 0x4000000c in ?? ()
(gdb)
As you see, the backtrace may contain several entries. This will let you check what exact sequence of function calls lead to the code where the target halted. Question marks ``??`` instead of a function name indicate that application is available only in binary format, without any source file in C language. The value like ``0x4000bfea`` is the memory address of the function call.
Using ``bt``, ``i threads``, ``thread N`` and ``list`` commands we are now able to navigate through the code of entire application. This comes handy when stepping though the code and working with breakpoints and will be discussed below.
Using ``bt``, ``i threads``, ``thread N`` and ``list`` commands we are now able to navigate through the code of entire application. This comes handy when stepping through the code and working with breakpoints and will be discussed below.
.. _jtag-debugging-examples-command-line-02:
@@ -430,22 +431,22 @@ When debugging, you may resume application and enter code waiting for some event
To check it delete all breakpoints and enter ``c`` to resume application. Then enter Ctrl+C. Application will be halted at some random point and LED will stop blinking. Debugger will print the following::
(gdb) c
Continuing.
^CTarget halted. PRO_CPU: PC=0x400D0C00 APP_CPU: PC=0x400D0C00 (active)
[New Thread 1073433352]
(gdb) c
Continuing.
^CTarget halted. PRO_CPU: PC=0x400D0C00 APP_CPU: PC=0x400D0C00 (active)
[New Thread 1073433352]
Program received signal SIGINT, Interrupt.
[Switching to Thread 1073413512]
0x400d0c00 in esp_vApplicationIdleHook () at /home/user-name/esp/esp-idf/components/esp32/./freertos_hooks.c:52
52 asm("waiti 0");
(gdb)
Program received signal SIGINT, Interrupt.
[Switching to Thread 1073413512]
0x400d0c00 in esp_vApplicationIdleHook () at /home/user-name/esp/esp-idf/components/esp32/./freertos_hooks.c:52
52 asm("waiti 0");
(gdb)
In particular case above, the application has been halted in line 52 of code in file ``freertos_hooks.c``. Now you can resume it again by enter ``c`` or do some debugging as discussed below.
.. note::
In MSYS2 shell Ctrl+C does not halt the target but exists debugger. To resolve this issue consider debugging with :ref:`jtag-debugging-examples-eclipse` or check a workaround under http://www.mingw.org/wiki/Workaround_for_GDB_Ctrl_C_Interrupt.
In MSYS2 shell Ctrl+C does not halt the target but exists debugger. To resolve this issue consider debugging with :ref:`jtag-debugging-examples-eclipse` or check a workaround under http://www.mingw.org/wiki/Workaround_for_GDB_Ctrl_C_Interrupt.
.. _jtag-debugging-examples-command-line-04:
@@ -556,7 +557,7 @@ You should see the LED to turn on immediately after entering ``set {unsigned int
Watching and setting program variables
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A common debugging tasks is checking the value of a program variable as the program runs. To be able to demonstrate this functionality, update file ``blink.c`` by adding a declaration of a global variable ``int i`` above definition of function ``blink_task``. Then add ``i++`` inside ``loop(1)`` of this function to get ``i`` incremented on each blink.
A common debugging tasks is checking the value of a program variable as the program runs. To be able to demonstrate this functionality, update file ``blink.c`` by adding a declaration of a global variable ``int i`` above definition of function ``blink_task``. Then add ``i++`` inside ``while(1)`` of this function to get ``i`` incremented on each blink.
Exit debugger, so it is not confused with new code, build and flash the code to the ESP and restart debugger. There is no need to restart OpenOCD.

View File

@@ -1,5 +1,6 @@
JTAG Debugging
==============
:link_to_translation:`zh_CN:[中文]`
This document provides a guide to installing OpenOCD for ESP32 and debugging using
GDB. The document is structured as follows:
@@ -17,7 +18,7 @@ GDB. The document is structured as follows:
:ref:`jtag-debugging-launching-debugger`
Steps to start up a debug session with GDB from :ref:`jtag-debugging-using-debugger-eclipse` and from :ref:`jtag-debugging-using-debugger-command-line`.
:ref:`jtag-debugging-examples`
If you are not familiar with GDB, check this section for debugging examples provided from from :ref:`jtag-debugging-examples-eclipse` as well as from :ref:`jtag-debugging-examples-command-line`.
If you are not familiar with GDB, check this section for debugging examples provided from :ref:`jtag-debugging-examples-eclipse` as well as from :ref:`jtag-debugging-examples-command-line`.
:ref:`jtag-debugging-building-openocd`
Procedure to build OpenOCD from sources for :doc:`Windows <building-openocd-windows>`, :doc:`Linux <building-openocd-linux>` and :doc:`MacOS <building-openocd-macos>` operating systems.
:ref:`jtag-debugging-tips-and-quirks`
@@ -59,7 +60,7 @@ Under "Application Loading and Monitoring" there is another software and hardwar
Debugging using JTAG and application loading / monitoring is integrated under the `Eclipse <https://www.eclipse.org/>`_ environment, to provide quick and easy transition from writing, compiling and loading the code to debugging, back to writing the code, and so on. All the software is available for Windows, Linux and MacOS platforms.
If the :doc:`ESP32 WROVER KIT <../../hw-reference/modules-and-boards>` is used, then connection from PC to ESP32 is done effectively with a single USB cable thanks to FT2232H chip installed on WROVER, which provides two USB channels, one for JTAG and the second for UART connection.
If the :doc:`ESP-WROVER-KIT <../../hw-reference/modules-and-boards>` is used, then connection from PC to ESP32 is done effectively with a single USB cable thanks to FT2232H chip installed on WROVER, which provides two USB channels, one for JTAG and the second for UART connection.
Depending on user preferences, both `debugger` and `make` can be operated directly from terminal / command line, instead from Eclipse.
@@ -69,11 +70,11 @@ Depending on user preferences, both `debugger` and `make` can be operated direct
Selecting JTAG Adapter
----------------------
The quickest and most convenient way to start with JTAG debugging is by using :doc:`ESP32 WROVER KIT <../../hw-reference/modules-and-boards>`. Each version of this development board has JTAG interface already build in. No need for an external JTAG adapter and extra wiring / cable to connect JTAG to ESP32. WROVER KIT is using FT2232H JTAG interface operating at 20 MHz clock speed, which is difficult to achieve with an external adapter.
The quickest and most convenient way to start with JTAG debugging is by using :doc:`ESP-WROVER-KIT <../../hw-reference/modules-and-boards>`. Each version of this development board has JTAG interface already build in. No need for an external JTAG adapter and extra wiring / cable to connect JTAG to ESP32. WROVER KIT is using FT2232H JTAG interface operating at 20 MHz clock speed, which is difficult to achieve with an external adapter.
If you decide to use separate JTAG adapter, look for one that is compatible with both the voltage levels on the ESP32 as well as with the OpenOCD software. The JTAG port on the ESP32 is an industry-standard JTAG port which lacks (and does not need) the TRST pin. The JTAG I/O pins all are powered from the VDD_3P3_RTC pin (which normally would be powered by a 3.3V rail) so the JTAG adapter needs to be able to work with JTAG pins in that voltage range.
If you decide to use separate JTAG adapter, look for one that is compatible with both the voltage levels on the ESP32 as well as with the OpenOCD software. The JTAG port on the ESP32 is an industry-standard JTAG port which lacks (and does not need) the TRST pin. The JTAG I/O pins all are powered from the VDD_3P3_RTC pin (which normally would be powered by a 3.3 V rail) so the JTAG adapter needs to be able to work with JTAG pins in that voltage range.
On the software side, OpenOCD supports a fair amount of JTAG adapters. See http://openocd.org/doc/html/Debug-Adapter-Hardware.html for an (unfortunately slightly incomplete) list of the adapters OpenOCD works with. This page lists SWD-compatible adapters as well; take note that the ESP32 does not support SWD. JTAG adapters that are hardcoded to a specific product line, e.g. STM32 debugging adapters, will not work.
On the software side, OpenOCD supports a fair amount of JTAG adapters. See http://openocd.org/doc/html/Debug-Adapter-Hardware.html for an (unfortunately slightly incomplete) list of the adapters OpenOCD works with. This page lists SWD-compatible adapters as well; take note that the ESP32 does not support SWD. JTAG adapters that are hardcoded to a specific product line, e.g. ST-LINK debugging adapters for STM32 families, will not work.
The minimal signalling to get a working JTAG connection are TDI, TDO, TCK, TMS and GND. Some JTAG debuggers also need a connection from the ESP32 power line to a line called e.g. Vtar to set the working voltage. SRST can optionally be connected to the CH_PD of the ESP32, although for now, support in OpenOCD for that line is pretty minimal.
@@ -169,7 +170,7 @@ Open terminal, go to directory where OpenOCD is installed and start it up::
.. highlight:: none
You should now see similar output (this log is for ESP32 WROVER KIT)::
You should now see similar output (this log is for ESP-WROVER-KIT)::
user-name@computer-name:~/esp/openocd-esp32$ bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg
Open On-Chip Debugger 0.10.0-dev-ged7b1a9 (2017-07-10-07:16)

View File

@@ -1,7 +1,7 @@
************************
Set up OpenOCD for Linux
************************
:link_to_translation:`zh_CN:[中文]`
Set up OpenOCD
==============

View File

@@ -1,7 +1,7 @@
************************
Set up OpenOCD for MacOS
************************
:link_to_translation:`zh_CN:[中文]`
Install libusb
==============

View File

@@ -1,13 +1,14 @@
**************************
Set up OpenOCD for Windows
**************************
:link_to_translation:`zh_CN:[中文]`
IDF Tools Installer
===================
If you are using CMake build system and followed the :doc:`/get-started-cmake/windows-setup` with the ``ESP-IDF Tools Installer`` V1.2 or newer, then by default you will already have ``openocd`` installed.
``ESP-IDF Tools Installer`` adds ``openocd` to the ``PATH`` so that it can be run from any directory.
``ESP-IDF Tools Installer`` adds ``openocd`` to the ``PATH`` so that it can be run from any directory.
Set up OpenOCD
==============

View File

@@ -1,5 +1,6 @@
Tips and Quirks
---------------
:link_to_translation:`zh_CN:[中文]`
This section provides collection of all tips and quirks referred to from various parts of this guide.
@@ -54,7 +55,7 @@ Support options for OpenOCD at compile time
ESP-IDF has some support options for OpenOCD debugging which can be set at compile time:
* :ref:`CONFIG_ESP32_DEBUG_OCDAWARE` is enabled by default. If a panic or unhandled exception is thrown and a JTAG debugger is connected (ie openocd is running), ESP-IDF will break into the debugger.
* :ref:`CONFIG_ESP32_DEBUG_OCDAWARE` is enabled by default. If a panic or unhandled exception is thrown and a JTAG debugger is connected (ie OpenOCD is running), ESP-IDF will break into the debugger.
* :ref:`CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK` (disabled by default) sets watchpoint index 1 (the second of two) at the end of any task stack. This is the most accurate way to debug task stack overflows. Click the link for more details.
Please see the :ref:`make menuconfig <get-started-configure>` menu for more details on setting compile-time options.
@@ -72,11 +73,11 @@ OpenOCD has explicit support for the ESP-IDF FreeRTOS. GDB can see FreeRTOS task
Why to set SPI flash voltage in OpenOCD configuration?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The MTDI pin of ESP32, being among four pins used for JTAG communication, is also one of ESP32's bootstrapping pins. On power up ESP32 is sampling binary level on MTDI to set it's internal voltage regulator used to supply power to external SPI flash chip. If binary level on MDTI pin on power up is low, the voltage regulator is set to deliver 3.3V, if it is high, then the voltage is set to 1.8V. The MTDI pin should have a pull-up or may rely on internal weak pull down resistor (see ESP32 Datasheet for details), depending on the type of SPI chip used. Once JTAG is connected, it overrides the pull-up or pull-down resistor that is supposed to do the bootstrapping.
The MTDI pin of ESP32, being among four pins used for JTAG communication, is also one of ESP32's bootstrapping pins. On power up ESP32 is sampling binary level on MTDI to set it's internal voltage regulator used to supply power to external SPI flash chip. If binary level on MDTI pin on power up is low, the voltage regulator is set to deliver 3.3 V, if it is high, then the voltage is set to 1.8 V. The MTDI pin should have a pull-up or may rely on internal weak pull down resistor (see `ESP32 Series Datasheet <https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf>`_ for details), depending on the type of SPI chip used. Once JTAG is connected, it overrides the pull-up or pull-down resistor that is supposed to do the bootstrapping.
To handle this issue OpenOCD's board configuration file (e.g. ``boards\esp-wroom-32.cfg`` for ESP32-WROOM-32 module) provides ``ESP32_FLASH_VOLTAGE`` parameter to set the idle state of the ``TDO`` line to a specified binary level, therefore reducing the chance of a bad bootup of application due to incorrect flash voltage.
Check specification of ESP32 module connected to JTAG, what is the power supply voltage of SPI flash chip. Then set ``ESP32_FLASH_VOLTAGE`` accordingly. Most WROOM modules use 3.3V flash, while WROVER modules use 1.8V flash.
Check specification of ESP32 module connected to JTAG, what is the power supply voltage of SPI flash chip. Then set ``ESP32_FLASH_VOLTAGE`` accordingly. Most WROOM modules use 3.3 V flash, while WROVER modules use 1.8 V flash.
.. _jtag-debugging-tip-optimize-jtag-speed:
@@ -160,7 +161,7 @@ Power supply voltage of ESP32's SPI flash chip
set ESP32_FLASH_VOLTAGE 1.8
Comment out this line to set 3.3V, ref: :ref:`jtag-debugging-tip-code-flash-voltage`
Comment out this line to set 3.3 V, ref: :ref:`jtag-debugging-tip-code-flash-voltage`
Configuration file for ESP32 targets

View File

@@ -1,5 +1,6 @@
Using Debugger
--------------
:link_to_translation:`zh_CN:[中文]`
This section covers configuration and running debugger either from :ref:`jtag-debugging-using-debugger-eclipse`
or :ref:`jtag-debugging-using-debugger-command-line`. It is recommended to first check if debugger works from :ref:`jtag-debugging-using-debugger-command-line` and then move to using Eclipse.

View File

@@ -1,5 +1,6 @@
Linker Script Generation
========================
:link_to_translation:`zh_CN:[中文]`
Overview
--------
@@ -49,6 +50,10 @@ For CMake set the variable ``COMPONENT_ADD_LDFRAGMENTS`` to your linker file/s b
register_component()
It is also possible to specify fragment files from the project CMakeLists.txt or component project_include.cmake using the function `ldgen_add_fragment_files`::
ldgen_add_fragment_files(target files ...)
Specifying placements
^^^^^^^^^^^^^^^^^^^^^
@@ -64,7 +69,7 @@ For the following text, suppose we have the following:
- a component named ``component`` that is archived as library ``libcomponent.a`` during build
- three object files archived under the library, ``object1.o``, ``object2.o`` and ``object3.o``
- under ``object1.o``, the function ``function1`` is defined; under ``object2.o``, the function ``function2`` is defined
- there exists configuration ``PERFORMANCE_MODE`` and ``PERFORMANCE_LEVEL`` in one of the IDF KConfig files, with the set value indicated by entries ``CONFIG_PERFORMANCE_MODE`` and ``CONFIG_PERFORMANCE_LEVEL`` in the project sdkconfig
- there exist configuration ``PERFORMANCE_MODE`` and ``PERFORMANCE_LEVEL`` in one of the IDF KConfig files, with the set value indicated by entries ``CONFIG_PERFORMANCE_MODE`` and ``CONFIG_PERFORMANCE_LEVEL`` in the project sdkconfig
In the created linker fragment file, we write:
@@ -82,8 +87,7 @@ will still be used for ``libcomponent.a``, unless the ``entries`` key is populat
Placing object files
""""""""""""""""""""
Suppose the entirety of ``object1.o`` is performance-critical, so it is desirable to place it in RAM. On the other hand, all of ``object2.o``
contains things to be executed coming out of deep sleep, so it needs to be put under RTC memory. We can write:
Suppose the entirety of ``object1.o`` is performance-critical, so it is desirable to place it in RAM. On the other hand, suppose all of ``object2.o`` contains things to be executed coming out of deep sleep, so it needs to be put under RTC memory. We can write:
.. code-block:: none
@@ -114,7 +118,7 @@ can be achieved for placing data by writing the variable name instead of the fun
.. warning::
There are :ref:`limitations<ldgen-type3-limitations>` in placing code/data using their symbol names. In order to ensure proper placements, an alternative would be to group
There are :ref:`limitations<ldgen-type1-limitations>` in placing code/data using their symbol names. In order to ensure proper placements, an alternative would be to group
relevant code and data into source files, and :ref:`use object file placement<ldgen-placing-object-files>`.
Placing entire component
@@ -394,7 +398,7 @@ Expanding the sections fragment with its entries definition:
...) # and so on
.. _ldgen-type3-limitations :
.. _ldgen-type1-limitations :
**On** ``Type I`` **Mapping Entries**
@@ -413,7 +417,7 @@ However, this is not the case for static data declared in function scope, as the
**Condition Entries**
Condition entries enable the linker script generation to be configuration-aware. Depending on whether expressions involving configuration values
are true or not, a particular set of mapping entries can be used. The evaluation uses ``eval_string`` from ``:idf_file:`tools/kconfig_new/kconfiglib.py``` and adheres to its required syntax and limitations.
are true or not, a particular set of mapping entries can be used. The evaluation uses ``eval_string`` from :idf_file:`tools/kconfig_new/kconfiglib.py` and adheres to its required syntax and limitations.
All mapping entries defined after a condition entry until the next one or the end of the mapping fragment belongs to that condition entry. During processing
conditions are tested sequentially, and the mapping entries under the first condition that evaluates to ``TRUE`` are used.
@@ -540,5 +544,5 @@ put under the build directory of the same component. Modifying this linker scrip
Linker Fragment File
^^^^^^^^^^^^^^^^^^^^
Any component can add a fragment file to the build. In order to add a fragment file to process, use the command ``ldgen_add_fragment_file`` as mentioned :ref:`here<ldgen-add-fragment-file>`.
Any component can add a fragment file to the build. In order to add a fragment file to process, set COMPONENT_ADD_LDFRAGMENTS or use the function ``ldgen_add_fragment_files`` (CMake only) as mentioned :ref:`here <ldgen-add-fragment-file>`.
Modifying any fragment file presented to the build system triggers a re-link of the app binary.

View File

@@ -248,9 +248,15 @@ The number of bits not included in square brackets is free (bits in EFUSE_BLK0 a
Debug eFuse & Unit tests
------------------------
eFuse manager have option :envvar:`CONFIG_EFUSE_VIRTUAL` in Kconfig which will make an operation write is virtual. It can help to debug app and unit tests.
Virtual eFuses
^^^^^^^^^^^^^^
esptool have an useful tool for reading/writing ESP32 eFuse bits - `espefuse.py <https://github.com/espressif/esptool/wiki/espefuse>`_.
The Kconfig option :envvar:`CONFIG_EFUSE_VIRTUAL` will virtualize eFuse values inside the eFuse Manager, so writes are emulated and no eFuse values are permanently changed. This can be useful for debugging app and unit tests.
espefuse.py
^^^^^^^^^^^
esptool includes a useful tool for reading/writing ESP32 eFuse bits - `espefuse.py <https://github.com/espressif/esptool/wiki/espefuse>`_.
::

View File

@@ -114,12 +114,12 @@ App version
Application version is stored in :cpp:class:`esp_app_desc_t` structure. It is located in DROM sector and has a fixed offset from the beginning of the binary file.
The structure is located after :cpp:class:`esp_image_header_t` and :cpp:class:`esp_image_segment_header_t` structures. The field version has string type and max length 32 chars.
To set version in your project manually you need set ``PROJECT_VER`` varible in your project Makefile/CMakeLists.txt:
To set version in your project manually you need to set ``PROJECT_VER`` variable in your project Makefile/CMakeLists.txt:
* For Make build system: in application Makefile put ``PROJECT_VER = "0.1.0.1"`` before including project.mk
* For Cmake build system: in application CMakeLists.txt put ``set(PROJECT_VER "0.1.0.1")`` before including project.cmake.
If ``PROJECT_VER`` variable did not set in project Makefile/CMakeLists.txt then it can retrieved from either ``$(PROJECT_PATH)/version.txt`` file (if present) else using git command ``git describe``. Application can make use of this by calling :cpp:func:`esp_ota_get_app_description` or :cpp:func:`esp_ota_get_partition_description` functions.
If ``PROJECT_VER`` variable is not set in project Makefile/CMakeLists.txt then it will be retrieved from either ``$(PROJECT_PATH)/version.txt`` file (if present) else using git command ``git describe``. If neither is available then ``PROJECT_VER`` will be set to "1". Application can make use of this by calling :cpp:func:`esp_ota_get_app_description` or :cpp:func:`esp_ota_get_partition_description` functions.
API Reference
-------------

View File

@@ -19,11 +19,11 @@ To compile with ESP-IDF you need to get the following packages:
- Ubuntu and Debian::
sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-pyparsing cmake ninja-build ccache
sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing cmake ninja-build ccache
- Arch::
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-pyparsing cmake ninja ccache
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing cmake ninja ccache
.. note::
CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake".
@@ -41,7 +41,7 @@ Compile the Toolchain from Source
sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool make
- Ubuntu 16.04::
- Ubuntu 16.04 or newer::
sudo apt-get install gawk gperf grep gettext python python-dev automake bison flex texinfo help2man libtool libtool-bin make

View File

@@ -17,11 +17,11 @@ To compile with ESP-IDF you need to get the following packages:
- Ubuntu and Debian::
sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-pyparsing cmake ninja-build ccache
sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing cmake ninja-build ccache
- Arch::
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-pyparsing cmake ninja ccache
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing cmake ninja ccache
.. note::
CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake".

View File

@@ -14,11 +14,11 @@ To compile with ESP-IDF you need to get the following packages:
- Ubuntu and Debian::
sudo apt-get install git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-pyparsing
sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing
- Arch::
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-pyparsing
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing
.. note::
@@ -39,7 +39,7 @@ Compile the Toolchain from Source
sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool
- Ubuntu 16.04::
- Ubuntu 16.04 or newer::
sudo apt-get install gawk gperf grep gettext python python-dev automake bison flex texinfo help2man libtool libtool-bin

View File

@@ -1,12 +1,12 @@
# This is a list of python packages used to generate documentation. This file is used with pip:
# pip install --user -r requirements.txt
#
sphinx==1.6.5
sphinx>=1.6.5
sphinx-rtd-theme
breathe==4.7.3
sphinxcontrib-blockdiag==1.5.3
sphinxcontrib-seqdiag==0.8.5
sphinxcontrib-actdiag==0.8.5
sphinxcontrib-nwdiag==0.9.5
breathe>=4.7.3
sphinxcontrib-blockdiag>=1.5.3
sphinxcontrib-seqdiag>=0.8.5
sphinxcontrib-actdiag>=0.8.5
sphinxcontrib-nwdiag>=0.9.5
recommonmark
future>=0.16.0 # for ../tools/gen_esp_err_to_name.py

View File

@@ -2,7 +2,7 @@
#
# Build will fail if sphinx-warning-log.txt contains any lines
# which are not in this file. Lines are pre-sanitized by
# check_doc_warnings.sh to remove formatting, paths, line numbers.
# check_doc_warnings.sh to remove formatting, paths and line numbers.
#
# Warnings in this file must be in the same overall order as the log file.
#
@@ -10,9 +10,74 @@
#
# Sphinx known issue https://github.com/sphinx-doc/sphinx/issues/2683
#
_build/inc/esp_a2dp_api.inc:line: WARNING: Invalid definition: Expected identifier in nested name. [error at 21]
# Note: warnings below will be gone after upgrade
# to the following package==version
#
# sphinx==1.8.4
# breathe==4.11.1
#
esp_a2dp_api.inc:line: WARNING: Invalid definition: Expected identifier in nested name. [error at 21]
union esp_a2d_mcc_t::@1 esp_a2d_mcc_t::cie
---------------------^
_build/inc/esp_bt_defs.inc:line: WARNING: Invalid definition: Expected identifier in nested name. [error at 21]
esp_bt_defs.inc:line: WARNING: Invalid definition: Expected identifier in nested name. [error at 21]
union esp_bt_uuid_t::@0 esp_bt_uuid_t::uuid
---------------------^
#
# Breathe known issue: https://github.com/michaeljones/breathe/issues/405
# Sphinx known issue: https://github.com/sphinx-doc/sphinx/pull/5901
#
# Note: warnings below have been identified after upgrade
# to the following package==version
#
# sphinx==1.8.4
# breathe==4.11.1
#
ulp-cmake.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_load_binary(uint32_t load_addr, const uint8_t * program_binary, size_t program_size)
ulp-cmake.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_run(uint32_t entry_point)
ulp-cmake.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_set_wakeup_period(size_t period_index, uint32_t period_us)
README.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_run(uint32_t entry_point)
#
# Issue present only when building on msys2 / mingw32 START >>>
#
esp_spp_api.inc:line: WARNING: Error in type declaration.
If typedef-like declaration:
Type must be either just a name or a typedef-like declaration.
If just a name:
Error in declarator or parameters and qualifiers
Invalid definition: Expected identifier in nested name, got keyword: void [error at 4]
void() esp_spp_cb_t(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
----^
If typedef-like declaration:
Error in declarator
If pointer to member declarator:
Invalid definition: Expected identifier in nested name. [error at 4]
void() esp_spp_cb_t(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
----^
If declId, parameters, and qualifiers:
Invalid definition: Expected identifier in nested name. [error at 4]
void() esp_spp_cb_t(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
----^
If parenthesis in noptr-declarator:
Error in declarator or parameters and qualifiers
If pointer to member declarator:
Invalid definition: Expected identifier in nested name. [error at 5]
void() esp_spp_cb_t(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
-----^
If declarator-id:
Invalid definition: Expected identifier in nested name. [error at 5]
void() esp_spp_cb_t(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
-----^
If type alias or template alias:
Invalid definition: Expected identifier in nested name, got keyword: void [error at 4]
void() esp_spp_cb_t(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
----^
#
# Issue present only when building on msys2 / mingw32 END <<<
#
spi_master.inc:line: WARNING: Duplicate declaration, struct spi_transaction_t spi_transaction_t
spi_slave.inc:line: WARNING: Duplicate declaration, struct spi_slave_transaction_t spi_slave_transaction_t
wear-levelling.rst:line: WARNING: Duplicate declaration, bool esp_vfs_fat_mount_config_t::format_if_mount_failed
wear-levelling.rst:line: WARNING: Duplicate declaration, int esp_vfs_fat_mount_config_t::max_files
wear-levelling.rst:line: WARNING: Duplicate declaration, size_t esp_vfs_fat_mount_config_t::allocation_unit_size
wear-levelling.rst:line: WARNING: Duplicate declaration, esp_vfs_fat_mount_config_t

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +1,17 @@
编译系统
构建系统
========
:link_to_translation:`en:[English]`
本文将介绍乐鑫物联网开发框架中的``编译系统````组件``的相关概念。
本文将介绍乐鑫物联网开发框架中的 ``构建系统````组件`` 的相关概念。
如果您想了解如何构建一个新的 ESP-IDF 项目,请阅读本文档。
我们建议您使用 `ESP-IDF 模板工程 <https://github.com/espressif/esp-idf-template>`_ 来开始您的新项目。
使用编译系统
使用构建系统
------------
ESP-IDF 的 :idf_file:`README.md` 文件对如何使用编译系统来构建项目作了简要的说明。
ESP-IDF 的 :idf_file:`README.md` 文件对如何使用构建系统来构建项目作了简要的说明。
概述
----
@@ -26,7 +26,7 @@ ESP-IDF 的 :idf_file:`README.md` 文件对如何使用编译系统来构建项
- 湿度传感器的驱动
- 将上述组件组织在一起的主代码
ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,编译系统会查找 ESP-IDF 目录、项目目录和用户自定义目录(可选)中所有的组件,然后使用基于文本的菜单系统让用户配置 ESP-IDF 项目中需要的每个组件。在配置结束后,编译系统开始编译整个项目。
ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,构建系统会查找 ESP-IDF 目录、项目目录和用户自定义目录(可选)中所有的组件,然后使用基于文本的菜单系统让用户配置 ESP-IDF 项目中需要的每个组件。在配置结束后,构建系统开始编译整个项目。
概念
~~~~
@@ -65,12 +65,11 @@ ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,
- main/ - src1.c
- src2.c
- component.mk
- build/
该示例项目 ``myProject`` 包含以下组成部分:
- 项目顶层 Makefile该 Makefile 设置了 ``PROJECT_NAME`` 变量,还可以定义作用于整个项目的其它 make 变量(可选)。顶层 Makefile 会导入核心 Makefile 文件 ``$(IDF_PATH)/make/project.mk`` ,由它负责实现 ESP-IDF 编译系统的剩余部分。
- 项目顶层 Makefile该 Makefile 设置了 ``PROJECT_NAME`` 变量,还可以定义作用于整个项目的其它 make 变量(可选)。顶层 Makefile 会导入核心 Makefile 文件 ``$(IDF_PATH)/make/project.mk`` ,由它负责实现 ESP-IDF 构建系统的剩余部分。
- 项目配置文件 sdkconfig执行 ``make menuconfig`` 后会创建或更新此文件,该文件中保存了项目中所有组件的配置信息(包括 ESP-IDF 本身)。``sdkconfig`` 文件可能会也可能不会被添加到项目的源代码管理系统中。
@@ -78,9 +77,9 @@ ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,
- ``main`` 目录是一个特殊的 ``伪组件``,它包含项目本身的源代码。``main`` 是默认名称Makefile 变量 ``COMPONENT_DIRS`` 默认会导入此组件,但您也可以修改此变量(或者设置 ``EXTRA_COMPONENT_DIRS`` )以查找其他位置的组件。
- ``build`` 目录在项目编译的时候创建或者更新,里面包含有编译生成的临时目标文件和库以及最终输出的二进制文件。此目录通常不会被添加到项目的源代码管理系统中,也不会随着项目源代码被发布。
- ``build`` 目录在项目构建的时候创建或者更新,里面包含有构建生成的临时目标文件和库以及最终输出的二进制文件。此目录通常不会被添加到项目的源代码管理系统中,也不会随着项目源代码被发布。
组件目录中会包含组件自己的 Makefile 文件 ``component.mk`` ,里面会定义一些变量来控制该组件的编译过程,以及它与整个项目的集成。更多详细信息请参考 `组件 Makefiles <#component-makefiles>`_
组件目录中会包含组件自己的 Makefile 文件 ``component.mk`` ,里面会定义一些变量来控制该组件的构建过程,以及它与整个项目的集成。更多详细信息请参考 `组件 Makefiles <#component-makefiles>`_
每个组件还可以包含一个 ``Kconfig`` 文件,它用于定义 ``menuconfig`` 时展示的组件配置信息的选项规则。某些组件还可能还会包含 ``Kconfig.projbuild````Makefile.projbuild`` 特殊文件,他们可以用来覆盖项目的部分配置。
@@ -106,15 +105,15 @@ ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,
可选的项目变量
^^^^^^^^^^^^^^
以下这些变量都有默认值,用户可以重写这些变量以自定义编译行为。查看 ``make/project.mk`` 文件可以获得所有的实现细节。
以下这些变量都有默认值,用户可以重写这些变量以自定义构建行为。查看 ``make/project.mk`` 文件可以获得所有的实现细节。
- ``PROJECT_PATH`` 顶层项目目录,默认是包含 Makefile 文件的目录,许多其他的项目变量都基于此变量。注意,项目路径中不能包含有空格。
- ``BUILD_DIR_BASE`` 所有对象、库、二进制文件的输出目录,默认为 ``$(PROJECT_PATH)/build``
- ``COMPONENT_DIRS`` 搜索组件的目录,默认为 ``$(IDF_PATH)/components````$(PROJECT_PATH)/components````$(PROJECT_PATH)/main````EXTRA_COMPONENT_DIRS`` 。如果您不希望从这些目录中搜索组件,请重写此变量。
- ``COMPONENT_DIRS`` 组件的搜索目录,默认为 ``$(IDF_PATH)/components````$(PROJECT_PATH)/components````$(PROJECT_PATH)/main````EXTRA_COMPONENT_DIRS`` 。如果您不希望从这些目录中搜索组件,请重写此变量。
- ``EXTRA_COMPONENT_DIRS`` 组件额外的搜索路径,可选。
- ``COMPONENTS``编译进项目中的组件列表,默认为 ``COMPONENT_DIRS`` 指定目录中所有的组件。
- ``EXCLUDE_COMPONENTS``编译的过程中需要剔除的组件列表,可选。请注意这只会减少编译的时间,并不会减少最终二进制文件的大小。
- ``TEST_EXCLUDE_COMPONENTS`` 在单元测试的编译过程中需要剔除的组件列表,可选。
- ``COMPONENTS``构建进项目中的组件列表,默认为 ``COMPONENT_DIRS`` 指定目录中所有的组件。
- ``EXCLUDE_COMPONENTS``构建的过程中需要剔除的组件列表,可选。请注意这只会减少构建的时间,并不会减少最终二进制文件的大小。
- ``TEST_EXCLUDE_COMPONENTS``构建单元测试的过程中需要剔除的组件列表,可选。
以上这些 Makefile 变量中的任何路径都要使用绝对路径,您可以使用 ``$(PROJECT_PATH)/xxx````$(IDF_PATH)/xxx``,或者使用 Make 内置函数 ``$(abspath xxx)`` 将相对路径转换为绝对路径。
@@ -136,8 +135,8 @@ ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,
运行 ``make list-components`` 命令可以查询这些变量的值,这有助于调试组件的搜索路径是否正确。
具有相同名字的多个组件
^^^^^^^^^^^^^^^^^^^^^^
同名组件
^^^^^^^^
ESP-IDF 搜索组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进行,这意味着在默认情况下,首先是 ESP-IDF 组件,然后是项目组件,最后是 ``EXTRA_COMPONENT_DIRS`` 中的组件。如果这些目录中的两个或者多个包含具有相同名字的组件,则使用搜索到的最后一个位置的组件。这就允许将组件复制到项目目录中再修改来覆盖 ESP-IDF 组件如果使用这种方式ESP-IDF 目录本身可以保持不变。
@@ -146,7 +145,7 @@ ESP-IDF 搜索组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进
最小组件 Makefile
^^^^^^^^^^^^^^^^^
最简单的 ``component.mk`` 文件可以是一个空文件,如果文件为空,则组件的默认编译行为会被设置为:
最简单的 ``component.mk`` 文件可以是一个空文件,如果文件为空,则组件的默认构建行为会被设置为:
- makefile 所在目录中的所有源文件(``*.c````*.cpp````*.cc````*.S``)将会被编译进组件库中。
- 子目录 ``include`` 将被添加到其他组件的全局头文件搜索路径中。
@@ -154,7 +153,7 @@ ESP-IDF 搜索组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进
更完整的组件 makefile 可以查看 `组件 Makefile 示例 <#example-component-makefile>`_
请注意,空的 ``component.mk`` 文件同没有 ``component.mk`` 文件之间存在本质差异,前者会调用默认的组件编译行为,后者不会发生默认的组件编译行为。一个组件中如果只包含影响项目配置或编译过程的文件,那么它可以没有 ``component.mk`` 文件。
请注意,空的 ``component.mk`` 文件同没有 ``component.mk`` 文件之间存在本质差异,前者会调用默认的组件构建行为,后者不会发生默认的组件构建行为。一个组件中如果只包含影响项目配置或构建过程的文件,那么它可以没有 ``component.mk`` 文件。
.. _preset-component-variables:
@@ -165,50 +164,50 @@ ESP-IDF 搜索组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进
- ``COMPONENT_PATH`` 组件的目录,即包含 ``component.mk`` 文件的绝对路径,路径中不能包含空格。
- ``COMPONENT_NAME`` 组件的名字,默认为组件目录的名称。
- ``COMPONENT_BUILD_DIR`` 组件的编译目录,即存放组件编译输出的绝对路径,它是 `$(BUILD_DIR_BASE)` 的子目录。该变量也是编译组件时的当前工作目录,所以 make 中的相对路径都以此目录为基础。
- ``COMPONENT_LIBRARY`` 组件编译后的静态库文件(相对于组件的编译目录)的名字,默认为 ``$(COMPONENT_NAME).a``
- ``COMPONENT_BUILD_DIR`` 组件的构建目录,即存放组件构建输出的绝对路径,它是 `$(BUILD_DIR_BASE)` 的子目录。该变量也是构建组件时的当前工作目录,所以 make 中的相对路径都以此目录为基础。
- ``COMPONENT_LIBRARY`` 组件构建后的静态库文件(相对于组件的构建目录)的名字,默认为 ``$(COMPONENT_NAME).a``
以下变量在项目顶层中设置,并被导出到组件中编译时使用:
以下变量在项目顶层中设置,并被导出到组件中构建时使用:
- ``PROJECT_NAME`` 项目名称,在项目的 Makefile 中设置。
- ``PROJECT_PATH`` 包含项目 Makefile 的目录的绝对路径。
- ``COMPONENTS`` 此次编译中包含的所有组件的名字。
- ``COMPONENTS`` 此次构建中包含的所有组件的名字。
- ``CONFIG_*`` 项目配置中的每个值在 make 中都对应一个以 ``CONFIG_`` 开头的变量。
- ``CC````LD````AR````OBJCOPY`` gcc xtensa 交叉编译工具链中每个工具的完整路径。
- ``HOSTCC````HOSTLD````HOSTAR`` 主机本地工具链中每个工具的全名。
- ``IDF_VER`` ESP-IDF 的版本号,可以通过检索 ``$(IDF_PATH)/version.txt`` 文件(假如存在的话)或者使用 git 命令 ``git describe`` 来获取。这里推荐的格式是在一行中指定主 IDF 的发布版本号,例如标记为 ``v2.0`` 的发布版本或者是标记任意一次提交记录的 ``v2.0-275-g0efaa4f``。应用程序可以通过调用 :cpp:func:`esp_get_idf_version` 函数来使用该变量。
如果您在 ``component.mk`` 文件中修改这些变量,这并不会影响其它组件的编译,但可能会使您的组件变得难以编译或调试。
如果您在 ``component.mk`` 文件中修改这些变量,这并不会影响其它组件的构建,但可能会使您的组件变得难以构建或调试。
.. _optional-project-wide-component-variables:
可选的项目通用组件变量
^^^^^^^^^^^^^^^^^^^^^^
可以在 ``component.mk`` 中设置以下变量来控制整个项目的编译行为:
可以在 ``component.mk`` 中设置以下变量来控制整个项目的构建行为:
- ``COMPONENT_ADD_INCLUDEDIRS`` 相对于组件目录的路径,将被添加到项目中所有组件的头文件搜索路径中。如果该变量未被覆盖,则默认为 ``include`` 目录。如果一个头文件路径仅仅为当前组件所用,那么应该将该路径添加到 ``COMPONENT_PRIV_INCLUDEDIRS`` 中。
- ``COMPONENT_ADD_LDFLAGS`` 添加链接参数到全局 ``LDFLAGS`` 中用以指导链接最终的可执行文件,默认为 ``-l$(COMPONENT_NAME)``。如果将预编译好的库添加到此目录,请使用它们为绝对路径,即 ``$(COMPONENT_PATH)/libwhatever.a``
- ``COMPONENT_DEPENDS`` 需要在当前组件之前编译的组件列表,这对于处理链接时的依赖不是必需的,因为所有组件的头文件目录始终可用。如果一个组件会生成一个头文件,然后另外一个组件需要使用它,此时该变量就有必要进行设置。大多数的组件不需要设置此变量。
- ``COMPONENT_DEPENDS`` 需要在当前组件之前构建的组件列表,这对于处理链接时的依赖不是必需的,因为所有组件的头文件目录始终可用。如果一个组件会生成一个头文件,然后另外一个组件需要使用它,此时该变量就有必要进行设置。大多数的组件不需要设置此变量。
- ``COMPONENT_ADD_LINKER_DEPS`` 保存一些文件的路径,当这些文件发生改变时,会触发 ELF 文件重新链接。该变量通常用于链接脚本文件和二进制文件,大多数的组件不需要设置此变量。
以下变量仅适用于属于 ESP-IDF 的组件:
- ``COMPONENT_SUBMODULES`` 组件使用的 git 子模块的路径列表(相对于 ``COMPONENT_PATH``)。这些路径会在编译的过程中被检查(并在必要的时候初始化)。如果组件位于 ``IDF_PATH`` 目录之外,则忽略此变量。
- ``COMPONENT_SUBMODULES`` 组件使用的 git 子模块的路径列表(相对于 ``COMPONENT_PATH``)。这些路径会在构建的过程中被检查(并在必要的时候初始化)。如果组件位于 ``IDF_PATH`` 目录之外,则忽略此变量。
可选的组件特定变量
^^^^^^^^^^^^^^^^^^
以下变量可以在 ``component.mk`` 中进行设置,用以控制该组件的编译行为:
以下变量可以在 ``component.mk`` 中进行设置,用以控制该组件的构建行为:
- ``COMPONENT_PRIV_INCLUDEDIRS`` 相对于组件目录的目录路径,该目录仅会被添加到该组件源文件的头文件搜索路径中。
- ``COMPONENT_EXTRA_INCLUDES`` 编译组件的源文件时需要指定的额外的头文件搜索路径,这些路径将以 ``-l`` 为前缀传递给编译器。这和 ``COMPONENT_PRIV_INCLUDEDIRS`` 变量的功能有些类似,但是这些路径不会相对于组件目录进行扩展。
- ``COMPONENT_SRCDIRS`` 相对于组件目录的目录路径,这些路径用于搜索源文件(``*.cpp````*.c````*.S``),默认为 ``.``,即组件目录本身。重写该变量可以指定包含源文件的不同目录列表。
- ``COMPONENT_OBJS`` 要编译生成的目标文件,默认是 ``COMPONENT_SRCDIRS`` 中每个源文件的 .o 文件。重写该变量将允许您剔除 ``COMPONENT_SRCDIRS`` 中的某些源文件,否则他们将会被编译。相关示例请参阅 `指定需要编译的组件源文件 <#specify-source-files>`_
- ``COMPONENT_EXTRA_CLEAN`` 相对于组件编译目录的路径,指向 ``component.mk`` 文件中自定义 make 规则生成的任何文件,它们也是 ``make clean`` 命令需要删除的文件。相关示例请参阅 `源代码生成 <#source-code-generation>`_
- ``COMPONENT_EXTRA_CLEAN`` 相对于组件构建目录的路径,指向 ``component.mk`` 文件中自定义 make 规则生成的任何文件,它们也是 ``make clean`` 命令需要删除的文件。相关示例请参阅 `源代码生成 <#source-code-generation>`_
- ``COMPONENT_OWNBUILDTARGET`` & ``COMPONENT_OWNCLEANTARGET`` 这些目标允许您完全覆盖组件的默认编译行为。有关详细信息,请参阅 `完全覆盖组件的 Makefile <#fully-overriding-component-makefile>`_。
- ``COMPONENT_CONFIG_ONLY`` 如果设置了此标志,则表示组件根本不会产生编译输出(即不会编译得到 ``COMPONENT_LIBRARY``),并且会忽略大多数其它组件变量。此标志用于 IDF 内部组件,其中仅包含 ``KConfig.projbuild`` 和/或 ``Makefile.projbuild`` 文件来配置项目,但是没有源文件。
- ``COMPONENT_CONFIG_ONLY`` 如果设置了此标志,则表示组件根本不会产生构建输出(即不会构建得到 ``COMPONENT_LIBRARY``),并且会忽略大多数其它组件变量。此标志用于 IDF 内部组件,其中仅包含 ``KConfig.projbuild`` 和/或 ``Makefile.projbuild`` 文件来配置项目,但是没有源文件。
- ``CFLAGS`` 传递给 C 编译器的标志。根据项目设置已经定义一组默认的 ``CFLAGS``,可以通过 ``CFLAGS +=`` 来为组件添加特定的标志,也可以完全重写该变量(尽管不推荐这么做)。
- ``CPPFLAGS`` 传递给 C 预处理器的标志(用于 ``.c````.cpp````.S`` 文件)。根据项目设置已经定义一组默认的 ``CPPFLAGS`` ,可以通过 ``CPPFLAGS +=`` 来为组件添加特定的标志,也可以完全重写该变量(尽管不推荐这么做)。
- ``CXXFLAGS`` 传递给 C++ 编译器的标志。根据项目设置已经定义一组默认的 ``CXXFLAGS`` ,可以通过 ``CXXFLAGS +=`` 来为组件添加特定的标志,也可以完全重写该变量(尽管不推荐这么做)。
@@ -217,7 +216,7 @@ ESP-IDF 搜索组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进
.. code:: makefile
apps/dhcpserver.o: CFLAGS += -Wno-unused-variable
apps/dhcpserver.o: CFLAGS += -Wno-unused-variable
如果上游代码在编译的时候发出了警告,那这么做可能会很有效。
@@ -235,12 +234,12 @@ ESP-IDF 搜索组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进
预处理器定义
~~~~~~~~~~~~
ESP-IDF 编译系统会在命令行中添加以下 C 预处理定义:
ESP-IDF 构建系统会在命令行中添加以下 C 预处理定义:
- ``ESP_PLATFORM`` — 可以用来检测在 ESP-IDF 内发生的编译行为。
- ``ESP_PLATFORM`` — 可以用来检测在 ESP-IDF 内发生的构建行为。
- ``IDF_VER`` — ESP-IDF 的版本,请参阅 `预设的组件变量 <#preset-component-variables>`_
编译的内部过程
构建的内部过程
~~~~~~~~~~~~~~
顶层:项目 Makefile
@@ -286,14 +285,14 @@ ESP-IDF 编译系统会在命令行中添加以下 C 预处理定义:
构建目标的进阶用法
~~~~~~~~~~~~~~~~~~
- ``make app````make bootloader````make partition table`` 可以根据需要为项目单独编译生成应用程序文件、启动引导文件和分区表文件。
- ``make app````make bootloader````make partition table`` 可以根据需要为项目单独构建生成应用程序文件、启动引导文件和分区表文件。
- ``make erase_flash````make erase_ota`` 会调用 esptool.py 脚本分别擦除整块闪存芯片或者其中 OTA 分区的内容。
- ``make size`` 会打印应用程序的大小信息。``make size-components````make size-files`` 两者功能相似,分别打印每个组件或者每个源文件大小的详细信息。
调试 Make 的过程
~~~~~~~~~~~~~~~~
调试 ESP-IDF 编译系统的一些技巧:
调试 ESP-IDF 构建系统的一些技巧:
-``V=1`` 添加到 make 的参数中(或将其设置为环境变量)将使 make 回显所有已经执行的命令,以及为子 make 输入的每个目录。
- 运行 ``make -w`` 将导致 make 在为子 make 输入时回显每个目录——与 ``V=1`` 相同但不回显所有命令。
@@ -360,13 +359,13 @@ Makefile.componentbuild
增加源文件目录
^^^^^^^^^^^^^^
默认情况下,将忽略子目录。如果您的项目在子目录中而不是在组件的根目录中有源文件,那么您可以通过设置 ``COMPONENT_SRCDIRS`` 将其告知编译系统:
默认情况下,将忽略子目录。如果您的项目在子目录中而不是在组件的根目录中有源文件,那么您可以通过设置 ``COMPONENT_SRCDIRS`` 将其告知构建系统:
.. code::
COMPONENT_SRCDIRS := src1 src2
编译系统将会编译 src1/ 和 src2/ 子目录中的所有源文件。
构建系统将会编译 src1/ 和 src2/ 子目录中的所有源文件。
.. _specify-source-files:
@@ -502,7 +501,7 @@ Makefile.componentbuild
完全覆盖组件的 Makefile
~~~~~~~~~~~~~~~~~~~~~~~
显然,在某些情况下,所有这些配置都不足以满足某个组件,例如,当组件基本上是另一个第三方组件的包装器时,该第三方组件最初不打算在 ESP-IDF 编译系统下工作,在这种情况下,可以通过设置 ``COMPONENT_OWNBUILDTARGET`` 和可能的 ``COMPONENT_OWNCLEANTARGET``,并在 ``component.mk`` 中定义名为 ``build````clean`` 的目标。构建目标可以执行任何操作,只要它为项目生成了 ``$(COMPONENT_LIBRARY)`` ,并最终被链接到应用程序二进制文件中即可。
显然,在某些情况下,所有这些配置都不足以满足某个组件,例如,当组件基本上是另一个第三方组件的包装器时,该第三方组件最初不打算在 ESP-IDF 构建系统下工作,在这种情况下,可以通过设置 ``COMPONENT_OWNBUILDTARGET`` 和可能的 ``COMPONENT_OWNCLEANTARGET``,并在 ``component.mk`` 中定义名为 ``build````clean`` 的目标。构建目标可以执行任何操作,只要它为项目生成了 ``$(COMPONENT_LIBRARY)`` ,并最终被链接到应用程序二进制文件中即可。
(实际上,这并不是必须的 - 如果 ``COMPONENT_ADD_LDFLAGS`` 变量被覆盖,那么组件可以指示链接器链接其他二进制文件。)
@@ -530,10 +529,10 @@ Makefile.componentbuild
python esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader/bootloader.bin 0x10000 example_app.bin 0x8000 partition_table_unit_test_app.bin
编译 Bootloader
构建 Bootloader
---------------
引导程序默认作为 ``make all`` 的一部分被编译,或者也可以通过 ``make bootloader-clean`` 来独构建,此外还可以通过 ``make bootloader-list-components`` 来查看构建引导程序时包含的组件。
引导程序默认作为 ``make all`` 的一部分被构建,或者也可以通过 ``make bootloader-clean``独构建,此外还可以通过 ``make bootloader-list-components`` 来查看构建引导程序时包含的组件。
引导程序是一个特殊的组件,因为主项目中的二级引导程序拥有单独的 .EFL 和 .BIN 文件。但是它与主项目共享配置和构建目录。

View File

@@ -6,8 +6,8 @@ API 指南
:maxdepth: 1
一般注意事项 <general-notes>
编译系统 <build-system>
编译系统 (CMake) <build-system-cmake>
构建系统 <build-system>
构建系统 (CMake) <build-system-cmake>
错误处理 <error-handling>
Fatal Errors <fatal-errors>
Deep Sleep Wake Stubs <deep-sleep-stub>
@@ -16,7 +16,7 @@ API 指南
FreeRTOS SMP Changes <freertos-smp>
Thread Local Storage <thread-local-storage>
High Level Interrupts <hlinterrupts>
JTAG Debugging <jtag-debugging/index>
JTAG 调试 <jtag-debugging/index>
Bootloader <bootloader>
分区表 <partition-tables>
Secure Boot <../security/secure-boot>
@@ -32,4 +32,4 @@ API 指南
ESP-MESH <mesh>
BluFi <blufi>
External SPI-connected RAM <external-ram>
Linker Script Generation <linker-script-generation>
链接脚本生成机制 <linker-script-generation>

View File

@@ -1 +1,76 @@
.. include:: ../../../en/api-guides/jtag-debugging/building-openocd-linux.rst
******************************
Linux 环境下从源码编译 OpenOCD
******************************
:link_to_translation:`en:[English]`
除了从 `Espressif 官方 <https://github.com/espressif/openocd-esp32/releases>`_ 直接下载 OpenOCD 可执行文件,你还可以选择从源码编译得到 OpenOCD。如果想要快速设置 OpenOCD 而不是自行编译,请备份好当前文件,前往 :doc:`setup-openocd-linux` 章节查阅。
.. highlight:: bash
下载 OpenOCD 源码
=================
支持 ESP32 的 OpenOCD 源代码可以从乐鑫官方的 GitHub 获得,网址为 https://github.com/espressif/openocd-esp32。请使用以下命令来下载源代码::
cd ~/esp
git clone --recursive https://github.com/espressif/openocd-esp32.git
克隆后的源代码被保存在 ``~/esp/openocd-esp32`` 目录中。
安装依赖的软件包
================
安装编译 OpenOCD 所需的软件包。
.. note::
依次安装以下软件包,检查安装是否成功,然后继续下一个软件包的安装。在进行下一步操作之前,要先解决当前报告的问题。
::
sudo apt-get install make
sudo apt-get install libtool
sudo apt-get install pkg-config
sudo apt-get install autoconf
sudo apt-get install automake
sudo apt-get install texinfo
sudo apt-get install libusb-1.0
.. note::
* pkg-config 应为 0.2.3 或以上的版本。
* autoconf 应为 2.6.4 或以上的版本。
* automake 应为 1.9 或以上的版本。
* 当使用 USB-BlasterASIX PrestoOpenJTAG 和 FT2232 作为适配器时,需要下载安装 libFTDI 和 FTD2XX 的驱动。
* 当使用 CMSIS-DAP 时,需要安装 HIDAPI。
构建 OpenOCD
============
配置和构建 OpenOCD 的流程如下::
cd ~/esp/openocd-esp32
./bootstrap
./configure
make
你可以选择最后再执行 ``sudo make install`` ,如果你已经安装过别的开发平台的 OpenOCD请跳过这个步骤因为它可能会覆盖掉原来的 OpenOCD。
.. note::
* 如果发生错误,请解决后再次尝试编译,直到 ``make`` 成功为止。
* 如果 OpenOCD 存在子模块问题,请 ``cd````openocd-esp32`` 目录,并输入 ``git submodule update --init`` 命令。
* 如果 ``./configure`` 成功运行JTAG 被使能的信息会被打印在 ``OpenOCD configuration summary`` 下面。
* 如果您的设备信息未显示在日志中,请根据 ``../openocd-esp32/doc/INSTALL.txt`` 文中的描述使用 ``./configure`` 启用它。
* 有关编译 OpenOCD 的详细信息,请参阅 ``openocd-esp32/README``
一旦 ``make`` 过程成功结束OpenOCD 的可执行文件会被保存到 ``~/openocd-esp32/bin`` 目录中。
下一步
======
想要进一步配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。

View File

@@ -1 +1,54 @@
.. include:: ../../../en/api-guides/jtag-debugging/building-openocd-macos.rst
******************************
MacOS 环境下从源码编译 OpenOCD
******************************
:link_to_translation:`en:[English]`
除了从 `Espressif 官方 <https://github.com/espressif/openocd-esp32/releases>`_ 直接下载 OpenOCD 可执行文件,你还可以选择从源码编译得到 OpenOCD。如果想要快速设置 OpenOCD 而不是自行编译,请备份好当前文件,前往 :doc:`setup-openocd-macos` 章节查阅。
.. highlight:: bash
下载 OpenOCD 源码
=================
支持 ESP32 的 OpenOCD 源代码可以从乐鑫官方的 GitHub 获得,网址为 https://github.com/espressif/openocd-esp32。请使用以下命令来下载源代码::
cd ~/esp
git clone --recursive https://github.com/espressif/openocd-esp32.git
克隆后的源代码被保存在 ``~/esp/openocd-esp32`` 目录中。
安装依赖的软件包
================
使用 Homebrew 安装编译 OpenOCD 所需的软件包::
brew install automake libtool libusb wget gcc@4.9 pkg-config
构建 OpenOCD
=============
配置和构建 OpenOCD 的流程如下::
cd ~/esp/openocd-esp32
./bootstrap
./configure
make
你可以选择最后再执行 ``sudo make install`` ,如果你已经安装过别的开发平台的 OpenOCD请跳过这个步骤因为它可能会覆盖掉原来的 OpenOCD。
.. note::
* 如果发生错误,请解决后再次尝试编译,直到 ``make`` 成功为止。
* 如果 OpenOCD 存在子模块问题,请 ``cd````openocd-esp32`` 目录,并输入 ``git submodule update --init`` 命令。
* 如果 ``./configure`` 成功运行JTAG 被使能的信息会被打印在 ``OpenOCD configuration summary`` 下面。
* 如果您的设备信息未显示在日志中,请根据 ``../openocd-esp32/doc/INSTALL.txt`` 文中的描述使用 ``./configure`` 启用它。
* 有关编译 OpenOCD 的详细信息,请参阅 ``openocd-esp32/README.OSX``
一旦 ``make`` 过程成功结束OpenOCD 的可执行文件会被保存到 ``~/esp/openocd-esp32/src/openocd`` 目录中。
下一步
======
想要进一步配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。

View File

@@ -1 +1,75 @@
.. include:: ../../../en/api-guides/jtag-debugging/building-openocd-windows.rst
********************************
Windows 环境下从源码编译 OpenOCD
********************************
:link_to_translation:`en:[English]`
除了从 `Espressif 官方 <https://github.com/espressif/openocd-esp32/releases>`_ 直接下载 OpenOCD 可执行文件,你还可以选择从源码编译得到 OpenOCD。如果想要快速设置 OpenOCD 而不是自行编译,请备份好当前文件,前往 :doc:`setup-openocd-windows` 章节查阅。
.. highlight:: bash
下载 OpenOCD 源码
=================
支持 ESP32 的 OpenOCD 源代码可以从乐鑫官方的 GitHub 获得,网址为 https://github.com/espressif/openocd-esp32。请使用以下命令来下载源代码::
cd ~/esp
git clone --recursive https://github.com/espressif/openocd-esp32.git
克隆后的源代码被保存在 ``~/esp/openocd-esp32`` 目录中。
安装依赖的软件包
================
安装编译 OpenOCD 所需的软件包。
.. note::
依次安装以下软件包,检查安装是否成功,然后继续下一个软件包的安装。在进行下一步操作之前,要先解决当前报告的问题。
::
pacman -S libtool
pacman -S autoconf
pacman -S automake
pacman -S texinfo
pacman -S mingw-w64-i686-libusb-compat-git
pacman -S pkg-config
.. note::
安装 ``pkg-config`` 会破坏 esp-idf 的工具链,因而在 OpenOCD 构建完成后,应将其卸载。详见文末进一步说明。如果想要再次构建 OpenOCD你需要再次运行 ``pacman -S pkg-config``。此步骤安装的其他软件包(在 ``pkg-config`` 之前)并不会出现这一问题。
构建 OpenOCD
============
配置和构建 OpenOCD 的流程如下::
cd ~/esp/openocd-esp32
./bootstrap
./configure
make
你可以选择最后再执行 ``sudo make install`` ,如果你已经安装过别的开发平台的 OpenOCD请跳过这个步骤因为它可能会覆盖掉原来的 OpenOCD。
.. note::
* 如果发生错误,请解决后再次尝试编译,直到 ``make`` 成功为止。
* 如果 OpenOCD 存在子模块问题,请 ``cd````openocd-esp32`` 目录,并输入 ``git submodule update --init`` 命令。
* 如果 ``./configure`` 成功运行JTAG 被使能的信息会被打印在 ``OpenOCD configuration summary`` 下面。
* 如果您的设备信息未显示在日志中,请根据 ``../openocd-esp32/doc/INSTALL.txt`` 文中的描述使用 ``./configure`` 启用它。
* 有关编译 OpenOCD 的详细信息,请参阅 ``openocd-esp32/README.Windows``
一旦 ``make`` 过程成功完成OpenOCD 的可执行文件会被保存到 ``~/esp/openocd-esp32/src/openocd`` 目录中。
如安装依赖步骤所述,最后还需要移除 ``pkg-config`` 软件包::
pacman -Rs pkg-config
下一步
======
想要进一步配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。

View File

@@ -1 +1,46 @@
.. include:: ../../../en/api-guides/jtag-debugging/configure-other-jtag.rst
配置其它 JTAG 接口
==================
:link_to_translation:`en:[English]`
关于适配 OpenOCD 和 ESP32 的 JTAG 接口选择问题,请参考 :ref:`jtag-debugging-selecting-jtag-adapter` 章节,确保 JTAG 适配器能够与 OpenOCD 和 ESP32 一同工作。然后按照以下三个步骤进行设置,使其正常工作。
配置硬件
^^^^^^^^
1. 找到 JTAG 接口和 ESP32 板上需要相互连接并建立通信的引脚/信号。
+---+---------------+-----------+
| | ESP32 引脚 | JTAG 信号 |
+===+===============+===========+
| 1 | CHIP_PU | TRST_N |
+---+---------------+-----------+
| 2 | MTDO / GPIO15 | TDO |
+---+---------------+-----------+
| 3 | MTDI / GPIO12 | TDI |
+---+---------------+-----------+
| 4 | MTCK / GPIO13 | TCK |
+---+---------------+-----------+
| 5 | MTMS / GPIO14 | TMS |
+---+---------------+-----------+
| 6 | GND | GND |
+---+---------------+-----------+
2. 检查 ESP32 上用于 JTAG 通信的的引脚是否被连接到了其它硬件上,这可能会影响 JTAG 的工作。
3. 连接 ESP32 和 JTAG 接口上的引脚/信号。
配置驱动
^^^^^^^^
你可能还需要安装软件驱动,才能使 JTAG 在计算机上正常工作,请参阅你所使用的 JTAG 适配器的有关文档,获取相关详细信息。
连接
^^^^
将 JTAG 接口连接到计算机,打开 ESP32 和 JTAG 接口板上的电源,然后检查计算机是否可以识别到 JTAG 接口。
要继续设置调试环境,请前往 :ref:`jtag-debugging-run-openocd` 章节。

View File

@@ -1 +1,198 @@
.. include:: ../../../en/api-guides/jtag-debugging/configure-wrover.rst
配置 WROVER 上的 JTAG 接口
==========================
:link_to_translation:`en:[English]`
所有版本的 ESP-WROVER-KIT 板子都内置了 JTAG 调试功能,要使其正常工作,还需要设置相关跳帽来启用 JTAG 功能,设置 SPI 闪存电压和配置 USB 驱动程序。具体步骤请参考以下说明。
配置硬件
^^^^^^^^
1. 根据 :doc:`../../get-started/get-started-wrover-kit` 文档中 :ref:`get-started-esp-wrover-kit-setup-options` 章节所描述的信息,设置 JP8 便可以启用 JTAG 功能。
2. 检查 ESP32 上用于 JTAG 通信的引脚是否被接到了其它硬件上,这可能会影响 JTAG 的工作。
+---+---------------+-----------+
| | ESP32 引脚 | JTAG 信号 |
+===+===============+===========+
| 1 | CHIP_PU | TRST_N |
+---+---------------+-----------+
| 2 | MTDO / GPIO15 | TDO |
+---+---------------+-----------+
| 3 | MTDI / GPIO12 | TDI |
+---+---------------+-----------+
| 4 | MTCK / GPIO13 | TCK |
+---+---------------+-----------+
| 5 | MTMS / GPIO14 | TMS |
+---+---------------+-----------+
配置 USB 驱动
^^^^^^^^^^^^^
安装和配置 USB 驱动,这样 OpenOCD 才能够与 ESP-WROVER-KIT 板上的 JTAG 接口通信,并且使用 UART 接口上传待烧写的镜像文件。请根据你的操作系统按照以下步骤进行安装配置。
.. note:: ESP-WROVER-KIT 使用了 FT2232 芯片实现了 JTAG 适配器,所以以下说明同样适用于其他基于 FT2232 的 JTAG 适配器。
Windows
"""""""
1. 使用标准 USB A / micro USB B 线将 ESP-WROVER-KIT 与计算机相连接,并打开板子的电源。
2. 等待 Windows 识别出 ESP-WROVER-KIT 并且为其安装驱动。如果驱动没有被自动安装,请前往 `官网 <http://www.ftdichip.com/Drivers/D2XX.htm>`_ 下载并手动安装。
3.`Zadig 官网 <http://zadig.akeo.ie/>`_ 下载 Zadig 工具Zadig_X.X.exe并运行。
4. 在 Zadig 工具中,进入 “Options” 菜单中选中 “List All Devices”。
5. 检查设备列表,其中应该包含两条与 ESP-WROVER-KIT 相关的条目“Dual RS232-HS (Interface 0)” 和 “Dual RS232-HS (Interface 1)”。驱动的名字应该是 “FTDIBUS (vxxxx)” 并且 USB ID 为0403 6010。
.. figure:: ../../../_static/jtag-usb-configuration-zadig.jpg
:align: center
:alt: Configuration of JTAG USB driver in Zadig tool
:figclass: align-center
在 Zadig 工具中配置 JTAG USB 驱动
6. 第一个设备 “Dual RS232-HSInterface 0” 连接到了 ESP32 的 JTAG 端口,此设备原来的 “FTDIBUS (vxxxx)” 驱动需要替换成 "WinUSB (v6xxxxx)"。为此,请选择 “Dual RS232-HS (Interface 0)” 并将驱动重新安装为 “WinUSB (v6xxxxx)”,具体可以参考上图。
.. note::
请勿更改第二个设备 “Dual RS232-HSInterface 1” 的驱动,它被连接到 ESP32 的串口UART用于上传应用程序映像给 ESP32 进行烧写。
现在ESP-WROVER-KIT 的 JTAG 接口应该可以被 OpenOCD 使用了,想要进一步设置调试环境,请前往 :ref:`jtag-debugging-run-openocd` 章节。
Linux
"""""
1. 使用标准 USB A / micro USB B 线将 ESP-WROVER-KIT 与计算机相连接,并打开板子的电源。
.. highlight:: none
2. 打开终端,输入 ``ls -l /dev/ttyUSB*`` 命令检查操作系统是否能够识别板子的 USB 端口。类似识别结果如下:
::
user-name@computer-name:~/esp$ ls -l /dev/ttyUSB*
crw-rw---- 1 root dialout 188, 0 Jul 10 19:04 /dev/ttyUSB0
crw-rw---- 1 root dialout 188, 1 Jul 10 19:04 /dev/ttyUSB1
3. 根据 `OpenOCD README 文档 <https://sourceforge.net/p/openocd/code/ci/master/tree/README>`_ 中 “Permissions delegation” 小节的介绍,设置这两个 USB 端口的访问权限。
4. 注销并重新登录 Linux 系统,然后重新插拔板子的电源使之前的改动生效。在终端再次输入 ``ls -l /dev/ttyUSB*`` 命令进行验证,查看这两个设备的组所有者是否已经从 ``dialout`` 更改为 ``plugdev``:
::
user-name@computer-name:~/esp$ ls -l /dev/ttyUSB*
crw-rw-r-- 1 root plugdev 188, 0 Jul 10 19:07 /dev/ttyUSB0
crw-rw-r-- 1 root plugdev 188, 1 Jul 10 19:07 /dev/ttyUSB1
如果看到类似的输出结果,并且你也是 ``plugdev`` 组的成员, 那么设置工作就完成了。
具有较低编号的 ``/dev/ttyUSBn`` 接口用于 JTAG 通信,另一路接口被连接到 ESP32 的串口UART用于上传应用程序映像给 ESP32 进行烧写。
现在ESP-WROVER-KIT 的 JTAG 接口应该可以被 OpenOCD 使用了,想要进一步设置调试环境,请前往 :ref:`jtag-debugging-run-openocd` 章节。
MacOS
"""""
在 macOS 上,同时使用 FT2232 的 JTAG 接口和串口还需另外进行其它操作。当操作系统加载 FTDI 串口驱动的时候,它会对 FT2232 芯片的两个通道做相同的操作。但是,这两个通道中只有一个是被用作串口,而另一个用于 JTAG如果操作系统已经为用于 JTAG 的通道加载了 FTDI 串口驱动的话OpenOCD 将无法连接到芯片。有两个方法可以解决这个问题:
1. 在启动 OpenOCD 之前手动卸载 FTDI 串口驱动程序,然后启动 OpenOCD再加载串口驱动程序。
2. 修改 FTDI 驱动程序的配置,使其不会为 FT2232 芯片的通道 B 进行自我加载,该通道用于 ESP-WROVER-KIT 板上的 JTAG 通道。
手动卸载驱动程序
................
1.`FTDI 官网 <http://www.ftdichip.com/Drivers/VCP.htm>`_ 安装驱动。
2. 使用 USB 线连接 ESP-WROVER-KIT。
3. 卸载串口驱动 ::
sudo kextunload -b com.FTDI.driver.FTDIUSBSerialDriver
有时,您可能还需要卸载苹果的 FTDI 驱动::
sudo kextunload -b com.apple.driver.AppleUSBFTDI
4. 运行 OpenOCD以下路径为 Github 上可供下载的预编译后的 OpenOCD::
bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg
如果 OpenOCD 是从源码编译得到的,那么路径需要做相应修改::
src/openocd -s tcl -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg
5. 在另一个终端窗口,再一次加载 FTDI 串口驱动::
sudo kextload -b com.FTDI.driver.FTDIUSBSerialDriver
.. include:: ./windows-openocd-note.rst
.. note::
如果你需要重启 OpenOCD则无需再次卸载 FTDI 驱动程序,只需停止 OpenOCD 并再次启动它。只有在重新连接 ESP-WROVER-KIT 或者切换了电源的情况下才需要再次卸载驱动。
你也可以根据自身需求,将此过程包装进 shell 脚本中。
修改 FTDI 驱动
..............
简而言之,这种方法需要修改 FTDI 驱动程序的配置文件,这样可以防止为 FT2232H 的通道 B 自动加载串口驱动。
.. note:: 其他板子可能将通道 A 用于 JTAG因此请谨慎使用此选项。
.. warning:: 此方法还需要操作系统禁止对驱动进行签名验证,因此可能无法被所有的用户所接受。
1. 使用文本编辑器打开 FTDI 驱动的配置文件(注意 ``sudo``::
sudo nano /Library/Extensions/FTDIUSBSerialDriver.kext/Contents/Info.plist
2. 找到并删除以下几行::
<key>FT2232H_B</key>
<dict>
<key>CFBundleIdentifier</key>
<string>com.FTDI.driver.FTDIUSBSerialDriver</string>
<key>IOClass</key>
<string>FTDIUSBSerialDriver</string>
<key>IOProviderClass</key>
<string>IOUSBInterface</string>
<key>bConfigurationValue</key>
<integer>1</integer>
<key>bInterfaceNumber</key>
<integer>1</integer>
<key>bcdDevice</key>
<integer>1792</integer>
<key>idProduct</key>
<integer>24592</integer>
<key>idVendor</key>
<integer>1027</integer>
</dict>
3. 保存并关闭文件
4. 禁用驱动的签名认证:
1. 点击苹果的 logo选择 “Restart...”
2. 重启后当听到响铃时,立即按下键盘上的 CMD+R 组合键
3. 进入恢复模式后,打开终端
4. 运行命令::
csrutil enable --without kext
5. 再一次重启系统
完成这些步骤后,可以同时使用串口和 JTAG 接口了。
想要进一步设置调试环境,请前往 :ref:`jtag-debugging-run-openocd` 章节。

View File

@@ -1 +1,655 @@
.. include:: ../../../en/api-guides/jtag-debugging/debugging-examples.rst
调试示例
========
:link_to_translation:`en:[English]`
本节将介绍如何在 :ref:`Eclipse <jtag-debugging-examples-eclipse>`:ref:`命令行 <jtag-debugging-examples-command-line>` 中使用 GDB 进行调试的示例。
.. highlight:: none
.. _jtag-debugging-examples-eclipse:
使用 Eclipse 的调试示例
-----------------------
请检查目标板是否已经准备好,并加载了 :example:`get-started/blink` 示例代码,然后按照 :ref:`jtag-debugging-using-debugger-eclipse` 中介绍的步骤配置和启动调试器,最后选择让应用程序在 ``app_main()`` 建立的断点处停止。
.. figure:: ../../../_static/debug-perspective.jpg
:align: center
:alt: Debug Perspective in Eclipse
:figclass: align-center
Eclipse 中的 Debug 视图
本小节的示例
^^^^^^^^^^^^
1. :ref:`jtag-debugging-examples-eclipse-01`
2. :ref:`jtag-debugging-examples-eclipse-02`
3. :ref:`jtag-debugging-examples-eclipse-03`
4. :ref:`jtag-debugging-examples-eclipse-04`
5. :ref:`jtag-debugging-examples-eclipse-05`
6. :ref:`jtag-debugging-examples-eclipse-06`
7. :ref:`jtag-debugging-examples-eclipse-07`
.. _jtag-debugging-examples-eclipse-01:
浏览代码,查看堆栈和线程
^^^^^^^^^^^^^^^^^^^^^^^^
当目标暂停时,调试器会在 “Debug” 窗口中显示线程的列表,程序暂停的代码行在下面的另一个窗口中被高亮显示,如下图所示。此时板子上的 LED 停止了闪烁。
.. figure:: ../../../_static/debugging-target-halted.jpg
:align: center
:alt: Target halted during debugging
:figclass: align-center
调试时目标停止
暂停的程序所在线程也会被展开显示函数调用的堆栈它表示直到目标暂停所在代码行下图高亮处为止的相关函数的调用关系。1 号线程下函数调用堆栈的第一行包含了最后一个调用的函数 ``app_main()``,根据下一行显示,它又是在函数 ``main_task()`` 中被调用的。堆栈的每一行还包含调用函数的文件名和行号。通过单击每个堆栈的条目,在下面的窗口中,你将看到此文件的内容。
通过展开线程,你可以浏览整个应用程序。展开 5 号线程,它包含了更长的函数调用堆栈,你可以看到函数调用旁边的数字,比如 ``0x4000000c``,它们代表未以源码形式提供的二进制代码所在的内存地址。
.. figure:: ../../../_static/debugging-navigate-through-the-stack.jpg
:align: center
:alt: Navigate through the call stack
:figclass: align-center
浏览函数调用堆栈
无论项目是以源代码还是仅以二进制形式提供,在右边一个窗口中,都可以看到反汇编后的机器代码。
回到 1 号线程中的 ``app_main()`` 函数所在的 ``blink.c`` 源码文件,下面的示例将会以该文件为例介绍调试的常用功能。调试器可以轻松浏览整个应用程序的代码,这给单步调试代码和设置断点带来了很大的便利,下面将一一展开讨论。
.. _jtag-debugging-examples-eclipse-02:
设置和清除断点
^^^^^^^^^^^^^^
在调试时,我们希望能够在关键的代码行停止应用程序,然后检查特定的变量、内存、寄存器和外设的状态。为此我们需要使用断点,以便在特定某行代码处快速访问和停止应用程序。
我们在控制 LED 状态发生变化的两处代码行分别设置一个断点。基于以上代码列表,这两处分别为第 33 和 36 代码行。按住键盘上的 “Control” 键,双击 blink.c 文件中的行号 33并在弹出的对话框中点击 “OK” 按钮进行确定。如果你不想看到此对话框,双击行号即可。执行同样操作,在第 36 行设置另外一个断点。
.. figure:: ../../../_static/debugging-setting-breakpoint.jpg
:align: center
:alt: Setting a breakpoint
:figclass: align-center
设置断点
断点的数量和位置信息会显示在右上角的“断点”窗口中。单击 “Show Breakpoints Supported by Selected Target” 图标可以刷新此列表。除了刚才设置的两个断点外,列表中可能还包含在调试器启动时设置在 ``app_main()`` 函数处的临时断点。由于最多只允许设置两个断点(详细信息请参阅 :ref:`jtag-debugging-tip-breakpoints`),你需要将其删除,否则调试会失败。
.. figure:: ../../../_static/debugging-three-breakpoints-set.jpg
:align: center
:alt: Three breakpoints are set / maximum two are allowed
:figclass: align-center
设置了三个断点 / 最多允许两个断点
单击 “Resume”如果 “Resume” 按钮是灰色的,请先单击 8 号线程的 ``blink_task()`` 函数)后处理器将开始继续运行,并在断点处停止。再一次单击 “Resume” 按钮,使程序再次运行,然后停在第二个断点处,依次类推。
每次单击 “Resume” 按钮恢复程序运行后,都会看到 LED 切换状态。
更多关于断点的信息,请参阅 :ref:`jtag-debugging-tip-breakpoints`:ref:`jtag-debugging-tip-where-breakpoints`
.. _jtag-debugging-examples-eclipse-03:
手动暂停目标
^^^^^^^^^^^^
在调试时,你可以恢复程序运行并输入代码等待某个事件发生或者保持无限循环而不设置任何断点。后者,如果想要返回调试模式,可以通过单击 “Suspend” 按钮来手动中断程序的运行。
在此之前,请删除所有的断点,然后单击 “Resume” 按钮。接着单击 “Suspend” 按钮,应用程序会停止在某个随机的位置,此时 LED 也将停止闪烁。调试器将展开线程并高亮显示停止的代码行。
.. figure:: ../../../_static/debugging-target-halted-manually.jpg
:align: center
:alt: Target halted manually
:figclass: align-center
手动暂停目标
在上图所示的情况中,应用程序已经在 ``freertos_hooks.c`` 文件的第 52 行暂停运行,现在你可以通过单击 “Resume” 按钮再次将其恢复运行或者进行下面要介绍的调试工作。
.. _jtag-debugging-examples-eclipse-04:
单步执行代码
^^^^^^^^^^^^
我们还可以使用 “Step Into (F5)” 和 “Step Over (F6)” 命令单步执行代码, 这两者之间的区别是执行 “Step Into (F5)” 命令会进入调用的子程序,而执行 “Step Over (F6)” 命令则会直接将子程序看成单个源码行,单步就能将其运行结束。
在继续演示此功能之前,请参照上文所述确保目前只在 ``blink.c`` 文件的第 36 行设置了一个断点。
按下 F8 键让程序继续运行然后在断点处停止运行,多次按下 “Step Over (F6)” 按钮,观察调试器是如何单步执行一行代码的。
.. figure:: ../../../_static/debugging-step-over.jpg
:align: center
:alt: Stepping through the code with "Step Over (F6)"
:figclass: align-center
使用 “Step Over (F6)” 单步执行代码
如果你改用 "Step Into (F5)",那么调试器将会进入调用的子程序内部。
.. figure:: ../../../_static/debugging-step-into.jpg
:align: center
:alt: Stepping through the code with "Step Into (F5)"
:figclass: align-center
使用 “Step Into (F5)” 单步执行代码
在上述例子中,调试器进入 ``gpio_set_level(BLINK_GPIO, 0)`` 代码内部,同时代码窗口快速切换到 ``gpio.c`` 驱动文件。
请参阅 :ref:`jtag-debugging-tip-why-next-works-as-step` 文档以了解 ``next`` 命令的潜在局限。
.. _jtag-debugging-examples-eclipse-05:
查看并设置内存
^^^^^^^^^^^^^^
要显示或者设置内存的内容,请使用“调试”视图中位于底部的 “Memory” 选项卡。
在 “Memory” 选项卡下,我们将在内存地址 ``0x3FF44004`` 处读取和写入内容。该地址也是 ``GPIO_OUT_REG`` 寄存器的地址,可以用来控制(设置或者清除)某个 GPIO 的电平。关于该寄存器的更多详细信息,请参阅 `ESP32 技术参考手册 <https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_cn.pdf>`_ 中的 IO_MUX 和 GPIO Matrix 章节。
同样在 ``blink.c`` 项目文件中,在两个 ``gpio_set_level`` 语句的后面各设置一个断点,单击 “Memory” 选项卡,然后单击 “Add Memory Monitor” 按钮,在弹出的对话框中输入 ``0x3FF44004``
按下 F8 按键恢复程序运行,并观察 “Monitor” 选项卡。
.. figure:: ../../../_static/debugging-memory-location-on.jpg
:align: center
:alt: Observing memory location 0x3FF44004 changing one bit to ON"
:figclass: align-center
观察内存地址 0x3FF44004 处的某个比特被置高
每按一下 F8你就会看到在内存 ``0x3FF44004`` 地址处的一个比特位被翻转(并且 LED 会改变状态)。
.. figure:: ../../../_static/debugging-memory-location-off.jpg
:align: center
:alt: Observing memory location 0x3FF44004 changing one bit to ON"
:figclass: align-center
观察内存地址 0x3FF44004 处的某个比特被置低
要修改内存的数值,请在 “Monitor” 选项卡中找到待修改的内存地址,如前面观察的结果一样,输入特定比特翻转后的值。当按下回车键后,将立即看到 LED 的状态发生了改变。
.. _jtag-debugging-examples-eclipse-06:
观察和设置程序变量
^^^^^^^^^^^^^^^^^^
常见的调试任务是在程序运行期间检查程序中某个变量的值,为了演示这个功能,更新 ``blink.c`` 文件,在 ``blink_task`` 函数的上面添加一个全局变量的声明 ``int i``,然后在 ``while(1)`` 里添加 ``i++``,这样每次 LED 改变状态的时候,变量 ``i`` 都会增加 1。
退出调试器,这样就不会与新代码混淆,然后重新构建并烧写代码到 ESP32 中,接着重启调试器。注意,这里不需要我们重启 OpenOCD。
一旦程序停止运行,在代码 ``i++`` 处添加一个断点。
下一步,在 “Breakpoints” 所在的窗口中,选择 “Expressions” 选项卡。如果该选项卡不存在,请在顶部菜单栏的 Window > Show View > Expressions 中添加这一选项卡。然后在该选项卡中单击 “Add new expression”并输入 ``i``
按下 F8 继续运行程序,每次程序停止时,都会看到变量 ``i`` 的值在递增。
.. figure:: ../../../_static/debugging-watch-variable.jpg
:align: center
:alt: Watching program variable "i"
:figclass: align-center
观察程序变量 “i”
如想更改 ``i`` 的值,可以在 “Value” 一栏中输入新的数值。按下 “Resume (F8)” 后,程序将从新输入的数字开始递增 ``i``
.. _jtag-debugging-examples-eclipse-07:
设置条件断点
^^^^^^^^^^^^
接下来的内容更为有趣,你可能想在一定条件满足的情况下设置断点,然后让程序停止运行。右击断点打开上下文菜单,选择 “Breakpoint Properties”将 “Type:” 改选为 “Hardware” 然后在 “Condition:” 一栏中输入条件表达式,例如 ``i == 2``
.. figure:: ../../../_static/debugging-setting-conditional-breakpoint.jpg
:align: center
:alt: Setting a conditional breakpoint
:figclass: align-center
设置条件断点
如果当前 ``i`` 的值小于 ``2`` (如果有需要也可以更改这个阈值)并且程序被恢复运行,那么 LED 就会循环闪烁,直到 ``i == 2`` 条件成立,最后程序停止在该处。
.. _jtag-debugging-examples-command-line:
使用命令行的调试示例
--------------------
请检查您的目标板是否已经准备好,并加载了 :example:`get-started/blink` 示例代码,然后按照 :ref:`jtag-debugging-using-debugger-command-line` 中介绍的步骤配置和启动调试器,最后选择让应用程序在 ``app_main()`` 建立的断点处停止运行 ::
Temporary breakpoint 1, app_main () at /home/user-name/esp/blink/main/./blink.c:43
43 xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
(gdb)
本小节的示例
^^^^^^^^^^^^
1. :ref:`jtag-debugging-examples-command-line-01`
2. :ref:`jtag-debugging-examples-command-line-02`
3. :ref:`jtag-debugging-examples-command-line-03`
4. :ref:`jtag-debugging-examples-command-line-04`
5. :ref:`jtag-debugging-examples-command-line-05`
6. :ref:`jtag-debugging-examples-command-line-06`
7. :ref:`jtag-debugging-examples-command-line-07`
.. _jtag-debugging-examples-command-line-01:
浏览代码,查看堆栈和线程
^^^^^^^^^^^^^^^^^^^^^^^^
当看到 ``(gdb)`` 提示符的时候应用程序已停止运行LED 也停止闪烁。
要找到代码暂停的位置,输入 ``l`` 或者 ``list`` 命令,调试器会打印出停止点(``blink.c`` 代码文件的第 43 行)附近的几行代码 ::
(gdb) l
38 }
39 }
40
41 void app_main()
42 {
43 xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
44 }
(gdb)
也可以通过输入 ``l 30, 40`` 等命令来查看特定行号范围内的代码。
使用 ``bt`` 或者 ``backtrace`` 来查看哪些函数最终导致了此代码被调用::
(gdb) bt
#0 app_main () at /home/user-name/esp/blink/main/./blink.c:43
#1 0x400d057e in main_task (args=0x0) at /home/user-name/esp/esp-idf/components/esp32/./cpu_start.c:339
(gdb)
输出的第 0 行表示应用程序暂停之前调用的最后一个函数,即我们之前列出的 ``app_main ()````app_main ()`` 又被位于 ``cpu_start.c`` 文件第 339 行的 ``main_task`` 函数调用。
想查看 ``cpu_start.c`` 文件中 ``main_task`` 函数的上下文,需要输入 ``frame N``,其中 N = 1因为根据前面的输出``main_task`` 位于 #1 下::
(gdb) frame 1
#1 0x400d057e in main_task (args=0x0) at /home/user-name/esp/esp-idf/components/esp32/./cpu_start.c:339
339 app_main();
(gdb)
输入 ``l`` 将显示一段名为 ``app_main()`` 的代码(在第 339 行)::
(gdb) l
334 ;
335 }
336 #endif
337 //Enable allocation in region where the startup stacks were located.
338 heap_caps_enable_nonos_stack_heaps();
339 app_main();
340 vTaskDelete(NULL);
341 }
342
(gdb)
通过打印前面的一些行,你会看到我们一直在寻找的 ``main_task`` 函数::
(gdb) l 326, 341
326 static void main_task(void* args)
327 {
328 // Now that the application is about to start, disable boot watchdogs
329 REG_CLR_BIT(TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN_S);
330 REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
331 #if !CONFIG_FREERTOS_UNICORE
332 // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack
333 while (port_xSchedulerRunning[1] == 0) {
334 ;
335 }
336 #endif
337 //Enable allocation in region where the startup stacks were located.
338 heap_caps_enable_nonos_stack_heaps();
339 app_main();
340 vTaskDelete(NULL);
341 }
(gdb)
如果要查看其他代码,可以输入 ``i threads`` 命令,则会输出目标板上运行的线程列表::
(gdb) i threads
Id Target Id Frame
8 Thread 1073411336 (dport) 0x400d0848 in dport_access_init_core (arg=<optimized out>)
at /home/user-name/esp/esp-idf/components/esp32/./dport_access.c:170
7 Thread 1073408744 (ipc0) xQueueGenericReceive (xQueue=0x3ffae694, pvBuffer=0x0, xTicksToWait=1644638200,
xJustPeeking=0) at /home/user-name/esp/esp-idf/components/freertos/./queue.c:1452
6 Thread 1073431096 (Tmr Svc) prvTimerTask (pvParameters=0x0)
at /home/user-name/esp/esp-idf/components/freertos/./timers.c:445
5 Thread 1073410208 (ipc1 : Running) 0x4000bfea in ?? ()
4 Thread 1073432224 (dport) dport_access_init_core (arg=0x0)
at /home/user-name/esp/esp-idf/components/esp32/./dport_access.c:150
3 Thread 1073413156 (IDLE) prvIdleTask (pvParameters=0x0)
at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:3282
2 Thread 1073413512 (IDLE) prvIdleTask (pvParameters=0x0)
at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:3282
* 1 Thread 1073411772 (main : Running) app_main () at /home/user-name/esp/blink/main/./blink.c:43
(gdb)
线程列表显示了每个线程最后一个被调用的函数以及所在的 C 源文件名(如果存在的话)。
您可以通过输入 ``thread N`` 进入特定的线程,其中 ``N`` 是线程 ID。我们进入 5 号线程来看一下它是如何工作的::
(gdb) thread 5
[Switching to thread 5 (Thread 1073410208)]
#0 0x4000bfea in ?? ()
(gdb)
然后查看回溯::
(gdb) bt
#0 0x4000bfea in ?? ()
#1 0x40083a85 in vPortCPUReleaseMutex (mux=<optimized out>) at /home/user-name/esp/esp-idf/components/freertos/./port.c:415
#2 0x40083fc8 in vTaskSwitchContext () at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:2846
#3 0x4008532b in _frxt_dispatch ()
#4 0x4008395c in xPortStartScheduler () at /home/user-name/esp/esp-idf/components/freertos/./port.c:222
#5 0x4000000c in ?? ()
#6 0x4000000c in ?? ()
#7 0x4000000c in ?? ()
#8 0x4000000c in ?? ()
(gdb)
如上所示,回溯可能会包含多个条目,方便查看直至目标停止运行的函数调用顺序。如果找不到某个函数的源码文件,将会使用问号 ``??`` 替代,这表示该函数是以二进制格式提供的。像 ``0x4000bfea`` 这样的值是被调用函数所在的内存地址。
使用诸如 ``bt`` ``i threads`` ``thread N````list`` 命令可以浏览整个应用程序的代码。这给单步调试代码和设置断点带来很大的便利,下面将一一展开来讨论。
.. _jtag-debugging-examples-command-line-02:
设置和清除断点
^^^^^^^^^^^^^^
在调试时,我们希望能够在关键的代码行停止应用程序,然后检查特定的变量、内存、寄存器和外设的状态。为此我们需要使用断点,以便在特定某行代码处快速访问和停止应用程序。
我们在控制 LED 状态发生变化的两处代码行分别设置一个断点。基于以上代码列表,这两处分别为第 33 和 36 代码行。使用命令 ``break M`` 设置断点,其中 M 是具体的代码行::
(gdb) break 33
Breakpoint 2 at 0x400db6f6: file /home/user-name/esp/blink/main/./blink.c, line 33.
(gdb) break 36
Breakpoint 3 at 0x400db704: file /home/user-name/esp/blink/main/./blink.c, line 36.
输入命令 ``c``,处理器将运行并在断点处停止。再次输入 ``c`` 将使其再次运行,并在第二个断点处停止,依此类推::
(gdb) c
Continuing.
Target halted. PRO_CPU: PC=0x400DB6F6 (active) APP_CPU: PC=0x400D10D8
Breakpoint 2, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:33
33 gpio_set_level(BLINK_GPIO, 0);
(gdb) c
Continuing.
Target halted. PRO_CPU: PC=0x400DB6F8 (active) APP_CPU: PC=0x400D10D8
Target halted. PRO_CPU: PC=0x400DB704 (active) APP_CPU: PC=0x400D10D8
Breakpoint 3, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:36
36 gpio_set_level(BLINK_GPIO, 1);
(gdb)
只有在输入命令 ``c`` 恢复程序运行后才能看到 LED 改变状态。
查看已设置断点的数量和位置,请使用命令 ``info break``::
(gdb) info break
Num Type Disp Enb Address What
2 breakpoint keep y 0x400db6f6 in blink_task at /home/user-name/esp/blink/main/./blink.c:33
breakpoint already hit 1 time
3 breakpoint keep y 0x400db704 in blink_task at /home/user-name/esp/blink/main/./blink.c:36
breakpoint already hit 1 time
(gdb)
请注意,断点序号(在 ``Num`` 栏列出)从 2 开始,这是因为在调试器启动时执行 ``thb app_main`` 命令已经在 ``app_main()`` 函数处建立了第一个断点。由于它是一个临时断点,已经被自动删除,所以没有被列出。
要删除一个断点,请输入 ``delete N`` 命令(或者简写成 ``d N``),其中 ``N`` 代表断点序号::
(gdb) delete 1
No breakpoint number 1.
(gdb) delete 2
(gdb)
更多关于断点的信息,请参阅 :ref:`jtag-debugging-tip-breakpoints`:ref:`jtag-debugging-tip-where-breakpoints`
.. _jtag-debugging-examples-command-line-03:
暂停和恢复应用程序的运行
^^^^^^^^^^^^^^^^^^^^^^^^
在调试时,可以恢复程序运行并输入代码等待某个事件发生或者保持无限循环而不设置任何断点。对于后者,想要返回调试模式,可以通过输入 Ctrl+C 手动中断程序的运行。
在此之前,请删除所有的断点,然后输入 ``c`` 恢复程序运行。接着输入 Ctrl+C应用程序会停止在某个随机的位置此时 LED 也将停止闪烁。调试器会打印如下信息::
(gdb) c
Continuing.
^CTarget halted. PRO_CPU: PC=0x400D0C00 APP_CPU: PC=0x400D0C00 (active)
[New Thread 1073433352]
Program received signal SIGINT, Interrupt.
[Switching to Thread 1073413512]
0x400d0c00 in esp_vApplicationIdleHook () at /home/user-name/esp/esp-idf/components/esp32/./freertos_hooks.c:52
52 asm("waiti 0");
(gdb)
在上图所示的情况下,应用程序已经在 ``freertos_hooks.c`` 文件的第 52 行暂停运行,现在您可以通过输入 ``c`` 再次将其恢复运行或者进行如下所述的一些调试工作。
.. note::
在 MSYS2 的 shell 中输入 Ctrl+C 并不会暂停目标的运行,而是会退出调试器。解决这个问题的方法可以通过 :ref:`使用 Eclipse 来调试 <jtag-debugging-examples-eclipse>` 或者参考 http://www.mingw.org/wiki/Workaround_for_GDB_Ctrl_C_Interrupt 里的解决方案。
.. _jtag-debugging-examples-command-line-04:
单步执行代码
^^^^^^^^^^^^
我们还可以使用 ``step````next`` 命令(可以简写成 ``s````n``)单步执行代码, 这两者之间的区别是执行 “step” 命令会进入调用的子程序内部,而执行 “next” 命令则会直接将子程序看成单个源码行,单步就能将其运行结束。
在继续演示此功能之前,请使用前面介绍的 ``break````delete`` 命令,确保目前只在 ``blink.c`` 文件的第 36 行设置了一个断点::
(gdb) info break
Num Type Disp Enb Address What
3 breakpoint keep y 0x400db704 in blink_task at /home/user-name/esp/blink/main/./blink.c:36
breakpoint already hit 1 time
(gdb)
输入 ``c`` 恢复程序运行然后等它在断点处停止运行::
(gdb) c
Continuing.
Target halted. PRO_CPU: PC=0x400DB754 (active) APP_CPU: PC=0x400D1128
Breakpoint 3, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:36
36 gpio_set_level(BLINK_GPIO, 1);
(gdb)
然后输入 ``n`` 多次,观察调试器是如何单步执行一行代码的::
(gdb) n
Target halted. PRO_CPU: PC=0x400DB756 (active) APP_CPU: PC=0x400D1128
Target halted. PRO_CPU: PC=0x400DB758 (active) APP_CPU: PC=0x400D1128
Target halted. PRO_CPU: PC=0x400DC04C (active) APP_CPU: PC=0x400D1128
Target halted. PRO_CPU: PC=0x400DB75B (active) APP_CPU: PC=0x400D1128
37 vTaskDelay(1000 / portTICK_PERIOD_MS);
(gdb) n
Target halted. PRO_CPU: PC=0x400DB75E (active) APP_CPU: PC=0x400D1128
Target halted. PRO_CPU: PC=0x400846FC (active) APP_CPU: PC=0x400D1128
Target halted. PRO_CPU: PC=0x400DB761 (active) APP_CPU: PC=0x400D1128
Target halted. PRO_CPU: PC=0x400DB746 (active) APP_CPU: PC=0x400D1128
33 gpio_set_level(BLINK_GPIO, 0);
(gdb)
如果你输入 ``s``,那么调试器将进入子程序::
(gdb) s
Target halted. PRO_CPU: PC=0x400DB748 (active) APP_CPU: PC=0x400D1128
Target halted. PRO_CPU: PC=0x400DB74B (active) APP_CPU: PC=0x400D1128
Target halted. PRO_CPU: PC=0x400DC04C (active) APP_CPU: PC=0x400D1128
Target halted. PRO_CPU: PC=0x400DC04F (active) APP_CPU: PC=0x400D1128
gpio_set_level (gpio_num=GPIO_NUM_4, level=0) at /home/user-name/esp/esp-idf/components/driver/./gpio.c:183
183 GPIO_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "GPIO output gpio_num error", ESP_ERR_INVALID_ARG);
(gdb)
上述例子中,调试器进入 ``gpio_set_level(BLINK_GPIO, 0)`` 代码内部,同时代码窗口快速切换到 ``gpio.c`` 驱动文件。
请参阅 :ref:`jtag-debugging-tip-why-next-works-as-step` 文档以了解 ``next`` 命令的潜在局限。
.. _jtag-debugging-examples-command-line-05:
查看并设置内存
^^^^^^^^^^^^^^
使用命令 ``x`` 可以显示内存的内容,配合其余参数还可以调整所显示内存位置的格式和数量。运行 ``help x`` 可以查看更多相关细节。与 ``x`` 命令配合使用的命令是 ``set``,它允许你将值写入内存。
为了演示 ``x````set`` 的使用,我们将在内存地址 ``0x3FF44004`` 处读取和写入内容。该地址也是 ``GPIO_OUT_REG`` 寄存器的地址,可以用来控制(设置或者清除)某个 GPIO 的电平。关于该寄存器的更多详细信息,请参阅 `ESP32 技术参考手册 <https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_cn.pdf>`_ 中的 IO_MUX 和 GPIO Matrix章节。
同样在 ``blink.c`` 项目文件中,在两个 ``gpio_set_level`` 语句的后面各设置一个断点。输入两次 ``c`` 命令后停止在断点处,然后输入 ``x /1wx 0x3FF44004`` 来显示 ``GPIO_OUT_REG`` 寄存器的值::
(gdb) c
Continuing.
Target halted. PRO_CPU: PC=0x400DB75E (active) APP_CPU: PC=0x400D1128
Target halted. PRO_CPU: PC=0x400DB74E (active) APP_CPU: PC=0x400D1128
Breakpoint 2, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:34
34 vTaskDelay(1000 / portTICK_PERIOD_MS);
(gdb) x /1wx 0x3FF44004
0x3ff44004: 0x00000000
(gdb) c
Continuing.
Target halted. PRO_CPU: PC=0x400DB751 (active) APP_CPU: PC=0x400D1128
Target halted. PRO_CPU: PC=0x400DB75B (active) APP_CPU: PC=0x400D1128
Breakpoint 3, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:37
37 vTaskDelay(1000 / portTICK_PERIOD_MS);
(gdb) x /1wx 0x3FF44004
0x3ff44004: 0x00000010
(gdb)
如果闪烁的 LED 连接到了 GPIO4那么每次 LED 改变状态时你会看到第 4 比特被翻转::
0x3ff44004: 0x00000000
...
0x3ff44004: 0x00000010
现在,当 LED 熄灭时,与之对应地会显示 ``0x3ff44004: 0x00000000``,尝试使用 ``set`` 命令向相同的内存地址写入 ``0x00000010`` 来将该比特置高::
(gdb) x /1wx 0x3FF44004
0x3ff44004: 0x00000000
(gdb) set {unsigned int}0x3FF44004=0x000010
在输入 ``set {unsigned int}0x3FF44004=0x000010`` 命令后,你会立即看到 LED 亮起。
.. _jtag-debugging-examples-command-line-06:
观察和设置程序变量
^^^^^^^^^^^^^^^^^^
常见的调试任务是在程序运行期间检查程序中某个变量的值,为了能够演示这个功能,更新 ``blink.c`` 文件,在 ``blink_task`` 函数的上面添加一个全局变量的声明 ``int i``,然后在 ``while(1)`` 里添加 ``i++``,这样每次 LED 改变状态的时候,变量 ``i`` 都会增加 1。
退出调试器,这样就不会与新代码混淆,然后重新构建并烧写代码到 ESP32 中,接着重启调试器。注意,这里不需要我们重启 OpenOCD。
一旦程序停止运行,输入命令 ``watch i``::
(gdb) watch i
Hardware watchpoint 2: i
(gdb)
这会在所有变量 ``i`` 发生改变的代码处插入所谓的“观察点”。现在输入 ``continue`` 命令来恢复应用程序的运行并观察它停止::
(gdb) c
Continuing.
Target halted. PRO_CPU: PC=0x400DB751 (active) APP_CPU: PC=0x400D0811
[New Thread 1073432196]
Program received signal SIGTRAP, Trace/breakpoint trap.
[Switching to Thread 1073432196]
0x400db751 in blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:33
33 i++;
(gdb)
多次恢复程序运行后,变量 ``i`` 的值会增加,现在你可以输入 ``print i`` (简写 ``p i``)来查看当前 ``i`` 的值::
(gdb) p i
$1 = 3
(gdb)
要修改 ``i`` 的值,请使用 ``set`` 命令,如下所示(可以将其打印输出来查看是否确已修改)::
(gdb) set var i = 0
(gdb) p i
$3 = 0
(gdb)
最多可以使用两个观察点,详细信息请参阅 :ref:`jtag-debugging-tip-breakpoints`
.. _jtag-debugging-examples-command-line-07:
设置条件断点
^^^^^^^^^^^^
接下来的内容更为有趣,你可能想在一定条件满足的情况下设置断点。请先删除已有的断点,然后尝试如下命令::
(gdb) break blink.c:34 if (i == 2)
Breakpoint 3 at 0x400db753: file /home/user-name/esp/blink/main/./blink.c, line 34.
(gdb)
以上命令在 ``blink.c`` 文件的 ``34`` 处设置了一个条件断点,当 ``i==2`` 条件满足时,程序会停止运行。
如果当前 ``i`` 的值小于 ``2`` 并且程序被恢复运行,那么 LED 就会循环闪烁,直到 ``i == 2`` 条件成立,最后程序停止在该处::
(gdb) set var i = 0
(gdb) c
Continuing.
Target halted. PRO_CPU: PC=0x400DB755 (active) APP_CPU: PC=0x400D112C
Target halted. PRO_CPU: PC=0x400DB753 (active) APP_CPU: PC=0x400D112C
Target halted. PRO_CPU: PC=0x400DB755 (active) APP_CPU: PC=0x400D112C
Target halted. PRO_CPU: PC=0x400DB753 (active) APP_CPU: PC=0x400D112C
Breakpoint 3, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:34
34 gpio_set_level(BLINK_GPIO, 0);
(gdb)
获得命令的帮助信息
^^^^^^^^^^^^^^^^^^
目前所介绍的都是些非常基础的命令,目的在于让您快速上手 JTAG 调试。如果想获得特定命令的语法和功能相关的信息,请在 ``(gdb)`` 提示符下输入 ``help`` 和命令名::
(gdb) help next
Step program, proceeding through subroutine calls.
Usage: next [N]
Unlike "step", if the current source line calls a subroutine,
this command does not enter the subroutine, but instead steps over
the call, in effect treating it as a single source line.
(gdb)
只需输入 ``help`` 命令,即可获得高级命令列表,帮助你了解更多详细信息。此外,还可以参考一些 GDB 命令速查表,比如 http://darkdust.net/files/GDB%20Cheat%20Sheet.pdf。虽然不是所有命令都适用于嵌入式环境但还是会有所裨益。
结束调试会话
^^^^^^^^^^^^
输入命令 ``q`` 可以退出调试器::
(gdb) q
A debugging session is active.
Inferior 1 [Remote target] will be detached.
Quit anyway? (y or n) y
Detaching from program: /home/user-name/esp/blink/build/blink.elf, Remote target
Ending remote debugging.
user-name@computer-name:~/esp/blink$

View File

@@ -1 +1,308 @@
.. include:: ../../../en/api-guides/jtag-debugging/index.rst
JTAG 调试
=========
:link_to_translation:`en:[English]`
本文将指导安装 ESP32 的 OpenOCD 调试环境,并介绍如何使用 GDB 来调试 ESP32 的应用程序。本文的组织结构如下:
:ref:`jtag-debugging-introduction`
介绍本指南主旨。
:ref:`jtag-debugging-how-it-works`
介绍 ESP32JTAGJoint Test Action Group接口OpenOCD 和 GDB 是如何相互连接从而实现 ESP32 的调试功能。
:ref:`jtag-debugging-selecting-jtag-adapter`
介绍有关 JTAG 硬件适配器的选择及参照标准。
:ref:`jtag-debugging-setup-openocd`
介绍如何在 :doc:`Windows <setup-openocd-windows>`:doc:`Linux <setup-openocd-linux>`:doc:`MacOS <setup-openocd-macos>` 操作系统上安装预编译好的 OpenOCD 软件包。
:ref:`jtag-debugging-configuring-esp32-target`
介绍如何设置 OpenOCD 软件并安装 JTAG 硬件适配器,这两者共同组成最终的调试目标。
:ref:`jtag-debugging-launching-debugger`
介绍如何从 :ref:`Eclipse 集成开发环境 <jtag-debugging-using-debugger-eclipse>`:ref:`命令行终端 <jtag-debugging-using-debugger-command-line>` 启动 GDB 调试会话。
:ref:`jtag-debugging-examples`
如果你对 GDB 不太熟悉,本小节会分别针对 :ref:`Eclipse 集成开发环境 <jtag-debugging-examples-eclipse>`:ref:`命令行终端 <jtag-debugging-examples-command-line>` 来讲解调试的范例。
:ref:`jtag-debugging-building-openocd`
介绍如何在 :doc:`Windows <building-openocd-windows>`:doc:`Linux <building-openocd-linux>`:doc:`MacOS <building-openocd-macos>` 操作系统上从源码构建 OpenOCD。
:ref:`jtag-debugging-tips-and-quirks`
介绍使用 OpenOCD 和 GDB 通过 JTAG 接口调试 ESP32 时的注意事项和补充内容。
.. _jtag-debugging-introduction:
引言
----
ESP32 具有两个强大的 Xtensa 内核支持多种程序架构。ESP-IDF 自带的 FreeRTOS 操作系统具有多核抢占式多线程的功能,它允许用户以更加直观的方式编写软件。
与此相对地,简便的编程方式会给程序的调试带来困难(如果没有合适的工具),比如找出由两个线程引起的错误,并且这两个线程在单独的 CPU 核上同时运行,仅凭 ``printf`` 语句会花费很长的时间来定位到该错误。在大多数情况下,调试此类问题更快的方法是使用调试器,连接到处理器的调试端口。
乐鑫已经为 ESP32 处理器和多核 FreeRTOS 架构移植好了 OpenOCD它将成为大多数 ESP32 应用程序的基础。此外,乐鑫还提供了一些 OpenOCD 本身并不支持的工具来进一步丰富调试的功能。
本文将指导如何在 LinuxWindows 和 MacOS 环境下为 ESP32 安装 OpenOCD并使用 GDB 进行软件调试。除了个别操作系统的安装过程有所差别以外,软件用户界面和使用流程都是一样的。
.. note::
本文使用的图片素材来自于 Ubuntu 16.04 LTE 上 Eclipse Neon 3 软件的截图不同的操作系统Windows MacOS 或者 Linux和 Eclipse 软件版本在用户界面上可能会有细微的差别。
.. _jtag-debugging-how-it-works:
工作原理
--------
通过 JTAGJoint Test Action Group接口使用 OpenOCD 调试 ESP32 时所需要的一些关键的软件和硬件包括 **xtensa-esp32-elf-gdb
调试器****OpenOCD 片上调试器** 和连接到 **ESP32** 目标的 **JTAG 适配器**。
.. figure:: ../../../_static/jtag-debugging-overview_zh.jpg
:align: center
:alt: JTAG debugging - overview diagram
:figclass: align-center
JTAG 调试 - 概述图
在 “Application Loading and Monitoring” 下还有另外一组软件和硬件,它们用来编译、构建和烧写应用程序到 ESP32 上,以及监视来自 ESP32 的运行诊断信息。
`Eclipse <https://www.eclipse.org/>`__ 环境集成了 JTAG 调试和应用程序加载、监视的功能,它使得软件从编写、编译、加载到调试的迭代过程变得更加快速而简单。所有的软件均适用于 WindowsLinux 和 MacOS 平台。
如果你使用的是 :doc:`ESP-WROVER-KIT 开发板 <../../hw-reference/modules-and-boards>`,得益于板载的 FT232H 芯片PC 和 ESP32 的连接仅仅需要一根 USB 线即可完成。FT232H 提供了两路 USB 通道,一路连接到 JTAG另一路连接到 UART。
根据用户的喜好,除了使用 Eclipse 集成开发环境,上述的调试工具和构建工具还可以直接在命令行终端运行。
.. _jtag-debugging-selecting-jtag-adapter:
选择 JTAG 适配器
----------------
上手 JTAG 最快速便捷的方式是使用 :doc:`ESP-WROVER-KIT 开发板 <../../hw-reference/modules-and-boards>`,因为它板载了 JTAG 调试接口,无需使用外部的 JTAG 硬件适配器和额外的线缆来连接 JTAG 与 ESP32。ESP-WROVER-KIT 采用 FT2232H 提供的 JTAG 接口,可以稳定运行在 20 MHz 的时钟频率,外接的适配器很难达到这个速度。
如果你想使用单独的 JTAG 适配器,请确保其与 ESP32 的电平电压和 OpenOCD 软件都兼容。ESP32 使用的是业界标准的 JTAG 接口它省略了实际上也并不需要TRST 信号脚。JTAG 使用的 IO 引脚由 VDD_3P3_RTC 电源引脚供电(通常连接到外部 3.3 V 的电源轨),因此 JTAG 硬件适配器的引脚需要能够在该电压范围内正常工作。
在软件方面OpenOCD 支持相当多数量的 JTAG 适配器,可以参阅 `OpenOCD 支持的适配器列表 <http://openocd.org/doc/html/Debug-Adapter-Hardware.html>`_ (尽管上面显示的器件不太完整),这个页面还列出了兼容 SWD 接口的适配器但是请注意ESP32 目前并不支持 SWD。此外那些被硬编码为只支持特定产品线的 JTAG 适配器也不能在 ESP32 上工作,比如用于 STM32 产品家族的 ST-LINK 适配器。
JTAG 正常工作至少需要连接的信号线有TDITDOTCKTMS 和 GND。某些 JTAG 适配器还需要 ESP32 提供一路电源到适配器的某个引脚上(比如 Vtar用以设置适配器的工作电压。SRST 信号线是可选的,它可以连接到 ESP32 的 CH_PD 引脚上,尽管目前 OpenOCD 对该信号线的支持还非常有限。
.. _jtag-debugging-setup-openocd:
安装 OpenOCD
------------
本节会介绍 OpenOCD 软件包的安装,如果你想从源码构建 OpenOCD请参阅 :ref:`jtag-debugging-building-openocd`。默认所有 OpenOCD 相关的文件都会被存放到 ``~/esp/openocd-esp32`` 目录下,你也可以选择任何其它的目录,但相应地,你也需要调整本文档示例中使用的相对路径。
.. toctree::
:hidden:
Windows <setup-openocd-windows>
Linux <setup-openocd-linux>
MacOS <setup-openocd-macos>
从下面选择你使用的操作系统,并按照提示进一步设置 OpenOCD。
+-------------------+-------------------+-------------------+
| |windows-logo| | |linux-logo| | |macos-logo| |
+-------------------+-------------------+-------------------+
| `Windows`_ | `Linux`_ | `Mac OS`_ |
+-------------------+-------------------+-------------------+
.. |windows-logo| image:: ../../../_static/windows-logo.png
:target: ../jtag-debugging/setup-openocd-windows.html
.. |linux-logo| image:: ../../../_static/linux-logo.png
:target: ../jtag-debugging/setup-openocd-linux.html
.. |macos-logo| image:: ../../../_static/macos-logo.png
:target: ../jtag-debugging/setup-openocd-macos.html
.. _Windows: setup-openocd-windows.html
.. _Linux: setup-openocd-linux.html
.. _Mac OS: setup-openocd-macos.html
安装完成后,请熟悉一下 ``openocd-esp32`` 安装路径下的两个关键目录:
- ``bin`` 目录下包含了 OpenOCD 的可执行文件
- ``share\openocd\scripts`` 目录下包含了一些配置文件,它们会作为命令行参数与 OpenOCD 一同被调用
.. note::
上面的目录名称和结构特定于 OpenOCD 的二进制发行版,它们会被用在本指南中的 OpenOCD 示例中。从源码构建得到的 OpenOCD 存放的目录可能会不一样,所以调用 OpenOCD 的方式也会略有不同。更多详细信息请参阅 :ref:`jtag-debugging-building-openocd`
.. _jtag-debugging-configuring-esp32-target:
配置 ESP32 目标板
-----------------
安装好 OpenOCD 之后就可以配置 ESP32 目标(即带 JTAG 接口的 ESP32 板),具体可以通过以下三个步骤进行:
- 配置并连接 JTAG 接口
- 运行 OpenOCD
- 上传待调试的应用程序
配置并连接 JTAG 接口
~~~~~~~~~~~~~~~~~~~~
此步骤取决于您使用的 JTAG 和 ESP32 板,请参考以下两种情况。
.. toctree::
:maxdepth: 1
configure-wrover
configure-other-jtag
.. _jtag-debugging-run-openocd:
运行 OpenOCD
~~~~~~~~~~~~
配置完目标并将其连接到电脑后,即可启动 OpenOCD。
.. highlight:: bash
打开终端,进入安装目录并启动 OpenOCD::
cd ~/esp/openocd-esp32
bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg
.. note::
如上所示,``-f`` 后面的文件是特定于板载 :ref:`ESP-WROOM-32 <esp-modules-and-boards-esp32-wroom-32>` 模组的 ESP-WROVER-KIT 开发板的。您可能需要根据具体使用的硬件而提供不同的配置文件,相关指导请参阅 :ref:`jtag-debugging-tip-openocd-configure-target`
.. include:: ./windows-openocd-note.rst
.. highlight:: none
现在应该可以看到类似下面的输出(此日志来自 ESP-WROVER-KIT::
user-name@computer-name:~/esp/openocd-esp32$ bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg
Open On-Chip Debugger 0.10.0-dev-ged7b1a9 (2017-07-10-07:16)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
none separate
adapter speed: 20000 kHz
force hard breakpoints
Info : ftdi: if you experience problems at higher adapter clocks, try the command "ftdi_tdo_sample_edge falling"
Info : clock speed 20000 kHz
Info : JTAG tap: esp32.cpu0 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
Info : JTAG tap: esp32.cpu1 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
Info : esp32: Debug controller was reset (pwrstat=0x5F, after clear 0x0F).
Info : esp32: Core was reset (pwrstat=0x5F, after clear 0x0F).
- 如果出现指示权限问题的错误,请参阅 ``~/esp/openocd-esp32`` 目录下 OpenOCD README 文件中关于 “Permissions delegation” 的说明。
- 如果发现配置文件有错误,例如 ``Can't find interface/ftdi/esp32_devkitj_v1.cfg``,请检查 ``-s`` 后面的路径OpenOCD 会根据此路径来查找 ``-f`` 指定的文件。此外,还需要检查配置文件是否确实位于该路径下。
- 如果看到 JTAG 错误(输出全是 1 或者全是 0请检查硬件连接除了 ESP32 的引脚之外是否还有其他信号连接到了 JTAG并查看是否所有器件都已经上电。
.. _jtag-upload-app-debug:
上传待调试的应用程序
~~~~~~~~~~~~~~~~~~~~
您可以像往常一样构建并上传 ESP32 应用程序,具体请参阅 :ref:`get-started-build-flash` 章节。
除此以外,还支持使用 OpenOCD 通过 JTAG 接口将应用程序镜像烧写到闪存中,命令如下::
cd ~/esp/openocd-esp32
bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg -c "program_esp32 filename.bin 0x10000 verify exit"
.. include:: ./windows-openocd-note.rst
其中 OpenOCD 的烧写命令 ``program_esp32`` 具有以下格式:
``program_esp32 <image_file> <offset> [verify] [reset] [exit]``
- ``image_file`` - 程序镜像文件存放的路径
- ``offset`` - 镜像烧写到闪存中的偏移地址
- ``verify`` - 烧写完成后校验闪存中的内容(可选)
- ``reset`` - 烧写完成后重启目标(可选)
- ``exit`` - 烧写完成后退出 OpenOCD可选
现在可以进行应用程序的调试了,请按照以下章节中讲解的步骤进行操作。
.. _jtag-debugging-launching-debugger:
启动调试器
----------
ESP32 的工具链中带有 GNU 调试器(简称 GDB ``xtensa-esp32-elf-gdb``,它和其它工具链软件存放在同一个 bin 目录下。除了直接在命令行终端中调用并操作 GDB 外,还可以在 IDE (例如 EclipseVisual Studio Code 等)中调用它,在图形用户界面的帮助下间接操作 GDB无需在终端中输入任何命令。
关于以上两种调试器的使用方法,详见以下链接。
* :ref:`jtag-debugging-using-debugger-eclipse`
* :ref:`jtag-debugging-using-debugger-command-line`
建议首先检查调试器是否能在 :ref:`命令行终端 <jtag-debugging-using-debugger-command-line>` 下正常工作,然后再转到使用 Eclipse 等 :ref:`集成开发环境 <jtag-debugging-using-debugger-eclipse>` 下进行调试工作。
.. _jtag-debugging-examples:
调试范例
--------
本节适用于不熟悉 GDB 的用户,将使用 :example:`get-started/blink` 下简单的应用程序来演示 :ref:`调试会话的工作流程 <jtag-debugging-examples-eclipse>`,同时会介绍以下常用的调试操作:
1. :ref:`jtag-debugging-examples-eclipse-01`
2. :ref:`jtag-debugging-examples-eclipse-02`
3. :ref:`jtag-debugging-examples-eclipse-03`
4. :ref:`jtag-debugging-examples-eclipse-04`
5. :ref:`jtag-debugging-examples-eclipse-05`
6. :ref:`jtag-debugging-examples-eclipse-06`
7. :ref:`jtag-debugging-examples-eclipse-07`
此外还会提供 :ref:`在命令行终端进行调试 <jtag-debugging-examples-command-line>` 的案例。
在演示之前,请设置好 ESP32 目标板并加载 :example:`get-started/blink` 至 ESP32 中。
.. _jtag-debugging-building-openocd:
从源码构建 OpenOCD
------------------
请参阅以下文档,它们分别介绍了在各大操作系统平台上从源码构建 OpenOCD 的流程。
.. toctree::
:maxdepth: 1
Windows <building-openocd-windows>
Linux <building-openocd-linux>
MacOS <building-openocd-macos>
.. note::
本文档演示所使用的 OpenOCD 是 :ref:`jtag-debugging-setup-openocd` 章节中介绍的预编译好的二进制发行版,如果要使用本地从源代码构建得到的 OpenOCD 程序,需要将相应可执行文件的路径修改为 ``src/openocd``,并将配置文件的路径修改为 ``-s tcl``
具体使用示例如下::
src/openocd -s tcl -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg
.. _jtag-debugging-tips-and-quirks:
注意事项和补充内容
--------------------
本节列出了本指南中提到的所有注意事项和补充内容的链接。
* :ref:`jtag-debugging-tip-breakpoints`
* :ref:`jtag-debugging-tip-where-breakpoints`
* :ref:`jtag-debugging-tip-flash-mappings`
* :ref:`jtag-debugging-tip-why-next-works-as-step`
* :ref:`jtag-debugging-tip-code-options`
* :ref:`jtag-debugging-tip-freertos-support`
* :ref:`jtag-debugging-tip-code-flash-voltage`
* :ref:`jtag-debugging-tip-optimize-jtag-speed`
* :ref:`jtag-debugging-tip-debugger-startup-commands`
* :ref:`jtag-debugging-tip-openocd-configure-target`
* :ref:`jtag-debugging-tip-reset-by-debugger`
* :ref:`jtag-debugging-tip-jtag-pins-reconfigured`
* :ref:`jtag-debugging-tip-reporting-issues`
相关文档
--------
.. toctree::
:maxdepth: 1
using-debugger
debugging-examples
tips-and-quirks
../app_trace

View File

@@ -1 +1,34 @@
.. include:: ../../../en/api-guides/jtag-debugging/setup-openocd-linux.rst
***************************
在 Linux 环境下安装 OpenOCD
***************************
:link_to_translation:`en:[English]`
安装 OpenOCD
============
64 位 Linux 系统版本的 OpenOCD 可以直接从以下 Github 链接中下载:
https://github.com/espressif/openocd-esp32/releases
下载文件名称包含 `linux64` 字样的最新发布的归档文件,例如 `openocd-esp32-linux64-0.10.0-esp32-20180418.tar.gz`
将该文件解压缩到 ``~/esp/`` 目录下::
cd ~/esp
tar -xzf ~/Downloads/openocd-esp32-linux64-<version>.tar.gz
下一步
======
进一下配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。
相关文档
========
.. toctree::
:maxdepth: 1
building-openocd-linux

View File

@@ -1 +1,39 @@
.. include:: ../../../en/api-guides/jtag-debugging/setup-openocd-macos.rst
***************************
在 MacOS 环境下安装 OpenOCD
***************************
:link_to_translation:`en:[English]`
安装 libusb
===========
使用 `Homebrew <https://brew.sh/>`_ 或者 `Macports <https://www.macports.org/>`_ 来安装 `libusb` 软件包。
安装 OpenOCD
============
MacOS 系统版本的 OpenOCD 可以直接从以下 Github 链接中下载:
https://github.com/espressif/openocd-esp32/releases
下载文件名包含 `macos` 字样的最新发布的归档文件,例如 `openocd-esp32-macos-0.10.0-esp32-20180418.tar.gz`
将该文件解压缩到 ``~/esp/`` 目录下::
cd ~/esp
tar -xzf ~/Downloads/openocd-esp32-macos-<version>.tar.gz
下一步
======
进一下配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。
相关文档
========
.. toctree::
:maxdepth: 1
building-openocd-macos

View File

@@ -1 +1,39 @@
.. include:: ../../../en/api-guides/jtag-debugging/setup-openocd-windows.rst
*****************************
在 Windows 环境下安装 OpenOCD
*****************************
:link_to_translation:`en:[English]`
IDF 工具安装程序
================
如果您正在使用 CMake 构建系统,并遵循 :doc:`/get-started-cmake/windows-setup` 章节的指导使用了 ``ESP-IDF Tools Installer`` 的 V1.2 及其以上版本,那么默认情况下您已经安装好了 ``OpenOCD`` 软件。
``ESP-IDF Tools Installer`` 会将 ``OpenOCD`` 添加到环境变量 ``PATH`` 中,这样你就可以在任何目录运行它。
安装 OpenOCD
============
Windows 系统版本的 OpenOCD 可以直接从以下 Github 链接中下载:
https://github.com/espressif/openocd-esp32/releases
下载文件名包含 `win32` 字样的最新发布的归档文件,例如 `openocd-esp32-macos-0.10.0-win32-20180418.zip`
将该文件解压缩到 ``~/esp/`` 目录下::
cd ~/esp
unzip /c/Users/<user>/Downloads/openocd-esp32-win32-<version>.zip
下一步
======
进一下配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。
相关文档
========
.. toctree::
:maxdepth: 1
building-openocd-windows

View File

@@ -1 +1,282 @@
.. include:: ../../../en/api-guides/jtag-debugging/tips-and-quirks.rst
注意事项和补充内容
------------------
:link_to_translation:`en:[English]`
本节提供了本指南中各部分提到的一些注意事项和补充内容。
.. _jtag-debugging-tip-breakpoints:
可用的断点和观察点
^^^^^^^^^^^^^^^^^^
ESP32 调试器支持 2 个硬件断点和 64 个软件断点。硬件断点是由 ESP32 芯片内部的逻辑电路实现的,能够设置在代码的任何位置:闪存或者 IRAM 的代码区域。除此以外OpenOCD 实现了两种软件断点:闪存断点(最多 32 个)和 IRAM 断点(最多 32 个)。目前 GDB 无法在闪存中设置软件断点,因此除非解决此限制,否则这些断点只能由 OpenOCD 模拟为硬件断点。(详细信息可以参阅 :ref:`下面 <jtag-debugging-tip-where-breakpoints>`。ESP32 还支持 2 个观察点,所以可以观察两个变量的变化或者通过 GDB 命令 ``watch myVariable`` 来读取变量的值。请注意 menuconfig 中的 :ref:`CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK` 选项会使用第二个观察点,如果你想在 OpenOCD 或者 GDB 中再次尝试使用这个观察点,可能不会得到预期的结果。详情请查看 menuconfig 中的帮助文档。
.. _jtag-debugging-tip-where-breakpoints:
关于断点的补充知识
^^^^^^^^^^^^^^^^^^
使用软件闪存模拟部分硬件断点的意思就是当使用 GDB 命令 ``hb myFunction`` 给某个函数设置硬件断点时,如果该函数位于闪存中,并且此时还有可用的硬件断点,那调试器就会使用硬件断点,否则就使用 32 个软件闪存断点中的一个来模拟。这个规则同样适用于 ``b myFunction`` 之类的命令在这种情况下GDB 会自己决定该使用哪种类型的断点。如果 ``myFunction`` 位于可写区域IRAM那就会使用软件 IRAM 断点,否则就会像处理 ``hb`` 命令一样使用硬件断点或者软件闪存断点。
.. _jtag-debugging-tip-flash-mappings:
闪存映射 vs 软件闪存断点
^^^^^^^^^^^^^^^^^^^^^^^^
为了在闪存中设置或者清除软件断点OpenOCD 需要知道它们在闪存中的地址。为了完成从 ESP32 的地址空间到闪存地址的转换OpenOCD 使用闪存中程序代码区域的映射。这些映射被保存在程序映像的头部位于二进制数据代码段和数据段之前并且特定于写入闪存的每一个应用程序的映像。因此为了支持软件闪存断点OpenOCD 需要知道待调试的应用程序映像在闪存中的位置。默认情况下OpenOCD 会在 0x8000 处读取分区表并使用第一个找到的应用程序映像的映射,但是也可能会存在无法工作的情况,比如分区表不在标准的闪存位置,甚至可能有多个映像:一个出厂映像和两个 OTA 映像你可能想要调试其中的任意一个。为了涵盖所有可能的调试情况OpenOCD 支持特殊的命令,用于指定待调试的应用程序映像在闪存中的具体位置。该命令具有以下格式:
``esp32 appimage_offset <offset>``
偏移量应为十六进制格式,如果要恢复默认行为,可以将偏移地址设置为 ``-1``
.. note::
由于 GDB 在连接 OpenOCD 时仅仅请求一次内存映射,所以可以在 TCL 配置文件中指定该命令,或者通过命令行传递给 OpenOCD。对于后者命令行示例如下
``bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg -c "init; halt; esp32 appimage_offset 0x210000"``
另外还可以通过 OpenOCD 的 telnet 会话执行该命令,然后再连接 GDB 不过这种方式似乎没有那么便捷。
.. _jtag-debugging-tip-why-next-works-as-step:
“next” 命令无法跳过子程序的原因
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
当使用 ``next`` 命令单步执行代码时, GDB 会在子程序的前面设置一个断点(两个中可用的一个),这样就可以跳过进入子程序内部的细节。如果这两个断点已经用在代码的其它位置,那么 ``next`` 命令将不起作用。在这种情况下,请删掉一个断点以使其中一个变得可用。当两个断点都已经被使用时,``next`` 命令会像 ``step`` 命令一样工作,调试器就会进入子程序内部。
.. _jtag-debugging-tip-code-options:
OpenOCD 支持的编译时的选项
^^^^^^^^^^^^^^^^^^^^^^^^^^
ESP-IDF 有一些针对 OpenOCD 调试功能的选项可以在编译时进行设置:
* :ref:`CONFIG_ESP32_DEBUG_OCDAWARE` 默认会被使能。如果程序抛出了不可修复或者未处理的异常,并且此时已经连接上了 JTAG 调试器(即 OpenOCD 正在运行),那么 ESP-IDF 将会进入调试器工作模式。
* :ref:`CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK` 默认没有使能。在所有任务堆栈的末尾设置观察点,从 1 号开始索引。这是调试任务堆栈溢出的最准确的方式。
更多有关设置编译时的选项的信息,请参阅 :ref:`make menuconfig <get-started-configure>`
.. _jtag-debugging-tip-freertos-support:
支持FreeRTOS
^^^^^^^^^^^^
OpenOCD 完全支持 ESP-IDF 自带的 FreeRTOS 操作系统GDB 会将 FreeRTOS 中的任务当做线程。使用 GDB 命令 ``i threads`` 可以查看所有的线程,使用命令 ``thread n`` 可以切换到某个具体任务的堆栈,其中 ``n`` 是线程的编号。检测 FreeRTOS 的功能可以在配置目标时被禁用。更多详细信息,请参阅 :ref:`jtag-debugging-tip-openocd-configure-target`.
.. _jtag-debugging-tip-code-flash-voltage:
在 OpenOCD 的配置文件中设置 SPI 闪存的工作电压
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ESP32 的 MTDI 引脚是用于 JTAG 通信的四个引脚之一,同时也是 ESP32 的 bootstrapping 引脚。上电时ESP32 会在 MTDI 引脚上采样二进制电平,据此来设置内部的稳压器,用于给外部的 SPI 闪存芯片供电。如果上电时 MTDI 引脚上的二进制电平为低电平,则稳压器会被设置为 3.3 V如果 MTDI 引脚为高电平,则稳压器会被设置为 1.8 V。MTDI 引脚通常需要一个上拉电阻或者直接使能内部的弱下拉电阻(详见 `ESP32 系列芯片技术规格书 <https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_cn.pdf>`_ ),具体取决于所使用的 SPI 芯片的类型。但是一旦连接上 JTAG 后,原来用于实现 bootstrapping 功能的上拉或者下拉电阻都会被覆盖掉。
为了解决这个问题OpenOCD 的板级配置文件(例如 ESP32-WROOM-32 模组的 ``boards\esp-wroom-32.cfg``)提供了 ``ESP32_FLASH_VOLTAGE`` 参数来设置 ``TDO`` 信号线在空闲状态下的二进制电平,这样就可以减少由于闪存电压不正确而导致的应用程序启动不良的几率。
查看 JTAG 连接的 ESP32 模组的规格书,检查其 SPI 闪存芯片的供电电压值,然后再相应的设置 ``ESP32_FLASH_VOLTAGE``。大多数的 WROOM 模组使用 3.3 V 的闪存芯片,但是 WROVER 模组使用 1.8 V 的闪存芯片。
.. _jtag-debugging-tip-optimize-jtag-speed:
优化 JTAG 的速度
^^^^^^^^^^^^^^^^
为了实现更高的数据通信速率同时最小化丢包数,建议优化 JTAG 时钟频率的设置,使其达到 JTAG 能稳定运行的最大值。为此,请参考以下建议。
1. 如果 CPU 以 80 MHz 运行,则 JTAG 时钟频率的上限为 20 MHz如果 CPU 以 160 MHz 或者 240 MHz 运行,则上限为 26 MHz。
2. 根据特定的 JTAG 适配器和连接线缆的长度,你可能需要将 JTAG 的工作频率降低至 20 / 26 MHz 以下。
3. 在某些特殊情况下,如果你看到 DSR/DIR 错误(并且它并不是由 OpenOCD 试图从一个没有物理存储器映射的地址空间读取数据而导致的),请降低 JTAG 的工作频率。
4. ESP-WROVER-KIT 能够稳定运行在 20 / 26 MHz 频率下。
.. _jtag-debugging-tip-debugger-startup-commands:
调试器的启动命令的含义
^^^^^^^^^^^^^^^^^^^^^^
在启动时,调试器发出一系列命令来复位芯片并使其在特定的代码行停止运行。这个命令序列(如下所示)支持自定义,用户可以选择在最方便合适的代码行开始调试工作。
* ``set remote hardware-watchpoint-limit 2`` — 限制 GDB 仅使用 ESP32 支持的两个硬件观察点。更多详细信息,请查阅 `GDB 配置远程目标 <https://sourceware.org/gdb/onlinedocs/gdb/Remote-Configuration.html>`_
* ``mon reset halt`` — 复位芯片并使 CPU 停止运行。
* ``flushregs`` — monitor (``mon``) 命令无法通知 GDB 目标状态已经更改GDB 会假设在 ``mon reset halt`` 之前所有的任务堆栈仍然有效。实际上,复位后目标状态将发生变化。执行 ``flushregs`` 是一种强制 GDB 从目标获取最新状态的方法。
* ``thb app_main`` — 在 ``app_main`` 处插入一个临时的硬件断点,如果有需要,可以将其替换为其他函数名。
* ``c`` — 恢复程序运行,它将会在 ``app_main`` 的断点处停止运行。
.. _jtag-debugging-tip-openocd-configure-target:
针对特定目标的 OpenOCD 配置
^^^^^^^^^^^^^^^^^^^^^^^^^^^
OpenOCD 需要知道当前使用的 JTAG 适配器的类型,以及其连接的目标板和处理器的类型。为此,请使用位于 OpenOCD 安装目录下 ``share/openocd/scripts/interface````share/openocd/scripts/board`` 文件夹中现有的配置文件。
例如,如果使用板载 ESP-WROOM-32 模组的 ESP-WROVER-KIT 开发板(详见 :ref:`esp-modules-and-boards-esp-wrover-kit-v1`),请使用以下配置文件:
* ``interface/ftdi/esp32_devkitj_v1.cfg``
* ``board/esp-wroom-32.cfg``
当然也可以使用自定义的配置文件,建议在已有配置文件的基础上进行修改,以匹配你的硬件。下面列举一些常用的板级配置参数。
.. highlight:: none
适配器的时钟速度
""""""""""""""""
::
adapter_khz 20000
请参阅 :ref:`jtag-debugging-tip-optimize-jtag-speed` 以获取有关如何设置此值的指导。
单核调试
""""""""
::
set ESP32_ONLYCPU 1
如果是双核调试,请注释掉这一行。
禁用 RTOS 支持
""""""""""""""
::
set ESP32_RTOS none
如果要支持 RTOS 请注释掉这一行。
ESP32 的 SPI 闪存芯片的电源电压
"""""""""""""""""""""""""""""""
::
set ESP32_FLASH_VOLTAGE 1.8
如果 SPI 闪存芯片的电源电压为 3.3 V 请注释掉这一行,更多信息请参阅: :ref:`jtag-debugging-tip-code-flash-voltage`
ESP32 的目标配置文件
""""""""""""""""""""
::
source [find target/esp32.cfg]
.. note::
除非你熟悉 OpenOCD 内部的工作原理,否则请不要更改 ``source [find target/esp32.cfg]`` 这一行。
目前 ``target/esp32.cfg`` 仍然是 ESP32 目标esp108 和 esp32的唯一配置文件。支持的配置矩阵如下所示
+---------------+---------------+---------------+
| Dual/single | RTOS | Target used |
+===============+===============+===============+
| dual | FreeRTOS | esp32 |
+---------------+---------------+---------------+
| single | FreeRTOS | esp108 (*) |
+---------------+---------------+---------------+
| dual | none | esp108 |
+---------------+---------------+---------------+
| single | none | esp108 |
+---------------+---------------+---------------+
(*) — 我们计划修复此问题,并在后续提交中添加对 esp32 目标的单核调试的支持。
更多信息,请查看 ``board/esp-wroom-32.cfg`` 配置文件的注释部分。
.. _jtag-debugging-tip-reset-by-debugger:
复位 ESP32
^^^^^^^^^^
通过在 GDB 中输入 ``mon reset`` 或者 ``mon reset halt`` 来复位板子。
.. _jtag-debugging-tip-jtag-pins-reconfigured:
不要将 JTAG 引脚用于其他功能
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
如果除了 ESP32 模组和 JTAG 适配器之外的其他硬件也连接到了 JTAG 引脚,那么 JTAG 的操作可能会受到干扰。ESP32 JTAG 使用以下引脚:
+---+----------------+-------------+
| | ESP32 JTAG Pin | JTAG Signal |
+===+================+=============+
| 1 | MTDO / GPIO15 | TDO |
+---+----------------+-------------+
| 2 | MTDI / GPIO12 | TDI |
+---+----------------+-------------+
| 3 | MTCK / GPIO13 | TCK |
+---+----------------+-------------+
| 4 | MTMS / GPIO14 | TMS |
+---+----------------+-------------+
如果用户应用程序更改了 JTAG 引脚的配置JTAG 通信可能会失败。如果 OpenOCD 正确初始化(检测到两个 Tensilica 内核),但在程序运行期间失去了同步并报出大量 DTR/DIR 错误,则应用程序可能将 JTAG 引脚重新配置为其他功能或者用户忘记将 Vtar 连接到 JTAG 适配器。
.. highlight:: none
下面是 GDB 在应用程序进入重新配置 MTDO/GPIO15 作为输入代码后报告的一系列错误摘录::
cpu0: xtensa_resume (line 431): DSR (FFFFFFFF) indicates target still busy!
cpu0: xtensa_resume (line 431): DSR (FFFFFFFF) indicates DIR instruction generated an exception!
cpu0: xtensa_resume (line 431): DSR (FFFFFFFF) indicates DIR instruction generated an overrun!
cpu1: xtensa_resume (line 431): DSR (FFFFFFFF) indicates target still busy!
cpu1: xtensa_resume (line 431): DSR (FFFFFFFF) indicates DIR instruction generated an exception!
cpu1: xtensa_resume (line 431): DSR (FFFFFFFF) indicates DIR instruction generated an overrun!
.. _jtag-debugging-tip-reporting-issues:
报告 OpenOCD / GDB 的问题
^^^^^^^^^^^^^^^^^^^^^^^^^
如果你遇到 OpenOCD 或者 GDB 程序本身的问题,并且在网上没有找到可用的解决方案,请前往 https://github.com/espressif/openocd-esp32/issues 新建一个议题。
1. 请在问题报告中提供你使用的配置的详细信息:
a. JTAG 适配器类型。
b. 用于编译和加载正在调试的应用程序的 ESP-IDF 版本号。
c. 用于调试的操作系统的详细信息。
d. 操作系统是在本地计算机运行还是在虚拟机上运行?
2. 创建一个能够演示问题的简单示例工程,描述复现该问题的步骤。且这个调试示例不能受到 Wi-Fi 协议栈引入的非确定性行为的影响,因而再次遇到同样问题时,更容易复现。
.. highlight:: bash
3. 在启动命令中添加额外的参数来输出调试日志。
OpenOCD 端:
::
bin/openocd -l openocd_log.txt -d 3 -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg
这种方式会将日志输出到文件,但是它会阻止调试信息打印在终端上。当有大量信息需要输出的时候(比如调试等级提高到 ``-d 3``)这是个不错的选择。如果你仍然希望在屏幕上看到调试日志,请改用以下命令:
::
bin/openocd -d 3 -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg 2>&1 | tee openocd.log
.. note::
如果运行的 OpenOCD 是从源码自行编译的,命令的格式会有些许不同,具体请参阅: :ref:`jtag-debugging-building-openocd`
Debugger 端:
::
xtensa-esp32-elf-gdb -ex "set remotelogfile gdb_log.txt" <all other options>
也可以将命令 ``remotelogfile gdb_log.txt`` 添加到 ``gdbinit`` 文件中。
4. 请将 ``openocd_log.txt````gdb_log.txt`` 文件附在你的问题报告中。

View File

@@ -1 +1,190 @@
.. include:: ../../../en/api-guides/jtag-debugging/using-debugger.rst
使用调试器
----------
:link_to_translation:`en:[English]`
本节会在 :ref:`Eclipse <jtag-debugging-using-debugger-eclipse>`:ref:`命令行 <jtag-debugging-using-debugger-command-line>` 中分别介绍配置和运行调试器的方法。我们建议你首先通过 :ref:`命令行 <jtag-debugging-using-debugger-command-line>` 检查调试器是否正常工作,然后再转到使用 :ref:`Eclipse <jtag-debugging-using-debugger-eclipse>` 平台。
.. _jtag-debugging-using-debugger-eclipse:
在 Eclipse 中使用 GDB
^^^^^^^^^^^^^^^^^^^^^
标准的 Eclipse 安装流程默认安装调试功能,另外我们还可以使用插件来调试,比如 “GDB Hardware Debugging”。这个插件用起来非常方便本指南会详细介绍该插件的使用方法。
首先,通过打开 Eclipse 并转到 “Help” > “Install New Software” 来安装 “GDB Hardware Debugging” 插件。
安装完成后,按照以下步骤配置调试会话。请注意,一些配置参数是通用的,有些则针对特定项目。我们会通过配置 "blink" 示例项目的调试环境来进行展示,请先按照 :doc:`使用 Eclipse IDE 编译和烧写 <../../get-started/eclipse-setup>` 文章介绍的方法将该示例项目添加到 Eclipse 的工作空间。示例项目 :example:`get-started/blink` 的源代码可以在 ESP-IDF 仓库的 :idf:`examples` 目录下找到。
1. 在 Eclipse 中,进入 `Run` > `Debug Configuration`,会出现一个新的窗口。在窗口的左侧窗格中,双击 “GDB Hardware Debugging” (或者选择 “GDB Hardware Debugging” 然后按下 “New” 按钮)来新建一个配置。
2. 在右边显示的表单中“Name:” 一栏中输入配置的名称,例如: “Blink checking”。
3. 在下面的 “Main” 选项卡中, 点击 “Project:” 边上的 “Browse” 按钮,然后选择当前的 “blink” 项目。
4. 在下一行的 “C/C++ Application:” 中,点击 “Browse” 按钮,选择 “blink.elf” 文件。如果 “blink.elf” 文件不存在,那么很有可能该项目还没有编译,请参考 :doc:`使用 Eclipse IDE 编辑和烧写 <../../get-started/eclipse-setup>` 指南中的介绍。
5. 最后,在 “Build (if required) before launching” 下面点击 “Disable auto build”。
上述步骤 1 - 5 的示例输入如下图所示。
.. figure:: ../../../_static/hw-debugging-main-tab.jpg
:align: center
:alt: Configuration of GDB Hardware Debugging - Main tab
:figclass: align-center
GDB 硬件调试的配置 - Main 选项卡
6. 点击 “Debugger” 选项卡,在 “GDB Command” 栏中输入 ``xtensa-esp32-elf-gdb`` 来调用调试器。
7. 更改 “Remote host” 的默认配置,在 “Port number” 下面输入 ``3333``
上述步骤 6 - 7 的示例输入如下图所示。
.. figure:: ../../../_static/hw-debugging-debugger-tab.jpg
:align: center
:alt: Configuration of GDB Hardware Debugging - Debugger tab
:figclass: align-center
GDB 硬件调试的配置 - Debugger 选项卡
8. 最后一个需要更改默认配置的选项卡是 “Startup” 选项卡。在 “Initialization Commands” 下,取消选中 “Reset and Delay (seconds)” 和 “Halt”然后在下面一栏中输入以下命令
::
mon reset halt
flushregs
set remote hardware-watchpoint-limit 2
.. note::
如果你想在启动新的调试会话之前自动更新闪存中的镜像,请在 “Initialization Commands” 文本框的开头添加以下命令行::
mon reset halt
mon program_esp32 ${workspace_loc:blink/build/blink.bin} 0x10000 verify
有关 ``program_esp32`` 命令的说明请参考 :ref:`jtag-upload-app-debug` 章节。
9. 在 “Load Image and Symbols” 下,取消选中 “Load image” 选项。
10. 在同一个选项卡中继续往下浏览,建立一个初始断点用来在调试器复位后暂停 CPU。插件会根据 “Set break point at:” 一栏中输入的函数名,在该函数的开头设置断点。选中这一选项,并在相应的字段中输入 ``app_main``
11. 选中 “Resume” 选项,这会使得程序在每次调用步骤 8 中的 ``mon reset halt`` 之后恢复,然后在 ``app_main`` 的断点处停止。
上述步骤 8 - 11 的示例输入如下图所示。
.. figure:: ../../../_static/hw-debugging-startup-tab.jpg
:align: center
:alt: Configuration of GDB Hardware Debugging - Startup tab
:figclass: align-center
GDB 硬件调试的配置 - Startup 选项卡
上面的启动序列看起来有些复杂,如果你对其中的初始化命令不太熟悉,请查阅 :ref:`jtag-debugging-tip-debugger-startup-commands` 章节获取更多说明。
12. 如果你前面已经完成 :ref:`jtag-debugging-configuring-esp32-target` 中介绍的步骤,那么目标正在运行并准备与调试器进行对话。按下 “Debug” 按钮就可以直接调试。否则请按下 “Apply” 按钮保存配置,返回 :ref:`jtag-debugging-configuring-esp32-target` 章节进行配置,最后再回到这里开始调试。
一旦所有 1 - 12 的配置步骤都已经完成Eclipse 就会打开 “Debug” 视图,如下图所示。
.. figure:: ../../../_static/debug-perspective.jpg
:align: center
:alt: Debug Perspective in Eclipse
:figclass: align-center
Eclipse 中的调试视图
如果你不太了解 GDB 的常用方法,请查阅 :ref:`jtag-debugging-examples-eclipse` 文章中的调试示例章节 :ref:`jtag-debugging-examples`
.. _jtag-debugging-using-debugger-command-line:
在命令行中使用 GDB
^^^^^^^^^^^^^^^^^^
1. 为了能够启动调试会话,需要先启动并运行目标,如果还没有完成,请按照 :ref:`jtag-debugging-configuring-esp32-target` 中的介绍进行操作。
.. highlight:: bash
2. 打开一个新的终端会话并前往待调试的项目目录,比如:
::
cd ~/esp/blink
.. highlight:: none
3. 当启动调试器时,通常需要提供几个配置参数和命令,为了避免每次都在命令行中逐行输入这些命令,我们可以新建一个配置文件,并将其命名为 ``gdbinit``:
::
target remote :3333
set remote hardware-watchpoint-limit 2
mon reset halt
flushregs
thb app_main
c
将此文件保存在当前目录中。
有关 ``gdbinit`` 文件内部的更多详细信息,请参阅 :ref:`jtag-debugging-tip-debugger-startup-commands` 章节。
.. highlight:: bash
4. 准备好启动 GDB请在终端中输入以下内容
::
xtensa-esp32-elf-gdb -x gdbinit build/blink.elf
.. highlight:: none
5. 如果前面的步骤已经正确完成,你会看到如下所示的输出日志,在日志的最后会出现 ``(gdb)`` 提示符:
::
user-name@computer-name:~/esp/blink$ xtensa-esp32-elf-gdb -x gdbinit build/blink.elf
GNU gdb (crosstool-NG crosstool-ng-1.22.0-61-gab8375a) 7.10
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-build_pc-linux-gnu --target=xtensa-esp32-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from build/blink.elf...done.
0x400d10d8 in esp_vApplicationIdleHook () at /home/user-name/esp/esp-idf/components/esp32/./freertos_hooks.c:52
52 asm("waiti 0");
JTAG tap: esp32.cpu0 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
JTAG tap: esp32.slave tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
esp32: Debug controller was reset (pwrstat=0x5F, after clear 0x0F).
esp32: Core was reset (pwrstat=0x5F, after clear 0x0F).
Target halted. PRO_CPU: PC=0x5000004B (active) APP_CPU: PC=0x00000000
esp32: target state: halted
esp32: Core was reset (pwrstat=0x1F, after clear 0x0F).
Target halted. PRO_CPU: PC=0x40000400 (active) APP_CPU: PC=0x40000400
esp32: target state: halted
Hardware assisted breakpoint 1 at 0x400db717: file /home/user-name/esp/blink/main/./blink.c, line 43.
0x0: 0x00000000
Target halted. PRO_CPU: PC=0x400DB717 (active) APP_CPU: PC=0x400D10D8
[New Thread 1073428656]
[New Thread 1073413708]
[New Thread 1073431316]
[New Thread 1073410672]
[New Thread 1073408876]
[New Thread 1073432196]
[New Thread 1073411552]
[Switching to Thread 1073411996]
Temporary breakpoint 1, app_main () at /home/user-name/esp/blink/main/./blink.c:43
43 xTaskCreate(&blink_task, "blink_task", 512, NULL, 5, NULL);
(gdb)
注意上面日志的倒数第三行显示了调试器已经在 ``app_main()`` 函数的断点处停止,该断点在 ``gdbinit`` 文件中设定。由于处理器已经暂停运行LED 也不会闪烁。如果这也是你看到的现象,你可以开始调试了。
如果你不太了解 GDB 的常用方法,请查阅 :ref:`jtag-debugging-examples-command-line` 文章中的调试示例章节 :ref:`jtag-debugging-examples`

View File

@@ -1 +1,3 @@
.. include:: ../../../en/api-guides/jtag-debugging/windows-openocd-note.rst
.. note::
如果您在 Windows 上使用 ``ESP-IDF Tools Installer`` 安装的 OpenOCD则无需切换目录即可运行 ``openocd -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg`` ,也无需使用 ``-s share/openocd/scripts`` 参数指定脚本文件的搜索路径。

View File

@@ -1 +1,498 @@
.. include:: ../../en/api-guides/linker-script-generation.rst
链接脚本生成机制
================
:link_to_translation:`en:[English]`
概述
----
ESP32 的代码和数据可以存放在多个 :ref:`内存区域 <memory-layout>`。通常,代码和只读数据存放在 flash 区域,可写数据存放在内存中。我们经常需要更改代码或者数据的默认映射区域,例如为了提高性能,将关键部分的代码和只读数据放置到内存中,或者将代码、数据和只读数据存放到 RTC 内存中以便在 :doc:`唤醒桩 <deep-sleep-stub>`:doc:`ULP 协处理器 <ulp>` 中使用。
IDF 的链接脚本生成机制允许用户在组件级别定义代码和数据的存放区域。组件通过 :ref:`链接片段文件 <ldgen-fragment-files>` 描述如何映射目标文件的输入段(甚至可以是某个具体的函数或者数据)。在构建应用程序时,链接片段文件会被收集、解析并处理,然后扩充到 :ref:`链接脚本模板 <ldgen-script-templates>` 中形成最终的链接脚本文件,该链接脚本会被用于链接最终的二进制应用程序。
快速上手
--------
本节将指导如何快速将代码和数据放入 RAM 和 RTC 内存中,并演示如何使这些放置规则依赖于项目的配置。本节内容重在指导快速入门,因此并未在使用前详细介绍所有涉及的术语和概念,但在首次提及此类术语或概念时,均提供了相应链接,以帮助您的理解。
.. _ldgen-add-fragment-file :
准备工作
^^^^^^^^
Make
""""
在组件目录中新建一个链接片段文件,该文件是一个扩展名为 ``.lf`` 的文本文件。为了能够让构建系统收集到此片段文件,需要为组件添加一个条目,在调用 ``register_component`` 之前设置 ``COMPONENT_ADD_LDFRAGMENTS`` 变量的值,使其指向刚才的链接片段文件。
.. code-block:: make
# 文件路径相对于组件的 Makefile
COMPONENT_ADD_LDFRAGMENTS += "path/to/linker_fragment_file.lf" "path/to/another_linker_fragment_file.lf"
CMake
"""""
对于 CMake 构建系统来说,需要在调用 ``register_component`` 之前设置 ``COMPONENT_ADD_LDFRAGMENTS`` 变量的值,使其指向链接片段文件。
.. code-block:: cmake
# 文件路径相对于组件的 CMakeLists.txt
set(COMPONENT_ADD_LDFRAGMENTS "path/to/linker_fragment_file.lf" "path/to/another_linker_fragment_file.lf")
register_component()
也可以使用函数 ``ldgen_add_fragment_files`` 在项目的 CMakeLists.txt 文件或者组件的 project_include.cmake 文件中指定该片段文件 ::
ldgen_add_fragment_files(target files ...)
指定放置区域
^^^^^^^^^^^^
链接脚本生成机制允许指定以下条目的存放位置:
- 组件中的一个或多个目标文件
- 一个或多个函数/变量(使用它们的名字来指定)
- 整个组件库
在继续讲解之前,假设我们的组件包含以下内容:
- 一个名为 ``component`` 的组件,在构建期间被归档为 ``libcomponent.a`` 库文件
- 该库中有三个存档的目标文件: ``object1.o````object2.o````object3.o``
- ``object1.o`` 中定义了 ``function1`` 函数,``object2.o`` 中定义了 ``function2`` 函数
- 在其中的一个 IDF KConfig 文件中存在 ``PERFORMANCE_MODE````PERFORMANCE_LEVEL`` 两个配置,相应地,项目的 sdkconfig 文件会通过 ``CONFIG_PERFORMANCE_MODE````CONFIG_PERFORMANCE_LEVEL`` 这两个宏来指示当前设置的值
在新建的链接片段文件中输入以下内容:
.. code-block:: none
[mapping]
archive: libcomponent.a
entries:
这会创建一个空的 :ref:`mapping 片段 <ldgen-mapping-fragment>`,它并不会执行任何操作。在链接期间,会使用 :ref:`默认的存放规则 <ldgen-default-placements>` 来映射 ``libcomponent.a``,除非填充了 ``entries`` 字段。
.. _ldgen-placing-object-files :
放置目标文件
""""""""""""
假设整个 ``object1.o`` 目标文件对性能至关重要,所以最好把它放在 RAM 中。另一方面,假设``object2.o`` 目标文件包含有从深度睡眠唤醒所需的数据,因此需要将它存放到 RTC 内存中。可以在链接片段文件中写入以下内容:
.. code-block:: none
[mapping]
archive: libcomponent.a
entries:
object1 (noflash) # 将所有代码和只读数据放置在 IRAM 和 DRAM 中
object2 (rtc) # 将所有代码、数据和只读数据放置到 RTC 快速内存和 RTC 慢速内存中
那么 ``object3.o`` 放在哪里呢?由于未指定放置规则,它会被存放到默认区域。
放置函数和数据
""""""""""""""
假设在 ``object1.o`` 目标文件中只有 ``function1`` 是与性能密切相关,且在 ``object2.o`` 目标文件中只有 ``function2`` 需要在深度睡眠唤醒后执行。可以在链接片段文件中写入以下内容:
.. code-block:: none
[mapping]
archive: libcomponent.a
entries:
object1:function1 (noflash)
object2:function2 (rtc)
``object1.o````object2.o`` 的剩余函数以及整个 ``object3.o`` 目标文件会被存放到默认区域。指定数据存放区域的方法很类似,仅需将 ```` 之后的函数名,替换为变量名即可。
.. warning::
使用符号名来指定放置区域有一定的 :ref:`局限 <ldgen-type1-limitations>`。因此,您也可以将相关代码和数据集中在源文件中,然后根据 :ref:`使用目标文件的放置规则 <ldgen-placing-object-files>` 进行放置。
放置整个组件
""""""""""""
在这个例子中,假设我们需要将整个组件存放到 RAM 中,可以这样写:
.. code-block:: none
[mapping]
archive: libcomponent.a
entries:
* (noflash)
类似的,下面的写法可以将整个组件存放到 RTC 内存中:
.. code-block:: none
[mapping]
archive: libcomponent.a
entries:
* (rtc)
依赖于具体配置的存放方式
""""""""""""""""""""""""
假设只有当 sdkconfig 文件中存在 ``CONFIG_PERFORMANCE_MODE == y`` 时,整个组件才会被放置到指定区域,可以这样写:
.. code-block:: none
[mapping]
archive: libcomponent.a
entries:
: PERFORMANCE_MODE = y
* (noflash)
其含义可以通过如下伪代码来表述:
.. code-block:: none
if PERFORMANCE_MODE = y
place entire libcomponent.a in RAM
else
use default placements
此外,您还可以设置多个判断条件。假设有如下需求:当 ``CONFIG_PERFORMANCE_LEVEL == 1`` 时,只有 ``object1.o`` 存放到 RAM 中;当 ``CONFIG_PERFORMANCE_LEVEL == 2`` 时,``object1.o````object2.o`` 会被存放到 RAM 中;当 ``CONFIG_PERFORMANCE_LEVEL == 3`` 时,归档中的所有目标文件都会被存放到 RAM 中;当这三个条件都不满足时,将整个组件库存放到 RTC 内存中。虽然这种使用场景很罕见,不过,还是可以通过以下方式实现:
.. code-block:: none
[mapping]
archive: libcomponent.a
entries:
: PERFORMANCE_LEVEL = 3
* (noflash)
: PERFORMANCE_LEVEL = 2
object1 (noflash)
object2 (noflash)
: PERFORMANCE_LEVEL = 1
object1 (noflash)
: default
* (rtc)
用伪代码可以表述为:
.. code-block:: none
if CONFIG_PERFORMANCE_LEVEL == 3
place entire libcomponent.a in RAM
else if CONFIG_PERFORMANCE_LEVEL == 2
only place object1.o and object2.o in RAM
else if CONFIG_PERFORMANCE_LEVEL == 1
only place object1.o in RAM
else
place entire libcomponent.a in RTC memory
条件测试还支持 :ref:`其他操作 <ldgen-condition-entries>`
.. _ldgen-default-placements:
默认的存放规则
^^^^^^^^^^^^^^
到目前为止,“默认存放规则”一直作为未指定 ``rtc````noflash`` 存放规则时的备选放置方式。``noflash`` 或者 ``rtc`` 标记不仅仅是链接脚本生成机制中的关键字,实际上还是由用户指定且被称为 :ref:`scheme 片段 <ldgen-scheme-fragment>` 的对象。由于这些存放规则非常常用,所以 IDF 中已经预定义了这些规则。
类似地,还有一个名为 ``default`` 的 scheme 片段,它定义了默认的存放规则,详情请见 :ref:`默认 scheme <ldgen-default-scheme>`
.. note::
有关使用此功能的 IDF 组件的示例,请参阅 :component_file:`freertos/CMakeLists.txt`。为了提高性能,``freertos`` 组件通过该机制将所有目标文件中的代码、字面量和只读数据存放到 IRAM 中。
快速入门指南到此结束,下面的文章将进一步详细讨论这个机制,例如它的组件、基本概念、语法、如何集成到构建系统中等等。以下部分有助于创建自定义的映射或者修改默认行为。
组件
----
.. _ldgen-fragment-files :
链接片段文件
^^^^^^^^^^^^
“链接片段文件”包含称为“片段”的对象,每个片段含有多条信息,放在一起时即可形成寻访规则,共同描述目标文件各个段在二进制输出文件中的存放位置。
换言之,处理“链接片段文件”也就是在 GNU LD 的 ``SECTIONS`` 命令中,创建段的存放规则,并将其放在一个内部 ``target`` token 中。
下面讨论三种类型的片段。
.. note::
片段具有名称属性mapping 片段除外)并且是全局可见的。片段的命名遵循 C 语言的基本变量命名规则,即区分大小写;必须以字母或者下划线开头;允许非初始字符使用字母、数字和下划线;不能使用空格等特殊字符。此外,每种片段都有自己的独立命名空间,如果多个片段的类型和名称相同,就会引发异常。
.. _ldgen-sections-fragment :
I. sections 片段
""""""""""""""""
sections 片段定义了 GCC 编译器输出的目标文件段的列表,可以是默认的段(比如 ``.text`` 段、``.data`` 段),也可以是用户通过 ``__attribute__`` 关键字自定义的段。
此外,用户还可以在某类段后增加一个 ``+``,表示囊括列表中的“所有这类段”和“所有以这类段开头的段”。相较于显式地罗列所有的段,我们更推荐使用这种方式。
**语法**
.. code-block:: none
[sections:name]
entries:
.section+
.section
...
**示例**
.. code-block:: none
# 不推荐的方式
[sections:text]
entries:
.text
.text.*
.literal
.literal.*
# 推荐的方式,效果与上面等同
[sections:text]
entries:
.text+ # 即 .text 和 .text.*
.literal+ # 即 .literal 和 .literal.*
.. _ldgen-scheme-fragment :
II. scheme 片段
"""""""""""""""
scheme 片段定义了为每个 sections 指定的 ``target``
**语法**
.. code-block:: none
[scheme:name]
entries:
sections -> target
sections -> target
...
**示例**
.. code-block:: none
[scheme:noflash]
entries:
text -> iram0_text # 名为 text 的 sections 片段下的所有条目均归入 iram0_text
rodata -> dram0_data # 名为 rodata 的 sections 片段下的所有条目均归入 dram0_data
.. _ldgen-default-scheme:
**default scheme**
注意,有一个名为 ``default`` 的 scheme 很特殊,特殊在于 catch-all 存放规则都是从这个 scheme 中的条目生成的。这意味着,如果该 scheme 有一条 ``text -> flash_text`` 条目,则将为目标 ``flash_text`` 生成如下的存放规则 :
.. code-block:: none
*(.literal .literal.* .text .text.*)
此后,这些生成的 catch-all 规则将用于未指定映射规则的情况。
.. note::
``default`` scheme 是在 :component:`esp32/ld/esp32_fragments.lf` 文件中定义的,此外,快速上手指南中提到的内置 ``noflash`` scheme 片段和 ``rtc`` scheme 片段也是在这个文件中定义的。
.. _ldgen-mapping-fragment :
III. mapping 片段
"""""""""""""""""
mapping 片段定义了可映射实体(即目标文件、函数名、变量名)对应的 scheme 片段。具体来说mapping 片段有两种类型的条目,分别为映射条目和条件条目。
.. note::
mapping 片段没有具体的名称属性,内部会根据归档条目的值构造其名称。
**语法**
.. code-block:: none
[mapping]
archive: archive # 构建后输出的存档文件的名称(即 libxxx.a
entries:
: condition # 条件条目,非默认
object:symbol (scheme) # 映射条目Type I
object (scheme) # 映射条目Type II
* (scheme) # 映射条目Type III
# 为了提高可读性,可以适当增加分隔行或注释,非必须
: default # 条件条目,默认
* (scheme) # 映射条目Type III
.. _ldgen-mapping-entries :
**映射条目**
mapping 片段的映射条目共有三种类型,分别为:
``Type I``
同时指定了目标文件名和符号名。其中,符号名可以是函数名或者变量名。
``Type II``
仅指定了目标文件名。
``Type III``
指定了 ``*``,也就是指定了归档文件中所有目标文件。
接下来,让我们通过展开一个 ``Type II`` 映射条目,更好地理解映射条目的含义。最初:
.. code-block:: none
object (scheme)
接着,让我们根据条目定义,将这个 scheme 片段展开:
.. code-block:: none
object (sections -> target,
sections -> target,
...)
然后再根据条目定义,将这个 sections 片段展开:
.. code-block:: none
object (.section,
.section,
... -> target, # 根据目标文件将这里所列出的所有段放在该目标位置
.section,
.section,
... -> target, # 同样的方法指定其他段
...) # 直至所有段均已展开
.. _ldgen-type1-limitations :
**有关 Type I 映射条目的局限性**
``Type I`` 映射条目可以工作的大前提是编译器必须支持 ``-ffunction-sections````-ffdata-sections`` 选项。因此,如果用户主动禁用了这两个选项,``Type I`` 映射条目就无法工作。此外,值得注意的是,``Type I`` 映射条目的实现还与输出段有关。因此,有时及时用户在编译时没有选择禁用这两个选项,也有可能无法使用 ``Type I`` 映射条目。
例如,当使用 ``-ffunction-sections`` 选项时,编译器会给每个函数都输出一个单独的段,根据段名的构造规则,这些段的名称应该类似 ``.text.{func_name}````.literal.{func_name}``。然而,对于函数中的字符串文字,情况并非如此,因为它们会使用池化后或者新创建的段名。
当使用 ``-fdata-sections`` 选项时,编译器会给每一个全局可见的数据输出一个单独的段,名字类似于 ``.data.{var_name}````.rodata.{var_name}`` 或者 ``.bss.{var_name}``。这种情况下,``Type I`` 映射条目可以使用。然而,对于在函数作用域中声明的静态数据,编译器在为其生成段名时会同时使用其变量名和其他信息,因此当涉及在函数作用域中定义的静态数据时就会出现问题。
.. _ldgen-condition-entries :
**条件条目**
条件条目允许根据具体项目配置生成不同的链接脚本。也就是说,可以根据一些配置表达式的值,选择使用一套不同的映射条目。由于检查配置的过程是通过 :idf_file:`tools/kconfig_new/kconfiglib.py` 文件中的 ``eval_string`` 完成的,因此条件表达式也必须遵循 ``eval_string`` 的语法和限制。
在一个 mapping 片段中,跟着一个条件条目后定义的所有映射条目均属于该条件条目,直至下一个条件条目的出现或者是该 mapping 片段的结束。在检查配置时,编译器将逐条检查这个 mapping 片段中的所有条件条目,直至找到一个满足条件的条件条目(即表达式为 ``TRUE``),然后使用该条件条目下定义的映射条目。另外,尽管每个映射都已包含一个隐式的空映射,但用户还是可以自定义一个默认条件,即所有条件条目均不满足时(即没有表达式为 ``TRUE``)使用的映射条目。
**示例**
.. code-block:: none
[scheme:noflash]
entries:
text -> iram0_text
rodata -> dram0_data
[mapping:lwip]
archive: liblwip.a
entries:
: LWIP_IRAM_OPTIMIZATION = y # 如果 CONFIG_LWIP_IRAM_OPTIMIZATION 在 sdkconfig 中被定义为 'y'
ip4:ip4_route_src_hook (noflash) # 将 ip4.o:ip4_route_src_hookip4.o:ip4_route_src 和
ip4:ip4_route_src (noflash) # ip4.o:ip4_route 映射到 noflash scheme
ip4:ip4_route (noflash) # 该 scheme 会将他们存放到 RAM 中
: default # 否则不使用特殊的映射规则
.. _ldgen-script-templates :
链接脚本模板
^^^^^^^^^^^^
链接脚本模板与其他链接脚本没有本质区别,但带有特定的标记语法,可以指示放置生成的存放规则的位置,是指定存放规则的放置位置的框架。
**语法**
如需引用一个 ``target`` token 下的所有存放规则,请使用以下语法:
.. code-block:: none
mapping[target]
**示例**
以下示例是某个链接脚本模板的摘录。该链接脚定义了一个输出段 ``.iram0.text``,里面包含一个引用目标 ``iram0_text`` 的标记。
.. code-block:: none
.iram0.text :
{
/* 标记 IRAM 的边界 */
_iram_text_start = ABSOLUTE(.);
/* 引用 iram0_text */
mapping[iram0_text]
_iram_text_end = ABSOLUTE(.);
} > iram0_0_seg
下面,让我们更具体一点。假设某个链接脚本生成器收集到了以下片段:
.. code-block:: none
[sections:text]
.text+
.literal+
[sections:iram]
.iram1+
[scheme:default]
entries:
text -> flash_text
iram -> iram0_text
[scheme:noflash]
entries:
text -> iram0_text
[mapping:freertos]
archive: libfreertos.a
entries:
* (noflash)
则该脚本生成器生成的链接脚本文件,其摘录应如下所示:
.. code-block:: c
.iram0.text :
{
/* 标记 IRAM 的边界 */
_iram_text_start = ABSOLUTE(.);
/* 将链接片段处理生成的存放规则放置在模板标记的位置处 */
*(.iram1 .iram1.*)
*libfreertos.a:(.literal .text .literal.* .text.*)
_iram_text_end = ABSOLUTE(.);
} > iram0_0_seg
``*libfreertos.a:(.literal .text .literal.* .text.*)``
这是从 ``freertos`` mapping 片段的 ``* (noflash)`` 条目中生成的规则。``libfreertos.a`` 归档文件下的所有目标文件的 ``text`` 段会被收集到 ``iram0_text`` 目标下(假设采用 ``noflash`` scheme并放在模板中被 ``iram0_text`` 标记的地方。
``*(.iram1 .iram1.*)``
这是从 ``default`` scheme 的 ``iram -> iram0_text`` 条目生成的规则,因为 ``default`` scheme 指定了一个 ``iram -> iram0_text`` 条目,因此生成的规则也将放在被 ``iram0_text`` 标记的地方。值得注意的是,由于该规则是从 ``default`` scheme 中生成的,因此在同一目标下收集的所有规则下排在第一位。
与构建系统的集成
----------------
链接脚本是在应用程序的构建过程中生成的,此时尚未链接形成最终的二进制文件。实现该机制的工具位于 ``$(IDF_PATH)/tools/ldgen`` 目录下。
链接脚本模板
^^^^^^^^^^^^
目前使用的链接脚本模板是 :component:`esp32/ld/esp32.common.ld.in`,仅用于应用程序的构建,生成的链接脚本文件将放在同一组件的构建目录下。值得注意的是,修改此链接描述文件模板会触发应用程序的二进制文件的重新链接。
链接片段文件
^^^^^^^^^^^^
任何组件都可以将片段文件添加到构建系统中,方法有两种:设置 ``COMPONENT_ADD_LDFRAGMENTS`` 变量或者使用 ``ldgen_add_fragment_files`` 函数(仅限 CMake具体可以参考 :ref:`添加片段文件 <ldgen-add-fragment-file>` 小节中的介绍。值得注意的是,修改构建系统中的任何片段文件都会触发应用程序的二进制文件的重新链接。

Some files were not shown because too many files have changed in this diff Show More