qiaoweiyiyi 发表于 2019-3-1 15:27:21

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 管脚


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


2. RTC GPIO 翻转图示本例子主 CPU 设置 ULP 协处理器每隔 10ms 唤醒自身一次 并且 ULP 协处理器每隔 8 个唤醒周期后,再唤醒主 CPU 一次,依此循环。每次处理器状态切换时,均有相应的 GPIO 翻转指示当前的状态。
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 SoCand wakup SoC if the values match */
    and r0, r3, toggle_cycles_to_wakeup
    jump wake_up, eq
4. 额外说明

如果你运行了这个例子,而且试图分析各个处理器切换状态,可能会遇到上图中额外多出的 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


---------------------
作者:espressif
来源:CSDN


相关阅读:ESP32 AT 入门指南
ESP32 的 ULP 协处理器简介和汇编编译环境设置
ESP32 - ULP 协处理器在低功耗模式下操作 RTC GPIO

feixiang20 发表于 2019-4-4 10:37:25

看看了

熊猫火锅 发表于 2019-4-12 16:03:48

我也是看看,没有人气呀

kindzhon 发表于 2020-12-4 13:08:12

牛,就是说deepsleep下是可以控制GPIO状态的:victory:

cqd4b21f8 发表于 2021-5-19 12:51:20

大佬,源码能发出来看看吗
页: [1]
查看完整版本: ESP32 - ULP 协处理器在低功耗模式下操作 RTC GPIO