背景:
低功耗是对 IoT 产品的最基本要求,也是一款好产品走向市场的基础,功耗评估显得尤为重要。
一、基础资源简析
ESP32 支持 Deep-sleep 低功耗模式,通过配置 RTC 外设和 ULP 协处理器的工作模式,可以满足多种应用场景下的低功耗需求。
在 Deep-sleep 模式时,所有由 APB_CLK 驱动的外设、CPU 和 RAM 将掉电,RTC_CLK 继续工作;
RTC 控制器、RTC 外设、ULP 协处理器、RTC 快速内存和 RTC 慢速内存可以不掉电,具体取决于应用程序中的唤醒源设置。
硬件资源:
RTC 外设 – 片上温度传感器、ADC、RTC GPIO 和 touchpad
ULP 协处理器 – 可在 Deep-sleep 模式下,进行简单的数据采集或作为一种唤醒源,协处理器可以访问 RTC 慢速内存和 RTC 寄存器
RTC 快速内存 – 芯片从 Deep-sleep 模式下唤醒后不会马上执行 bootloader,而是会先执行存放在 RTC 快速内存中的 esp_wake_deep_sleep() 函数
RTC 慢速内存 – 存放 ULP 协处理器和 wake stub 代码访问的数据
Deep-sleep 模式下支持的唤醒源包括:
1、定时器
2、touchpad
3、Ext(0):RTC IO 中某个指定 GPIO 满足指定电平即唤醒
4、Ext(1):RTC IO 中某些指定 GPIO 同时满足指定电平即唤醒
5、ULP 协处理器
二、示例
1、定时器唤醒:6uA 左右
调用 esp_deep_sleep_enable_timer_wakeup(sleep_time_us) 函数,设置 Deep-sleep 时间
调用 esp_deep_sleep_start() 函数,进入 Deep-sleep 模式
此时需要周期性唤醒 ESP32,不能充分利用 ESP32 的低功耗性能,但可以进行复杂的传感器数据采集
/*
Simple Deep Sleep with Timer Wake Up
ESP32 offers a deep sleep mode for effective power
saving as power is an important factor for IoT
applications. In this mode CPUs, most of the RAM,
and all the digital peripherals which are clocked
from APB_CLK are powered off. The only parts of
the chip which can still be powered on are:
RTC controller, RTC peripherals ,and RTC memories
This code displays the most basic deep sleep with
a timer to wake it up and how to store data in
RTC memory to use it over reboots
This code is under Public Domain License.
Author:
Pranav Cherukupalli <cherukupallip@gmail.com>
*/
define uS_TO_S_FACTOR 1000000 / Conversion factor for micro seconds to seconds /
define TIME_TO_SLEEP 5 / Time ESP32 will go to sleep (in seconds) /
RTC_DATA_ATTR int bootCount = 0;
/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
esp_deep_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_deep_sleep_get_wakeup_cause();
switch(wakeup_reason)
{
case 1 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
case 2 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
case 3 : Serial.println("Wakeup caused by timer"); break;
case 4 : Serial.println("Wakeup caused by touchpad"); break;
case 5 : Serial.println("Wakeup caused by ULP program"); break;
default : Serial.println("Wakeup was not caused by deep sleep"); break;
}
}
void setup(){
Serial.begin(115200);
delay(1000); //Take some time to open up the Serial Monitor
//Increment boot number and print it every reboot
++bootCount;
Serial.println("Boot number: " + String(bootCount));
//Print the wakeup reason for ESP32
print_wakeup_reason();
/*
First we configure the wake up source
We set our ESP32 to wake up every 5 seconds
*/
esp_deep_sleep_enable_timer_wakeup(TIME_TO_SLEEP uS_TO_S_FACTOR2);
Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +
" Seconds");
/*
Next we decide what all peripherals to shut down/keep on
By default, ESP32 will automatically power down the peripherals
not needed by the wakeup source, but if you want to be a poweruser
this is for you. Read in detail at the API docs
http://esp-idf.readthedocs.io/en/latest/api-reference/system/deep_sleep.html
Left the line commented as an example of how to configure peripherals.
The line below turns off all RTC peripherals in deep sleep.
*/
//esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
//Serial.println("Configured all RTC Peripherals to be powered down in sleep");
/*
Now that we have setup a wake cause and if needed setup the
peripherals state in deep sleep, we can now start going to
deep sleep.
In the case that no wake up sources were provided but deep
sleep was started, it will sleep forever unless hardware
reset occurs.
*/
Serial.println("Going to sleep now");
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void loop(){
//This is not going to be called
}
2、Touchpad:36uA 左右
设置作为唤醒源的 touchpad
调用 esp_deep_sleep_enable_touchpad_wakeup() 函数使能 touchpad 唤醒,然后调用 esp_deep_sleep_start() 函数进入 Deep-sleep 模式
/*
Deep Sleep with Touch Wake Up
This code displays how to use deep sleep with
a touch as a wake up source and how to store data in
RTC memory to use it over reboots
This code is under Public Domain License.
Author:
Pranav Cherukupalli <cherukupallip@gmail.com>
*/
define Threshold 40 / Greater the value, more the sensitivity /
RTC_DATA_ATTR int bootCount = 0;
touch_pad_t touchPin;
/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
esp_deep_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_deep_sleep_get_wakeup_cause();
switch(wakeup_reason)
{
case 1 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
case 2 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
case 3 : Serial.println("Wakeup caused by timer"); break;
case 4 : Serial.println("Wakeup caused by touchpad"); break;
case 5 : Serial.println("Wakeup caused by ULP program"); break;
default : Serial.println("Wakeup was not caused by deep sleep"); break;
}
}
/*
Method to print the touchpad by which ESP32
has been awaken from sleep
*/
void print_wakeup_touchpad(){
touch_pad_t pin;
touchPin = esp_deep_sleep_get_touchpad_wakeup_status();
switch(touchPin)
{
case 0 : Serial.println("Touch detected on GPIO 4"); break;
case 1 : Serial.println("Touch detected on GPIO 0"); break;
case 2 : Serial.println("Touch detected on GPIO 2"); break;
case 3 : Serial.println("Touch detected on GPIO 15"); break;
case 4 : Serial.println("Touch detected on GPIO 13"); break;
case 5 : Serial.println("Touch detected on GPIO 12"); break;
case 6 : Serial.println("Touch detected on GPIO 14"); break;
case 7 : Serial.println("Touch detected on GPIO 27"); break;
case 8 : Serial.println("Touch detected on GPIO 33"); break;
case 9 : Serial.println("Touch detected on GPIO 32"); break;
default : Serial.println("Wakeup not by touchpad"); break;
}
}
void callback(){
//placeholder callback function
}
void setup(){
Serial.begin(115200);
delay(1000); //Take some time to open up the Serial Monitor
//Increment boot number and print it every reboot
++bootCount;
Serial.println("Boot number: " + String(bootCount));
//Print the wakeup reason for ESP32 and touchpad too
print_wakeup_reason();
print_wakeup_touchpad();
//Setup interrupt on Touch Pad 3 (GPIO15)
touchAttachInterrupt(T3, callback, Threshold);
//Configure Touchpad as wakeup source
esp_deep_sleep_enable_touchpad_wakeup();
//Go to sleep now
Serial.println("Going to sleep now");
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void loop(){
//This will never be reached
}
3、GPIO 唤醒:6uA 左右
调用 rtc_gpio_pulldown_en(MY_RTC_WAKEUP_IO) 函数或 rtc_gpio_pullup_en(MY_RTC_WAKEUP_IO) 函数,设置内部下拉或上拉类型
调用 esp_deep_sleep_enable_ext0_wakeup(MY_RTC_WAKEUP_IO, WAKEUP_IO_LEVEL) 函数或 esp_deep_sleep_enable_ext1_wakeup(WAKEUP_PIN_MASK, WAKEUP_TYPE) 函数,设置从 Deep-sleep 模式下唤醒的 RTC GPIO 电压条件
调用 esp_deep_sleep_start() 函数进入 Deep-sleep 模式
/*
Deep Sleep with External Wake Up
This code displays how to use deep sleep with
an external trigger as a wake up source and how
to store data in RTC memory to use it over reboots
This code is under Public Domain License.
Hardware Connections
Push Button to GPIO 33 pulled down with a 10K Ohm
resistor
NOTE:
Only RTC IO can be used as a source for external wake
source. They are pins: 0,2,4,12-15,25-27,32-39.
Author:
Pranav Cherukupalli <cherukupallip@gmail.com>
*/
define BUTTON_PIN_BITMASK 0x200000000 // 2^33 in hex
RTC_DATA_ATTR int bootCount = 0;
/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
switch(wakeup_reason)
{
case 1 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
case 2 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
case 3 : Serial.println("Wakeup caused by timer"); break;
case 4 : Serial.println("Wakeup caused by touchpad"); break;
case 5 : Serial.println("Wakeup caused by ULP program"); break;
default : Serial.println("Wakeup was not caused by deep sleep"); break;
}
}
void setup(){
Serial.begin(115200);
delay(1000); //Take some time to open up the Serial Monitor
//Increment boot number and print it every reboot
++bootCount;
Serial.println("Boot number: " + String(bootCount));
Serial.printf("Boot number: %d ", bootCount);
//Print the wakeup reason for ESP32
print_wakeup_reason();
/*
First we configure the wake up source
We set our ESP32 to wake up for an external trigger.
There are two types for ESP32, ext0 and ext1 .
ext0 uses RTC_IO to wakeup thus requires RTC peripherals
to be on while ext1 uses RTC Controller so doesnt need
peripherals to be powered on.
Note that using internal pullups/pulldowns also requires
RTC peripherals to be turned on.
*/
esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,1); //1 = High, 0 = Low
//If you were to use ext1, you would use it like
//esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);
//Go to sleep now
Serial.println("Going to sleep now");
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void loop(){
//This is not going to be called
}
4、ULP 协处理器
用户根据 ULP 指令集,自行编写需要 ULP 协处理器在 Deep-sleep 模式下执行的汇编代码,完整流程如下:
芯片 boot 启动后,从 RTC_SLOW_MEMORY 读取芯片在 Deep-sleep 模式期间 ULP 协处理器采集的数据,并上传数据
调用 ulp_process_macros_and_load() 函数,将汇编程序代码拷贝至 RTC_SLOW_MEMORY
调用 ulp_run(ADDRESS) 函数启动 ULP 协处理器,执行 RTC_SLOW_MEMORY 中的代码
调用 esp_deep_sleep_start() 函数,进入 Deep-sleep 模式
为了便于用户使用 ULP 协处理器进行数据采集与存储,IoT Solution 中增加了 ulp_monitor 模块,可直接调用 C 函数运行协处理器
ulp_monitor 模块的使用流程如下:
芯片 boot 启动后,从 RTC_SLOW_MEMORY 读取 ULP 协处理器在芯片 Deep-sleep 模式期间采集的数据,并上传数据
调用 ulp_monitor_init(ULP_PROGRAM_ADDR, ULP_DATA_ADDR) 函数,设置 ULP 协处理器的程序运行地址与数据保存地址
调用 ulp_add_adc_monitor 函数或 ulp_add_temprature_monitor 函数,添加 ULP 协处理器采集的数据类型和唤醒条件(可同时添加)
调用 ulp_monitor_start 函数设置测量频率,并启动 ULP 协处理器
调用 esp_deep_sleep_start() 函数,进入 Deep-sleep 模式。目前,ULP 协处理只支持片上温度传感器和 ADC 数据的采集
该方式可以在低功耗情况下频繁地采集数据,从而降低对传感器的要求
从《天道》的角度谈谈产品规划
原创2023-02-24 21:05·产品人卫朋
今天主要借用《天道》中丁元英的商业案例来谈谈产品规划这个话题。
《天道》这部被众人追捧的影视剧来源于豆豆的成名作《遥远的救世主》。
如果没有全局做过产品或者市场的规划,而且是初次接触这部剧。
你就会惊叹于主人公的组局、布局,以及成局的能力。
从互联网拥簇的评论声中,也可见一斑。
剧中的丁元英甚至都有一种被神化的趋势。
而随着个人知识和阅历的增加,再加上每年也都要做产品规划。
也逐渐对这部剧或者这本书有了一些新的认识。
究其本质,这是一种战略性的思维,也是一种规划的能力。
更是一种市场与内部能力的匹配过程。
笔者之前也分享过这块的内容,也看到了一些质疑。
怎么能用虚拟的案例做讲解呢?
其实这么做的原因主要有两点考虑:
首先,这部剧中的商业案例的整体逻辑是自洽的,而且也符合当时的商业环境。
其次,整部剧将整个商业案例完整地呈现了出来,也包括其中很多的决策细节。
这就要比分析现实案例直观得多,也更加有指导意义。
再回到产品规划这个话题上来。
产品规划从本质上来说是一种推演能力,也就是根据第一性原则推演产品从0到1、从1到100的一个过程。
如果说一款产品是一个点的话,那产品规划便是通过构造一种系统能力以达成企业最终的商业目的。
第一性原理是埃隆·马斯克非常推崇的一种思维模型。
通常来说,企业愿景对应的便是企业的第一性原则。
围绕第一性原则可以激发资源优势、制定细分市场目标,最终实现企业目标。
下面以影视剧中丁元英操盘的格律诗音响项目为例,谈谈产品规划。
格律诗音响公司的企业愿景是实现王庙村生产力和市场的对接,最终实现农户脱贫。
这是企业的愿景,同时也是丁元英承诺要给红颜知己芮小丹创造的神话。
启动一个项目或产品,资源和人力配置是你首先要考虑的。
企业在不同的发展周期,对人的要求是有很大差异的。
丁元英在分析完这些人的本质之后,并没有把自己的全套计划完整地告诉原始这些人。
而是通过市场的变化来淘汰掉一部分人。
因为这部分人现在不淘汰掉,在以后的市场变化中,可能会给公司带来毁灭性的灾难。
下面就先梳理一下其中的关键人物:
丁元英作为格律诗音响项目的唯一操盘手,全局规划了整个项目。
他的优势是自己在欧洲的人脉和战略规划能力,以及在欧阳雪等人心中的影响力。
同时,作为发烧级音乐玩家,他对音箱的独特见解也为他们打造差异化的产品起到了关键助力作用。
差异化的意思是相比于竞争对手,你的独特优势或者护城河,没有这个前提,整个策略也就无从谈起,这为他们赢得了时间上的先机。
在音响这个市场,竞品已经很成功了,而且他们提供的价值点已经被用户接受。
如果按照他们的价值点去做产品,你就永远只能跟在他们身后。
这时候就需要找一个跟他们不一样的价值点,做差异化。
欧阳雪这个人呢,做事很踏实,很讲义气,不贪心。优势是人脉、资金和社会地位。
这个人的价值在于她对格律诗的绝对控股,这样就可以确保关键决策权的归属。
由于每个人的认知水平的限制,很多时候不同个体看到的终局是有极大差异的,这个时候你就需要考虑如何增加成事的确定性。
如果开公司的话,股权的分配问题是你优先要考虑的。
不赚钱的时候,大家还都能力出一孔。一旦公司有起色,每个人就开始有自己的诉求,不确定性也就随之而来。
肖亚文见过世面,知道公司怎么运行,知道商务谈判和商务合作的事情,是很精明的职场人物。
而冯世杰和叶晓明想成就一番事业,但没有机会,能够脚踏实地的做事情,但眼光欠缺。刘冰是小人物,唯利是图,关键时刻不能顶上,迟早会被淘汰。
叶晓明,冯世杰,刘冰这三个人的优势就是懂音乐,会组装,可以作为高级技术工。
同时,这三人和王庙村农民有一定的关系,可以作为连接的纽带,核心竞争力是技术和人脉。
乐圣公司的掌舵人是林雨峰(竞争对手),但太过刚硬,只知道进攻,不懂防守,考虑问题存在漏洞。
这就有点类似竞争分析了,通过分析竞争对手的漏洞,找到破局点,制定商业竞争策略。
接下来就需要统一思想了:
想要以小博大,达成乐圣跟王庙村合作的目的,就必须把优势发挥到最大效果。
这才有几次股东开会,召集农民兄弟一起开会等,就是为了统一思想。
市场的生存竞争非常残酷,胜负往往就在毫厘之间,微弱的优势都可能成为关键一环,你比他多一口气,你就是赢家。
最后,丁元英就把这些人的优势资源整合起来,按照需要组建公司,精心规划。
详细案例分析可以参阅笔者之前的文章。
卫朋
人人都是产品经理受邀专栏作家,CSDN 嵌入式领域新星创作者、资深技术博主。2020 年 8 月开始写产品相关内容,截至目前,人人都是产品经理单渠道阅读 56 万+,鸟哥笔记单渠道阅读200 万+,CSDN 单渠道阅读 210 万+,51CTO单渠道阅读 180 万+。
卫朋入围2021/2022年人人都是产品经理平台年度作者,光环国际学习社区首批原创者、知识合作伙伴,商业新知 2021 年度产品十佳创作者,腾讯调研云2022年达人榜第三名。
文章被人人都是产品经理、CSDN、华为云、运营派、产品壹佰、鸟哥笔记、光环国际、商业新知、腾讯调研云等头部垂直类媒体转载。文章见仁见智,各位看官可策略性选择对于自己有用的部分。