文章目录
- 前言
- 一、工程要达成什么
- 二、工程结构
- 三、板级默认配置(N16R8)
- 四、编译、烧录、监视
- 五、代码走读(main/sysinfo.c)
- 5.1 头文件与职责
- 5.2 `app_main` 流程
- 5.3 芯片信息
- 5.4 内存信息(重点)
- 5.5 FreeRTOS 两行
- 六、运行输出
- 七、和「官方 hello_world」的关系
- 八、建议你改的几处小练习
- 九、踩坑速查
- 十、本篇命令小结
- 全部代码
- 参考链接
目录 | 上篇 | 下篇
前言
环境装好、命令会用、板卡规格也清楚之后,该动手写第一个固件了。本篇以仓库中的sysinfo工程为例:用 ESP-IDF 在ESP32-S3上跑起来,经串口打印芯片、CPU、Flash、堆与 PSRAM 等信息,并每秒刷新剩余堆。
目标不是堆功能,而是把这条链路跑通:
建工程 → set-target → 配 N16R8 → 写 app_main → build → flash → monitor工程路径(相对本仓库根):sysinfo/。
一、工程要达成什么
启动后串口大致看到三类信息:
| 块 | 内容 |
|---|---|
| Chip | 目标芯片、IDF 版本、核数、硅片修订、Wi-Fi/BLE、CPU 频率、Flash 容量 |
| Memory | 总堆空闲、历史最小空闲、片内 / DMA / PSRAM 空闲与最大连续块 |
| FreeRTOS | Tick 频率、当前任务数 |
随后每秒一行 uptime 与堆快照,确认程序在跑、堆没有异常掉光。
实测(本系列默认板)可对上这些量级:
| 项 | 期望量级 |
|---|---|
| Flash | 16 MB |
| PSRAM | 约 8 MB可用(日志里常有Found 8MB PSRAM) |
| CPU | 默认常见160 MHz(可在 menuconfig 改到 240) |
| 片内空闲 | 约数百 KB |
| 总堆空闲 | 片内 + PSRAM,约8 MB+ |
二、工程结构
sysinfo/ CMakeLists.txt # 工程入口:project(sysinfo) sdkconfig.defaults # N16R8 默认:16MB Flash + Octal PSRAM sdkconfig # set-target / menuconfig 后生成(本地生效) main/ CMakeLists.txt # 注册源文件 sysinfo.c # app_main 与打印逻辑 README.md # 工程内速查 build/ # 编译产物(勿手改)要点:
- 工程根的
CMakeLists.txt必须include($ENV{IDF_PATH}/tools/cmake/project.cmake),再project(...)。 main组件用idf_component_register声明源文件;入门阶段一个.c足够。sdkconfig.defaults存「换机器也希望一致」的板级默认;首次配置会合并进sdkconfig。
创建方式:
# 官方脚手架idf.py create-project sysinfocdsysinfo三、板级默认配置(N16R8)
sdkconfig.defaults内容:
# ESP32-S3-N16R8 defaults (see esp32/e003.md) CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y CONFIG_SPIRAM_SPEED_80M=y若你的板不是 Octal PSRAM / 不是 16 MB Flash,先改 defaults 或menuconfig,再fullclean后重新set-target/build。
四、编译、烧录、监视
串口名以本机为准;macOS 上 S3 原生 USB 常见为/dev/cu.usbmodem*:
ls/dev/cu.usbmodem*完整流程:
get_idfcdsysinfo idf.py set-target esp32s3# 首次或换目标时需要idf.py build idf.py-p/dev/cu.usbmodemXXXXXXXX flash monitor| 操作 | 说明 |
|---|---|
| 退出监视器 | Ctrl+] |
| 只烧不监 | idf.py -p <PORT> flash |
| 复位后再看日志 | 监视器里按Ctrl+T再Ctrl+R(见 e002) |
成功烧录时 esptool 会打印芯片特性,例如双核、Embedded PSRAM 8MB 等,可与后面应用打印交叉核对。
五、代码走读(main/sysinfo.c)
ESP-IDF 应用入口是app_main(由系统在启动任务里调用),不是桌面程序的main。
5.1 头文件与职责
| 头文件 | 用途 |
|---|---|
esp_chip_info.h | esp_chip_info():核数、特性、修订号 |
esp_flash.h | esp_flash_get_size():Flash 容量 |
esp_system.h | IDF 版本、总堆空闲 / 历史最小空闲 |
esp_heap_caps.h | 按能力查堆:INTERNAL/DMA/SPIRAM |
freertos/FreeRTOS.h+task.h | vTaskDelay、任务数、Tick |
sdkconfig.h | CONFIG_*宏(目标名、CPU 频率、是否开 SPIRAM) |
5.2app_main流程
voidapp_main(void){// 1. 一次性打印 Chip / Memory / FreeRTOSprint_chip_info();print_memory_info();print_rtos_info();// 2. 死循环:每秒打一行堆快照(固件常驻,不要 return 后空等)while(1){// printf uptime + heap ...vTaskDelay(pdMS_TO_TICKS(1000));}}入门习惯:需要周期干活时用vTaskDelay,避免空转占满 CPU。
5.3 芯片信息
esp_chip_info_tchip_info;esp_chip_info(&chip_info);// chip_info.cores / .revision / .featuresCONFIG_IDF_TARGET、CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ来自配置,编译期写入,用来打印「当前固件按什么目标、默认主频」构建。
Flash 用运行时 API:
uint32_tflash_size;esp_flash_get_size(NULL,&flash_size);// 字节;再换成 MB5.4 内存信息(重点)
| API | 含义 |
|---|---|
esp_get_free_heap_size() | 当前总空闲堆(含已并入分配器的 PSRAM) |
esp_get_minimum_free_heap_size() | 启动以来空闲堆的最小值(看有没有短暂吃紧) |
heap_caps_get_free_size(MALLOC_CAP_INTERNAL) | 片内 SRAM 空闲 |
heap_caps_get_largest_free_block(...) | 最大连续空闲块(比「总空闲」更能说明能否一次malloc大块) |
heap_caps_get_free_size(MALLOC_CAP_DMA) | 可给 DMA 用的空闲 |
heap_caps_get_free_size(MALLOC_CAP_SPIRAM) | PSRAM 空闲(需CONFIG_SPIRAM) |
代码里用#if CONFIG_SPIRAM包住 PSRAM 打印:没开外挂 RAM 时仍能编译通过,并提示 disabled。
5.5 FreeRTOS 两行
configTICK_RATE_HZ// 常见 100 HzuxTaskGetNumberOfTasks()// 当前任务数(含系统任务)本例不自建任务,数字会偏小,够用来确认 RTOS 已起来。
六、运行输出
执行命令写入并监测
idf.py-p/dev/cu.usbmodemXXXXXXXX flash monitor输出结果
*** ESP32-S3 sysinfo *** ======== Chip ======== Target esp32s3 IDF version v6.0.1 CPU cores 2 Silicon revision v0.2 Features Wi-Fi BLE CPU frequency 160 MHz Flash size 16 MB (external) ======== Memory ======== Heap free 8745164 bytes (8540.2 KB) Heap min free 8745164 bytes (8540.2 KB) Internal free 391039 bytes ( 381.9 KB) Internal largest 294912 bytes ( 288.0 KB) DMA-capable free 383251 bytes ( 374.3 KB) PSRAM free 8386156 bytes (8189.6 KB) PSRAM largest 8257536 bytes (8064.0 KB) ======== FreeRTOS ======== Tick rate 100 Hz Tasks 5 [uptime 0s] free heap=8745164 internal=391039 psram=8386156 [uptime 1s] free heap=8745164 internal=391039 psram=8386156 [uptime 2s] free heap=8745164 internal=391039 psram=8386156 [uptime 3s] free heap=8745164 internal=391039 psram=8386156 [uptime 4s] free heap=8745164 internal=391039 psram=8386156启动日志里还可留意:
SPI Flash Size : 16MBFound 8MB PSRAM device/SPI SRAM memory test OKcpu freq: 160000000 Hz
七、和「官方 hello_world」的关系
官方examples/get-started/hello_world也会打印芯片与最小空闲堆,然后倒计时esp_restart()。
sysinfo在同样入门路径上多做了三件事,更贴本系列板卡:
- 拆开片内 / DMA / PSRAM,方便对照上篇
- 用
sdkconfig.defaults固化 N16R8 - 常驻循环打堆,而不是自动重启(便于盯监视器)
会改sysinfo之后,再去读官方示例会轻松很多。
八、建议你改的几处小练习
按兴趣任选,巩固 API,不必一次做完:
- 把 CPU 默认频率改为240 MHz(
menuconfig→ ESP System Settings),重编烧录,看打印是否变化。 - 增加一行:打印
esp_get_free_internal_heap_size()(若当前 IDF 提供)或当前任务名pcTaskGetName(NULL)。 - 用
heap_caps_malloc(1 * 1024 * 1024, MALLOC_CAP_SPIRAM)申请 1 MB,打印前后 PSRAM free 差值,再free。 - 把 1 秒周期改成
CONFIG可配,或拆成独立 FreeRTOS 任务。
九、踩坑速查
| 现象 | 排查 |
|---|---|
idf.py: command not found | get_idf或source ~/esp/esp-idf/export.sh |
| 找不到串口 | 换数据线;ls /dev/cu.usbmodem*;驱动 / 线材问题见 e001 |
| Flash 不是 16 MB / 校验失败 | CONFIG_ESPTOOLPY_FLASHSIZE_16MB;模组是否真是 N16 |
| PSRAM free 为 0 或启动报 PSRAM 错 | Octal 模式与频率是否匹配板卡;见 e003 |
| 监视器乱码 | 波特率是否 115200(默认);确认连的是正在跑本固件的口 |
| 改 defaults 不生效 | 删掉或调整已有sdkconfig,或idf.py fullclean后重新配置再编 |
十、本篇命令小结
get_idfcdsysinfo idf.py set-target esp32s3 idf.py build idf.py-p/dev/cu.usbmodemXXXXXXXX flash monitor# 退出监视:Ctrl+]全部代码
sysinfo.c
/* * ESP32-S3 入门:打印芯片 / CPU / 内存等信息 */#include<inttypes.h>#include<stdio.h>#include"esp_chip_info.h"#include"esp_flash.h"#include"esp_heap_caps.h"#include"esp_system.h"#include"freertos/FreeRTOS.h"// IWYU pragma: keep#include"freertos/task.h"#include"sdkconfig.h"staticvoidprint_bytes(constchar*label,size_tbytes){printf(" %-22s %8zu bytes (%6.1f KB)\n",label,bytes,bytes/1024.0);}staticvoidprint_chip_info(void){esp_chip_info_tchip_info;uint32_tflash_size=0;esp_chip_info(&chip_info);printf("\n======== Chip ========\n");printf(" Target %s\n",CONFIG_IDF_TARGET);printf(" IDF version %s\n",esp_get_idf_version());printf(" CPU cores %d\n",chip_info.cores);printf(" Silicon revision v%d.%d\n",chip_info.revision/100,chip_info.revision%100);printf(" Features %s%s%s%s\n",(chip_info.features&CHIP_FEATURE_WIFI_BGN)?"Wi-Fi ":"",(chip_info.features&CHIP_FEATURE_BT)?"BT ":"",(chip_info.features&CHIP_FEATURE_BLE)?"BLE ":"",(chip_info.features&CHIP_FEATURE_EMB_PSRAM)?"embedded-PSRAM ":"");#ifdefined(CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ)printf(" CPU frequency %d MHz\n",CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ);#endifif(esp_flash_get_size(NULL,&flash_size)==ESP_OK){printf(" Flash size %"PRIu32" MB (%s)\n",flash_size/(1024*1024),(chip_info.features&CHIP_FEATURE_EMB_FLASH)?"embedded":"external");}else{printf(" Flash size (read failed)\n");}}staticvoidprint_memory_info(void){printf("\n======== Memory ========\n");print_bytes("Heap free",esp_get_free_heap_size());print_bytes("Heap min free",esp_get_minimum_free_heap_size());print_bytes("Internal free",heap_caps_get_free_size(MALLOC_CAP_INTERNAL));print_bytes("Internal largest",heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL));print_bytes("DMA-capable free",heap_caps_get_free_size(MALLOC_CAP_DMA));#ifCONFIG_SPIRAMprint_bytes("PSRAM free",heap_caps_get_free_size(MALLOC_CAP_SPIRAM));print_bytes("PSRAM largest",heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM));#elseprintf(" PSRAM disabled in sdkconfig\n");#endif}staticvoidprint_rtos_info(void){printf("\n======== FreeRTOS ========\n");printf(" Tick rate %u Hz\n",(unsigned)configTICK_RATE_HZ);printf(" Tasks %u\n",(unsigned)uxTaskGetNumberOfTasks());}voidapp_main(void){printf("\n*** ESP32-S3 sysinfo ***\n");print_chip_info();print_memory_info();print_rtos_info();printf("\n");intsec=0;while(1){printf("[uptime %ds] free heap=%"PRIu32" internal=%zu"#ifCONFIG_SPIRAM" psram=%zu"#endif"\n",sec,esp_get_free_heap_size(),heap_caps_get_free_size(MALLOC_CAP_INTERNAL)#ifCONFIG_SPIRAM,heap_caps_get_free_size(MALLOC_CAP_SPIRAM)#endif);fflush(stdout);vTaskDelay(pdMS_TO_TICKS(1000));sec++;}}参考链接
- 本仓库工程:
../sysinfo/ - ESP-IDF · 入门 Hello World:https://docs.espressif.com/projects/esp-idf/zh_CN/stable/esp32s3/get-started/index.html
- 堆分配 / heap_caps:https://docs.espressif.com/projects/esp-idf/zh_CN/stable/esp32s3/api-reference/system/mem_alloc.html
- 芯片信息:https://docs.espressif.com/projects/esp-idf/zh_CN/stable/esp32s3/api-reference/system/misc_system_api.html