本文最后修改时间:2025年05月27日 01:57
一、本节简介
本节以树莓派pico2开发板为例,举例如何写一个低功耗驱动。
二、实验平台
1、硬件平台
1)树莓派pico2开发板
①树莓派pico2开发板(作为仿真器)
②micro usb数据线
2)电脑
3)香瓜RP2350目标板
2、软件平台
1)VS CODE
三、版权声明
1)作者:甜甜的大香瓜
2)声明:喝水不忘挖井人,转载请注明出处。
3)纠错/业务合作:897503845@qq.com
4)香瓜嵌入式之树莓派群:512598061
5)本文出处:原创连载资料《简单粗暴学树莓派》
6)完整开源资料下载地址(电脑端打开):
四、实验前提
1、在进行本文步骤前,请先阅读以下章节:
1)《简单粗暴学树莓派》的“第一章至第二章”章节。
2、在进行本文步骤前,请先实现以下章节:
1)《简单粗暴学树莓派》的《香瓜树莓派RP2350之搭建开发环境(windows)》
2)《简单粗暴学树莓派》的《香瓜树莓派RP2350之新建工程》
五、硬件原理
1、硬件连接


实际只接了4根线,3.3V、GND、CLK、DIO
注意: 给pico2供电时接VSYS,是因为pico2会再经过稳压到3.3v供电给pico2目标板的rp2350。而香瓜使用的板子仿真接口是直接供电给rp2350的,所以需要直连3.3v。
2、原理图

RP2350A芯片有设计bug,如果不外接下拉电阻,在低功耗时会漏电。所以我们在没有用到的引脚外部加了下拉电阻。
六、实验步骤
1、在VS CODE工程文件夹下,添加驱动GUA_DeepSleep.c(VS CODE会自动加载)
| //********************************************************************** //name: GUA_DeepSleep.c //introduce: dormant模式的驱动(sleep模式是关电并需要clock唤醒,dormant模式则是切换晶振通过外部事件唤醒) //author: opengua //email: 897503845@qq.com //QQ group: 香瓜嵌入式之树莓派群(512598061) //shop: opengua.taobao.com //changetime: 2025.03.13 //********************************************************************** #include "hardware/powman.h" #include "hardware/clocks.h" #include "hardware/pll.h" #include "pico/sync.h" #include "hardware/regs/rosc.h" #include "hardware/structs/rosc.h" #include "hardware/regs/xosc.h" #include "hardware/xosc.h" #include "pico/runtime_init.h" #include <stdio.h> #include "pico/stdlib.h" #include "GUA_DeepSleep.h" #include "main.h" /*********************宏定义************************/ #define GUA_KEY_PIN 4 #define GUA_SC89890H_QON_PIN 5 #define GUA_HUSB363_PIN 9 #define GUA_SC89890H_INT_PIN 10 #define GUA_ALARMB_PIN 11 #define GUA_IIC_SDA_PIN 12 #define GUA_IIC_SCL_PIN 13 #define GUA_PCF8563_PIN 14 #define GUA_DCDC_PIN 19 #define LED1_BAT0_PIN 22 #define LED2_BAT25_PIN 23 #define LED3_BAT75_PIN 24 #define LED4_BAT100_PIN 25 /*********************内部函数************************/ static bool GUA_Dormant_Source_Valid(stGUA_Dormant_Source dormant_source); static void GUA_Rosc_Clear_Bad_Write(void); static bool GUA_Rosc_Write_Okay(void); static void GUA_Rosc_Write(io_rw_32 *addr, uint32_t value); static void GUA_Rosc_Disable(void); static void GUA_Rosc_Enable(void); static void GUA_Rosc_Set_Dormant(void); static void GUA_Sleep_Run_From_Dormant_Source(stGUA_Dormant_Source dormant_source); static void GUA_Sleep_PowerUp(void); static void GUA_Disable_Irq(void); static void GUA_DeepSleep_GPIO_Init(void); //********************************************************************** //name: GUA_Dormant_Source_Valid //introduce: 确认要切换的晶振频率是否合规 //parameter: dormant_source:要切换的时钟频率 //return: true or false //author: opengua //email: 897503845@qq.com //QQ group: 香瓜嵌入式之树莓派群(512598061) //shop: opengua.taobao.com //changetime: 2025.03.26 //********************************************************************** static bool GUA_Dormant_Source_Valid(stGUA_Dormant_Source dormant_source) { switch(dormant_source) { //12MHZ case DORMANT_SOURCE_XOSC: return true; //6.6MHZ case DORMANT_SOURCE_ROSC: return true; //32kHZ case DORMANT_SOURCE_LPOSC: return true; //其他 default: return false; } } //********************************************************************** //name: GUA_Rosc_Clear_Bad_Write //introduce: 清除与重置寄存器坏写状态 //parameter: none //return: none //author: opengua //email: 897503845@qq.com //QQ group: 香瓜嵌入式之树莓派群(512598061) //shop: opengua.taobao.com //changetime: 2025.03.26 //********************************************************************** static void GUA_Rosc_Clear_Bad_Write(void) { hw_clear_bits(&rosc_hw->status, ROSC_STATUS_BADWRITE_BITS); } //********************************************************************** //name: GUA_Rosc_Write_Okay //introduce: 判断rosc写入正常 //parameter: none //return: true or false //author: opengua //email: 897503845@qq.com //QQ group: 香瓜嵌入式之树莓派群(512598061) //shop: opengua.taobao.com //changetime: 2025.03.26 //********************************************************************** static bool GUA_Rosc_Write_Okay(void) { return !(rosc_hw->status & ROSC_STATUS_BADWRITE_BITS); } //********************************************************************** //name: GUA_Rosc_Write //introduce: 写入寄存器数值 //parameter: addr:寄存器地址 // data:要写入寄存器的数值 //return: none //author: opengua //email: 897503845@qq.com //QQ group: 香瓜嵌入式之树莓派群(512598061) //shop: opengua.taobao.com //changetime: 2025.03.26 //********************************************************************** static void GUA_Rosc_Write(io_rw_32 *addr, uint32_t value) { GUA_Rosc_Clear_Bad_Write(); assert(GUA_Rosc_Write_Okay()); *addr = value; assert(GUA_Rosc_Write_Okay()); }; //********************************************************************** //name: GUA_Rosc_Disable //introduce: 关闭rosc时钟 //parameter: none //return: none //author: opengua //email: 897503845@qq.com //QQ group: 香瓜嵌入式之树莓派群(512598061) //shop: opengua.taobao.com //changetime: 2025.03.26 //********************************************************************** static void GUA_Rosc_Disable(void) { uint32_t tmp = rosc_hw->ctrl; tmp &= (~ROSC_CTRL_ENABLE_BITS); tmp |= (ROSC_CTRL_ENABLE_VALUE_DISABLE << ROSC_CTRL_ENABLE_LSB); GUA_Rosc_Write(&rosc_hw->ctrl, tmp); // Wait for stable to go away while(rosc_hw->status & ROSC_STATUS_STABLE_BITS); } //********************************************************************** //name: GUA_Rosc_Enable //introduce: 开启rosc时钟 //parameter: none //return: none //author: opengua //email: 897503845@qq.com //QQ group: 香瓜嵌入式之树莓派群(512598061) //shop: opengua.taobao.com //changetime: 2025.03.26 //********************************************************************** static void GUA_Rosc_Enable(void) { //Re-enable the rosc GUA_Rosc_Write(&rosc_hw->ctrl, ROSC_CTRL_ENABLE_BITS); //Wait for it to become stable once restarted while (!(rosc_hw->status & ROSC_STATUS_STABLE_BITS)); } //********************************************************************** //name: GUA_Rosc_Set_Dormant //introduce: 进入rosc晶振下的dormant模式 //parameter: none //return: none //author: opengua //email: 897503845@qq.com //QQ group: 香瓜嵌入式之树莓派群(512598061) //shop: opengua.taobao.com //changetime: 2025.03.26 //********************************************************************** static void GUA_Rosc_Set_Dormant(void) { //WARNING: This stops the rosc until woken up by an irq GUA_Rosc_Write(&rosc_hw->dormant, ROSC_DORMANT_VALUE_DORMANT); //Wait for it to become stable once woken up while(!(rosc_hw->status & ROSC_STATUS_STABLE_BITS)); } //********************************************************************** //name: GUA_Sleep_Run_From_Dormant_Source //introduce: 配置时钟源并进入dormant模式 //parameter: dormant_source:时钟源 //return: none //author: opengua //email: 897503845@qq.com //QQ group: 香瓜嵌入式之树莓派群(512598061) //shop: opengua.taobao.com //changetime: 2025.03.26 //********************************************************************** static void GUA_Sleep_Run_From_Dormant_Source(stGUA_Dormant_Source dormant_source) { //判断晶振参数是否正确 assert(GUA_Dormant_Source_Valid(dormant_source)); uint32_t src_hz; uint32_t clk_ref_src; switch(dormant_source) { case DORMANT_SOURCE_XOSC: src_hz = XOSC_HZ; clk_ref_src = CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC; break; case DORMANT_SOURCE_ROSC: src_hz = 6500 * KHZ; // todo clk_ref_src = CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH; break; case DORMANT_SOURCE_LPOSC: src_hz = 32 * KHZ; clk_ref_src = CLOCKS_CLK_REF_CTRL_SRC_VALUE_LPOSC_CLKSRC; break; default: hard_assert(false); } //CLK_REF = XOSC or ROSC or LCOSC clock_configure(clk_ref, clk_ref_src, 0, //No aux mux src_hz, src_hz); //CLK SYS = CLK_REF clock_configure(clk_sys, CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF, 0, //Using glitchless mux src_hz, src_hz); //关闭外设时钟 clock_stop(clk_adc); clock_stop(clk_usb); //关闭high-speed serial transmit (HSTX) clock_stop(clk_hstx); // CLK PERI = clk_sys. 外设时钟,使用系统时钟作为参考 clock_configure(clk_peri, 0, CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS, src_hz, src_hz); //禁用PLL(相位锁定环) pll_deinit(pll_sys); pll_deinit(pll_usb);
//关闭没用的晶振 //XOSC if(dormant_source == DORMANT_SOURCE_XOSC) { GUA_Rosc_Disable(); } //ROSC or LPOSC else { xosc_disable(); } /* //进入晶振对应的dormant //XOSC if(dormant_source == DORMANT_SOURCE_XOSC) { xosc_dormant(); } //ROSC or LPOSC else { GUA_Rosc_Set_Dormant(); } */ //Reconfigure uart with new clocks //setup_default_uart(); } //********************************************************************** //name: GUA_Sleep_PowerUp //introduce: sleep mode和dormant mode通用的唤醒函数,恢复系统时钟和硬件的配置 //parameter: none //return: none //author: opengua //email: 897503845@qq.com //QQ group: 香瓜嵌入式之树莓派群(512598061) //shop: opengua.taobao.com //changetime: 2025.03.26 //********************************************************************** static void GUA_Sleep_PowerUp(void) { //启用ROSC GUA_Rosc_Enable(); //重置睡眠使能寄存器,目的是外设和硬件能正常使用 clocks_hw->sleep_en0 |= ~(0u); clocks_hw->sleep_en1 |= ~(0u); //初始化时钟 clocks_init(); //make powerman use xosc again uint64_t restore_ms = powman_timer_get_ms(); powman_timer_set_1khz_tick_source_xosc(); powman_timer_set_ms(restore_ms); //重新初始化串口通信 //setup_default_uart();
//关中断 GUA_Disable_Irq(); } //********************************************************************** //name: GUA_Disable_Irq //introduce: 关闭中断 //parameter: enabled:true or false //return: none //author: opengua //email: 897503845@qq.com //QQ group: 香瓜嵌入式之树莓派群(512598061) //shop: opengua.taobao.com //changetime: 2025.03.13 //********************************************************************** extern void GUA_gpio_callback(uint gpio, uint32_t events); //引用其他文件的中断处理函数 static void GUA_Disable_Irq(void) { //4 下降沿中断触发 暂时去除 gpio_set_irq_enabled_with_callback(GUA_KEY_PIN, GPIO_IRQ_EDGE_FALL, false, &GUA_gpio_callback); //9 下降沿中断触发 gpio_set_irq_enabled_with_callback(GUA_HUSB363_PIN, GPIO_IRQ_EDGE_FALL, false, &GUA_gpio_callback); //10 下降沿中断触发 gpio_set_irq_enabled_with_callback(GUA_SC89890H_INT_PIN, GPIO_IRQ_EDGE_FALL, false, &GUA_gpio_callback); //14 下降沿中断触发 RTC需要一直开着 //gpio_set_irq_enabled_with_callback(GUA_PCF8563_PIN, GPIO_IRQ_EDGE_FALL, enabled, &GUA_gpio_callback); } //********************************************************************** //name: GUA_DeepSleep_GPIO_Init //introduce: 设置唤醒中断引脚 //parameter: none //return: none //author: opengua //email: 897503845@qq.com //QQ group: 香瓜嵌入式之树莓派群(512598061) //shop: opengua.taobao.com //changetime: 2025.03.13 //********************************************************************** static void GUA_DeepSleep_GPIO_Init(void) { for(uint8_t io = 0; io < 30; io++) { //4 输入上拉 下降沿中断 if(io == GUA_KEY_PIN) { gpio_set_dir(io, GPIO_IN); gpio_set_function(io, GPIO_FUNC_SIO); gpio_pull_up(io);
//下降沿中断触发 gpio_set_irq_enabled_with_callback(io, GPIO_IRQ_EDGE_FALL, true, &GUA_gpio_callback); } //5 输入上拉 else if(io == GUA_SC89890H_QON_PIN) { gpio_set_dir(io, GPIO_IN); gpio_set_function(io, GPIO_FUNC_SIO); gpio_pull_up(io); } //9 输入上拉 下降沿中断 else if(io == GUA_HUSB363_PIN) { gpio_set_dir(io, GPIO_IN); gpio_set_function(io, GPIO_FUNC_SIO); gpio_pull_up(io);
//下降沿中断触发 gpio_set_irq_enabled_with_callback(io, GPIO_IRQ_EDGE_FALL, true, &GUA_gpio_callback); } //10 输入上拉 下降沿中断 else if(io == GUA_SC89890H_INT_PIN) { gpio_set_dir(io, GPIO_IN); gpio_set_function(io, GPIO_FUNC_SIO); gpio_pull_up(io);
//下降沿中断触发 gpio_set_irq_enabled_with_callback(io, GPIO_IRQ_EDGE_FALL, true, &GUA_gpio_callback); } //11 输入下拉,不能设置为输出,避免烧坏电量计 else if(io == GUA_ALARMB_PIN) { gpio_set_dir(io, GPIO_IN); gpio_set_function(io, GPIO_FUNC_SIO); gpio_pull_down(io); } //12 输入上拉 else if(io == GUA_IIC_SDA_PIN) { gpio_set_dir(io, GPIO_IN); gpio_set_function(io, GPIO_FUNC_SIO); gpio_pull_up(io); } //13 悬浮输入 else if (io == GUA_IIC_SCL_PIN) { gpio_set_dir(io, GPIO_IN); gpio_set_function(io, GPIO_FUNC_SIO); gpio_disable_pulls(io); } //14 输入上拉 下降沿中断 else if(io == GUA_PCF8563_PIN) { gpio_set_dir(io, GPIO_IN); gpio_set_function(io, GPIO_FUNC_SIO); gpio_pull_up(io);
//下降沿中断触发 gpio_set_irq_enabled_with_callback(io, GPIO_IRQ_EDGE_FALL, true, &GUA_gpio_callback); } //LED1~4 22~25 悬浮输出 else if((io >= LED1_BAT0_PIN) && (io <= LED4_BAT100_PIN)) { gpio_init(io); gpio_set_dir(io, GPIO_OUT); gpio_disable_pulls(io); } //19 悬浮输入,DCDC会被拉低 else if(io == GUA_DCDC_PIN) { gpio_set_dir(io, GPIO_IN); gpio_set_function(io, GPIO_FUNC_SIO); gpio_disable_pulls(io); } //悬浮输入 else if(io == 3 || io == 20 || io == 21) { gpio_set_dir(io, GPIO_IN); gpio_set_function(io, GPIO_FUNC_SIO); gpio_disable_pulls(io); } //下拉输入 else if(io == 1 || io == 2 || io == 6 || io == 7 || io == 12 ||io == 13 || io == 15 || io ==26 || io == 27 || io == 28 || io == 29 ) { gpio_set_dir(io, GPIO_IN); gpio_set_function(io, GPIO_FUNC_SIO); gpio_pull_down(io); } //其他悬浮输出(0、8、17、18) else { gpio_set_dir(io, GPIO_OUT); gpio_set_function(io, GPIO_FUNC_SIO); gpio_disable_pulls(io); } } } //********************************************************************** //name: GUA_DeepSleep //introduce: 休眠函数 //parameter: none //return: none //author: opengua //email: 897503845@qq.com //QQ group: 香瓜嵌入式之树莓派群(512598061) //shop: opengua.taobao.com //changetime: 2025.03.26 //********************************************************************** //add hardware_powman and hardware_regs (lib) in CMakeLists.txt void GUA_DeepSleep(void) { //等待串口TX缓冲区清空 uart_default_tx_wait_blocking(); //设置睡眠时钟并进入睡眠模式(Dormant只可以设置XOSC和ROSC,不可以设置为LP0SC,否则KEY会电平波动导致进中断) //必须在io中断之前,否则会导致其他io中断,但万用表看不出来波动,可能是有滤波导致电平波动小 GUA_Sleep_Run_From_Dormant_Source(DORMANT_SOURCE_ROSC); //IO配置 GUA_DeepSleep_GPIO_Init(); //确保系统在中断或定时器到期之前不会唤醒 while(gnGUA_Function == FUNC_GUA_SHUTDOWN_EVENT) { __wfi(); } //唤醒后重新启用时钟源和硬件 GUA_Sleep_PowerUp(); } |
2、在VS CODE工程文件夹下,添加驱动GUA_DeepSleep.h(VS CODE会自动加载)
| //********************************************************************** //name: GUA_DeepSleep.h //introduce: 深度睡眠驱动 //author: opengua //email: 897503845@qq.com //QQ group: 香瓜嵌入式之树莓派群(512598061) //shop: opengua.taobao.com //changetime: 2025.03.13 //********************************************************************** #ifndef _GUA_DEEP_SLEEP_H_ #define _GUA_DEEP_SLEEP_H_ /*********************外部变量************************/ typedef enum { DORMANT_SOURCE_NONE, DORMANT_SOURCE_XOSC, DORMANT_SOURCE_ROSC, DORMANT_SOURCE_LPOSC, // rp2350 only } stGUA_Dormant_Source; /*********************外部函数声明************************/ extern void GUA_DeepSleep(void); #endif |
3、添加对应驱动文件名称

4、添加库

5、在应用层中调用
1)添加驱动头文件(main.c中)
| #include "GUA_DeepSleep.h" |
2)添加测试代码(main.c的main函数中)
| //低功耗模式 case FUNC_GUA_SHUTDOWN_EVENT: { //led跑马灯 //GUA_BatteryLed_OnOff(GUA_BATTERY_LED_NEWS_TICKER);
//进入睡眠模式 GUA_DeepSleep(); //初始化 GUA_Init(); break; } |
有报错注意增删减改
七、实验结果
1、工作电流(香瓜实际很多外设): 23.9mA
2、低功耗电流: 7.54mA
因此实验成功。

3747

被折叠的 条评论
为什么被折叠?



