ESP32 - ULP 协处理器在低功耗模式下操作 RTC GPIO

ESP32 - ULP 协处理器在低功耗模式下操作 RTC GPIO 的例子

本文目的是介绍 ESP32 如何在 ULP 协处理器中操作 RTC GPIO

1. RTC GPIO

RTC GPIO 一共有 18 个 IO 口,这些 GPIO 管脚具有低功耗 RTC 性能和模拟功能,并且由 ESP32 的 RTC 子系统控制。这些功能不使用 IO_MUX 和 GPIO 交换矩阵,而是使用 RTC_MUX 将 IO 指向 RTC 子系统。

当这些管脚被配置为 RTC GPIO 管脚时,作为输出的管脚能够在芯片处于 Deep-Sleep 睡眠状态下保持输出电平值,或者作为输入管脚使用时可以将芯片从 Deep-Sleep 中唤醒。

下表列出了 RTC 管脚和其对应的 GPIO 管脚

RTC GPIO NumGPIO NumPad NameAnalog Function1Analog Function2Analog Function3
036SENSOR_VPADC_HADC1_CH0-
137SENSOR_CAPPADC_HADC1_CH1-
238SENSOR_CAPNADC_HADC1_CH2-
339SENSOR_VN-ADC1_CH3-
434VDET_1-ADC1_CH6-
535VDET_2-ADC1_CH7-
625GPIO25DAC_1ADC2_CH8-
726GPIO26DAC_2ADC2_CH9-
83332K_XNXTAL_32K_NADC1_CH5TOUCH8
93232K_XPXTAL_32K_PADC1_CH4TOUCH9
104GPIO4-ADC2_CH0TOUCH0
110GPIO0-ADC2_CH1TOUCH1
122GPIO2-ADC2_CH2TOUCH2
1315MTDO-ADC2_CH3TOUCH3
1413MTCK-ADC2_CH4TOUCH4
1512MTDI-ADC2_CH5TOUCH5
1614MTMS-ADC2_CH6TOUCH6
1727GPIO27-ADC2_CH7TOUCH7

在本例子中,我们使用 GPIO25,GPIO26 指示 CPU 的工作状态;GPIO4,GPIO27 指示 ULP 协处理器的状态。

PIN说明
GPIO25主 CPU 运行时置高,主 CPU 休眠时置低
GPIO26每当主 CPU 被唤醒时,翻转一次电平状态
GPIO4ULP 协处理器运行时置高,ULP 协处理器时休眠时置低
GPIO27每当 ULP 协处理器被唤醒时,翻转一次电平状态

2. RTC GPIO 翻转图示

本例子主 CPU 设置 ULP 协处理器每隔 10ms 唤醒自身一次 并且 ULP 协处理器每隔 8 个唤醒周期后,再唤醒主 CPU 一次,依此循环。每次处理器状态切换时,均有相应的 GPIO 翻转指示当前的状态。
1

3.软件部分

ESP32 的 C 语言编译环境安装和配置参照 链接地址,另外 ULP 协处理器目前只支持汇编编程,所以还需要安装汇编工具链,下面介绍汇编工具链的安装和配置。

3.1 汇编环境的配置

ULP 协处理器配置汇编编译工具链,只需两步即可安装配置完毕,下面给出 ubuntu 操作系统下配置的步骤,或者点击 链接地址 获得更多 ULP 编程信息

  • 第一步, 下载工具链 binutils-esp32ulp toolchain 链接地址, 解压到需要安装的目录
  • 第二步,添加工具链的 bin 目录到系统环境变量 PATH 中。例如我的解压目录是 /opt/esp32ulp-elf-binutils 那么添加 export PATH=/opt/esp32ulp-elf-binutils/bin:$PATH 这一行到 /home 目录的隐藏文件 .bashrc 文件最后一行,保存关闭文件并使用命令 source .bashrc 使上述环境变量生效

至此,汇编编译环境就安装好了,将 ulp_rtc_gpio/ 目录下的 sdkconfig.defaults 复制一份改名为 sdkconfig,然后在工程中使用 make all -j8 && make flash monitor 编译并烧录命令时,会自动调用汇编工具链编译汇编代码。

3.2 汇编代码介绍

需要注意:每个 GPIO(包括 RTC GPIO)都有单独的 hold 功能,由 RTC 寄存器控制。 GPIO 的 hold 功能被置上后, GPIO 在置上 hold 那一刻的状态被强制保持,无论内部信号如何变化,修改 IO_MUX 配置或者 GPIO 配置,都不会改变 GPIO 的状态。所以如果希望在看门狗超时触发内核复位或系统复位时亦或者 Deep-sleep 时 GPIO 的状态不被改变,就需要提前把相应GPIO 的 hold 功能置位。

在下面的汇编代码中,我们需要操作 RTC_GPIO10, 则先应 disable RTC_GPIO10 管脚的 hold 功能后,再操作 RTC_GPIO10 输出高

	.global entry
entry:
	/* Disable hold of RTC_GPIO10 output */
	WRITE_RTC_REG(RTC_IO_TOUCH_PAD0_REG,RTC_IO_TOUCH_PAD0_HOLD_S,1,0)
	/* Set the RTC_GPIO10 output HIGH to signal that ULP is now up */
	WRITE_RTC_REG(RTC_GPIO_OUT_W1TS_REG,RTC_GPIO_OUT_DATA_W1TS_S+10,1,1)
	/* Wait some cycles to have visible trace on the scope */
	wait 1000

同理,在进入 Deep-Sleep 之前,拉低 RTC_GPIO10 之后,则需要把 RTC_GPIO10 管脚的 hold 功能置位,使其在系统复位时能够保持原来的电平状态

	.global toggle_complete
toggle_complete:
	/* Set the RTC_GPIO10 output LOW (clear output) to signal that ULP is now going down */
	WRITE_RTC_REG(RTC_GPIO_OUT_W1TC_REG,RTC_GPIO_OUT_DATA_W1TC_S+10,1,1)
	/* Enable hold on RTC_GPIO10 output */
	WRITE_RTC_REG(RTC_IO_TOUCH_PAD0_REG,RTC_IO_TOUCH_PAD0_HOLD_S,1,1)
	/* Compare the toggle counter with toggle cycles to wakeup SoC  and wakup SoC if the values match */ 
	and r0, r3, toggle_cycles_to_wakeup
	jump wake_up, eq

4. 额外说明

2

如果你运行了这个例子,而且试图分析各个处理器切换状态,可能会遇到上图中额外多出的 98ms 的疑惑。这里需要说明的是,汇编程序 Polling CPU 并唤醒 CPU 时间是很短的,绝大部分的时间是用来 boot 主 CPU 的(例如主 CPU 上电动作、一级 Bootloader 加载打印等时间消耗)。因为在 DeepSleep 状态下 CPU 的各个模块都是被关掉的,如内部 8MHz 振荡器、40MHz 高速晶振、PLL 及射频模块均禁用;数字内核断电,CPU 内容丢失,这里有一个重新上电加载的过程。

	/* Get ULP back to sleep */
	.global exit
exit:
	halt
	.global wake_up
wake_up:
	/* Check if the SoC can be woken up */
	READ_RTC_REG(RTC_CNTL_DIAG0_REG, 19, 1)
	and r0, r0, 1
	jump exit, eq
	/* Wake up the SoC and stop ULP program */
	wake
	/* Stop the wakeup timer so it does not restart ULP */
	WRITE_RTC_FIELD(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN, 0)
	halt
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值