【RP2350】香瓜树莓派RP2350之低功耗

本文最后修改时间: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)完整开源资料下载地址(电脑端打开):

opengua.taobao.com

四、实验前提

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

因此实验成功。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

甜甜的大香瓜

谢谢你的支持^_^

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值