ESP32开发二_LED闪烁灯

LED闪烁灯

交流QQ: 1048272975             QQ交流群: 636564526

控制LED灯的亮灭是MCU开发中一个最简单的应用功能,实现这个应用功能包含了MCU开发中工程的构建、编译的过程、下载烧录的方式、开机运行的流程等等内容。

1. 开发工具链

针对ESP32开发,乐鑫官方提供了ESP-IDF框架以及对应的开发工具链,开发环境的搭建可以参考上一章节的内容。作为一个LED灯控制的简单程序,只需要基于Xtensa架构的GNU交叉编译工具的支持。

2. LED闪烁灯程序

以通用的main函数作为程序的入口,通过控制ESP32 GPIO输出高低电平来控制LED灯的亮灭。

2.1. 关闭看门狗

参考ESP-IDF目录components/bootloader裸机引导程序的实现流程以及ESP32芯片数据手册,可以知道Flash启动时使能了主系统看门狗定时器MWDT和RTC看门狗定时器RWDT,程序应加入关闭看门狗的代码。

设置TIMGn_Tx_WDTCONFIG0_REG寄存器的TIMGn_Tx_WDT_FLASHBOOT_MOD_EN(位14)为0即可关闭主系统看门狗定时器MWDT。

主系统看门狗MWDT配置寄存器

设置RTC_CNTL_WDTCONFIG0_REG寄存器的RTC_CNTL_WDT_FLASHBOOT_MOD_EN (位10)为0即可关闭RTC看门狗定时器RWDT。

RTC看门狗RWDT配置寄存器

2.2. 初始化GPIO

通过设置GPIO交换矩阵配置寄存器GPIO_FUNCn_OUT_SEL_CFG_REG的输出选择为256,使对应的GPIO n引脚为GPIO输出功能。通过设置GPIO输出使能置位寄存器PIO_ENABLE_W1TS_REG对应n位为1,使能GPIO n的输出。通过设置GPIO输出置位寄存器GPIO_OUT_W1TS_REG对应n位为1, GPIO n输出高电平,通过设置GPIO输出清零寄存器GPIO_OUT_W1TC_REG对应n位为1, GPIO n输出低电平。

GPIO交换矩阵输出信

2.3. 循环闪烁

在while循环里面控制GPIO输出低电平,然后软件延时,再输出高电平,软件延时,如此循环,实现LED灯的闪烁。

2.4. c代码

LED闪烁灯项目路径为D:esp32led,完整的LED闪烁灯代码led.c如下:

3. 编译运行

ESP32使用Xtensa架构的GNU交叉编译工具,可以使用通用的GUN工具命令编译代码,链接生成可执行代码,也可以生成相应的输出文件,如map文件、反汇编等等用于分析调试。

3.1. 编译

用gcc命令编译led.c,输出led.o文件。

xtensa-esp32-elf-gcc.exe -Os -c led.c -o led.o

代码编译

3.2. 链接

编译生成目标文件后,需要通过链接器链接为一个可执行文件,可以通过链接脚本控制链接过程。链接脚本可以指定程序的入口、各个输入段的内存布局等等,其有特定的语法格式。可以参考ESP-IDF目录componentsbootloadersubprojectmainldesp32下bootloader.ld文件,实现ESP32裸机程序的链接脚本。

LED闪烁灯项目的链接脚本led.ld实现如下:

链接脚本指定了程序的入口为main,代码段.text加载到0x40078000地址的内存区域执行。由于LED闪烁灯程序比较简单,只有代码段.text以及字面量段.literal,没有全局变量静态变量.bss段和.data段、常数.rodata段,可以不指定未使用段的内存布局。

用ld命令链接目标文件,生成可执行文件led.elf。用-T指定led.ld链接脚本,用-Map指定输出map文件,可以了解程序、数据、IO空间等等的映射关系。

xtensa-esp32-elf-ld.exe -Map led.map -T led.ld led.o -o led.elf

led.map文件

3.3. 反汇编

链接生成可执行elf文件后,可以提取可执行段并生成反汇编代码,用于代码优化、调试等分析。

用objdump命令反汇编led.elf,输出led.dis反汇编文件。

xtensa-esp32-elf-objdump.exe -d led.elf > led.dis

led.dis反汇编代码

ESP32为Xtensa架构,该架构具有很强的可重构性和可拓展性,允许自定义全新指令,用于硬件加速,可提升处理器的运算性能同时又便于软件实现控制。详细的汇编指令可参考Xtensa指令集体系结构(ISA)数据手册。

从反汇编代码可以看出,函数总是以entry指令开头,该指令主要实现两个功能:

1、为函数分配堆栈帧,计算并设置函数的栈指针。

2、根据函数调用指令calln/callxn,将寄存器窗口移动/旋转n个物理寄存器。

例如entry a1, 32,表示为函数分配32个字长的堆栈帧,并计算设置函数栈指针a1的值。当使用call8调用该函数时,寄存器窗口移动/旋转8个物理寄存器。

针对函数的调用,Xtensa架构设计了一种窗口旋转方式的寄存器管理机制,将逻辑寄存器和物理寄存器分开。对于ESP32,有16个逻辑寄存器(指令中的a0~a15),有64个环形物理寄存器,通过WindowBase寄存器,使逻辑寄存器可滑动对应实际的物理寄存器。从而避免寄存器覆盖,减少入栈和出栈的操作。

这一设计机制可让嵌入式软件性能得到明显提高。这是因为使用函数时,往往需要入栈,保存函数使用前的寄存器现场,函数结束时,需要出栈,恢复之前的寄存器现场后返回。入栈和出栈将对外部内存进行读写,而外部内存对于高性能CPU来说是慢速设备,需打断流水线等待访问完成,因此频繁访问外部内存将极大地影响性能。通常高性能的CPU,如Cortex-A系列ARM核,通过增加一级或二级Cache来降低CPU读写等待内存的几率。而Xtensa架构直接减少了函数调用时的入栈和出栈,降低了内存的访问,更大限度地提升了性能。

环形物理寄存器

3.4. 烧录文件

链接生成的可执行文件为elf格式,该文件保存了二进制可执行代码,适用于Unix类系统环境。ESP32无法直接运行elf代

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2022年2月5日
下一篇 2022年2月5日

相关推荐