不过掉电状态的时候,RAM中的数据都会都是,所以掉电状态不能进行调试,需要直接将固件烧录到代码中。
经过一番尝试,在RGB-LED灯的实例基础上,结合掉电状态进行测试。
预期如下:
1. 板子启动后,RGB-LED呼吸灯自动启动
2. 按PBUTN按键 16秒以后,RGB-LED呼吸灯停止
3. 一会后,再按PBUTN或者WBUTN按键0.5秒以上,则RGB-LED呼吸灯恢复。
实际参考的两个例子如下:
1. samples/RGB-LED
2. samples/drivers/butn
合并后的代码如下:
/* * Copyright (c) 2021 HPMicro * * SPDX-License-Identifier: BSD-3-Clause * */ #include <stdio.h> #include "board.h" #include "hpm_debug_console.h" #include "hpm_clock_drv.h" #include "hpm_pwm_drv.h" #include "hpm_butn_drv.h" #include "hpm_bpor_drv.h" #define TEST_BPOR HPM_BPOR #define TEST_BPOR_POWER_ON_CAUSE bpor_power_on_cause_wbutn #ifdef BOARD_RED_PWM #define RED_PWM_IRQ BOARD_RED_PWM_IRQ #define RED_PWM BOARD_RED_PWM #define RED_PWM_CMP BOARD_RED_PWM_CMP #define RED_PWM_CMP_INITIAL_ZERO BOARD_RED_PWM_CMP_INITIAL_ZERO #define RED_PWM_OUT BOARD_RED_PWM_OUT #define RED_PWM_CLOCK_NAME BOARD_RED_PWM_CLOCK_NAME #else #error BOARD_RED_PWM needs to be defined #endif #ifdef BOARD_GREEN_PWM #define GREEN_PWM_IRQ BOARD_GREEN_PWM_IRQ #define GREEN_PWM BOARD_GREEN_PWM #define GREEN_PWM_CMP BOARD_GREEN_PWM_CMP #define GREEN_PWM_CMP_INITIAL_ZERO BOARD_GREEN_PWM_CMP_INITIAL_ZERO #define GREEN_PWM_OUT BOARD_GREEN_PWM_OUT #define GREEN_PWM_CLOCK_NAME BOARD_BLUE_PWM_CLOCK_NAME #else #error BOARD_GREEN_PWM needs to be defined #endif #ifdef BOARD_BLUE_PWM #define BLUE_PWM_IRQ BOARD_BLUE_PWM_IRQ #define BLUE_PWM BOARD_BLUE_PWM #define BLUE_PWM_CMP BOARD_BLUE_PWM_CMP #define BLUE_PWM_CMP_INITIAL_ZERO BOARD_BLUE_PWM_CMP_INITIAL_ZERO #define BLUE_PWM_OUT BOARD_BLUE_PWM_OUT #define BLUE_PWM_CLOCK_NAME BOARD_BLUE_PWM_CLOCK_NAME #else #error BOARD_BLUE_PWM needs to be defined #endif #define PWM_PERIOD_IN_MS (1U) #define PWM_DUTY_STEP_COUNT (1000U) typedef struct { PWM_Type *pwm; uint32_t reload; uint32_t step; bool pwm_cmp_initial_zero; uint8_t pwm_irq; uint8_t pwm_cmp; uint8_t pwm_ch; } led_pwm_t; typedef enum { red = BOARD_RGB_RED, green = BOARD_RGB_GREEN, blue = BOARD_RGB_BLUE } led_index_t; led_pwm_t leds[3]; uint32_t reload; volatile bool do_update; volatile led_index_t current; void pwm_isr(void) { pwm_clear_status(leds[current].pwm, PWM_IRQ_HALF_RELOAD); do_update = true; } SDK_DECLARE_EXT_ISR_M(RED_PWM_IRQ, pwm_isr) #if (GREEN_PWM_IRQ != RED_PWM_IRQ) SDK_DECLARE_EXT_ISR_M(GREEN_PWM_IRQ, pwm_isr) #endif #if (BLUE_PWM_IRQ != RED_PWM_IRQ) && (GREEN_PWM_IRQ != BLUE_PWM_IRQ) SDK_DECLARE_EXT_ISR_M(BLUE_PWM_IRQ, pwm_isr) #endif void config_pwm(PWM_Type * ptr, uint8_t pin, uint8_t cmp_index, uint32_t reload, bool cmp_initial_zero, uint8_t hw_event_cmp, bool off_level_high) { pwm_cmp_config_t cmp_config = {0}; pwm_config_t pwm_config = {0}; pwm_stop_counter(ptr); pwm_get_default_pwm_config(ptr, &pwm_config); pwm_get_default_cmp_config(ptr, &cmp_config); pwm_config.enable_output = false; pwm_config.dead_zone_in_half_cycle = 0; pwm_config.invert_output = !(cmp_initial_zero && off_level_high); /* * reload and start counter */ pwm_set_reload(ptr, 0, reload); pwm_set_start_count(ptr, 0, 0); cmp_config.mode = pwm_cmp_mode_output_compare; cmp_config.cmp = cmp_initial_zero ? 0 : reload + 1; cmp_config.update_trigger = pwm_shadow_register_update_on_modify; /* config initial compare value which should take affect immediately */ pwm_config_cmp(ptr, cmp_index, &cmp_config); /* update trigger type so that compare value will be updated on hardware event (RELOAD) */ cmp_config.update_trigger = pwm_shadow_register_update_on_hw_event; /* * config pwm as output driven by cmp */ if (status_success != pwm_setup_waveform(ptr, pin, &pwm_config, cmp_index, &cmp_config, 1)) { printf("failed to setup waveform\n"); while(1); } /* * config hw event */ cmp_config.cmp = reload - 1; cmp_config.update_trigger = pwm_shadow_register_update_on_hw_event; pwm_load_cmp_shadow_on_match(ptr, hw_event_cmp, &cmp_config); } void turn_on_rgb_led(led_index_t i) { PWM_Type *pwm; uint8_t pwm_cmp; uint32_t initial; /* make sure cmp value is set to initial, before enabling output */ pwm = leds[i].pwm; pwm_cmp = leds[i].pwm_cmp; initial = leds[i].pwm_cmp_initial_zero ? 0 : (leds[i].reload + 1); pwm_update_raw_cmp_edge_aligned(pwm, pwm_cmp, initial); board_enable_output_rgb_led(i); } void turn_off_rgb_led(led_index_t i) { board_disable_output_rgb_led(i); } void update_rgb_led(void) { uint32_t duty; bool increase_step = true; PWM_Type *pwm; uint32_t reload, pwm_cmp, step; step = leds[current].step; reload = leds[current].reload; pwm = leds[current].pwm; pwm_cmp = leds[current].pwm_cmp; duty = step; pwm_enable_irq(pwm, PWM_IRQ_HALF_RELOAD); turn_on_rgb_led(current); while(!(!increase_step && (duty < 2 * step))) { if (increase_step && (duty + step > reload)) { increase_step = false; } if (increase_step) { duty += step; } else { duty -= step; } while (!do_update) { ; } pwm_update_raw_cmp_edge_aligned(pwm, pwm_cmp, duty); do_update = false; } turn_off_rgb_led(current); pwm_disable_irq(pwm, PWM_IRQ_HALF_RELOAD); } int main(void){ uint32_t freq; uint32_t hw_event_cmp; board_init(); init_butn_pins(); board_init_rgb_pwm_pins(); printf("rgb led example\n"); freq = clock_get_frequency(RED_PWM_CLOCK_NAME); leds[red].reload = freq / 1000 * PWM_PERIOD_IN_MS - 1; leds[red].pwm = RED_PWM; leds[red].pwm_ch = RED_PWM_OUT; leds[red].pwm_cmp = RED_PWM_CMP; leds[red].pwm_cmp_initial_zero = RED_PWM_CMP_INITIAL_ZERO; leds[red].pwm_irq = RED_PWM_IRQ; freq = clock_get_frequency(GREEN_PWM_CLOCK_NAME); leds[green].reload = freq / 1000 * PWM_PERIOD_IN_MS - 1; leds[green].pwm = GREEN_PWM; leds[green].pwm_ch = GREEN_PWM_OUT; leds[green].pwm_cmp = GREEN_PWM_CMP; leds[green].pwm_cmp_initial_zero = GREEN_PWM_CMP_INITIAL_ZERO; leds[green].pwm_irq = GREEN_PWM_IRQ; freq = clock_get_frequency(BLUE_PWM_CLOCK_NAME); leds[blue].reload = freq / 1000 * PWM_PERIOD_IN_MS - 1; leds[blue].pwm = BLUE_PWM; leds[blue].pwm_ch = BLUE_PWM_OUT; leds[blue].pwm_cmp = BLUE_PWM_CMP; leds[blue].pwm_cmp_initial_zero = BLUE_PWM_CMP_INITIAL_ZERO; leds[blue].pwm_irq = BLUE_PWM_IRQ; hw_event_cmp = PWM_SOC_CMP_MAX_COUNT; for (uint8_t i = 0; i < PWM_SOC_CMP_MAX_COUNT; i++) { if ((i != RED_PWM_CMP) && (i != GREEN_PWM_CMP) && (i != BLUE_PWM_CMP)) { continue; } hw_event_cmp = i; break; } if (hw_event_cmp == PWM_SOC_CMP_MAX_COUNT) { printf("Failed to find a comparator for hardware event\n"); while (1) { }; } for (uint8_t i = 0; i < ARRAY_SIZE(leds); i++) { leds[i].step = leds[i].reload / PWM_DUTY_STEP_COUNT; config_pwm(leds[i].pwm, leds[i].pwm_ch, leds[i].pwm_cmp, leds[i].reload, leds[i].pwm_cmp_initial_zero, hw_event_cmp, BOARD_LED_OFF_LEVEL); pwm_start_counter(leds[i].pwm); intc_m_enable_irq_with_priority(leds[i].pwm_irq, 1); } bpor_select_power_on_cause(TEST_BPOR, TEST_BPOR_POWER_ON_CAUSE); printf("Please press PBUTN 16s to enter power down mode, then press PBUTN or WBUTN 0.5s to wake up from power down mode.\n"); current = red; while(1) { update_rgb_led(); do_update = false; current = (current + 1) % (blue + 1); } return 0; }
复制代码上述代码中,RGB-LED的呼吸灯模式,主要就是启用了PWM来进行控制,核心设置为:
#define PWM_PERIOD_IN_MS (1U)#define PWM_DUTY_STEP_COUNT (1000U) freq = clock_get_frequency(RED_PWM_CLOCK_NAME); leds[red].reload = freq / 1000 * PWM_PERIOD_IN_MS - 1; leds[red].pwm = RED_PWM; leds[red].pwm_ch = RED_PWM_OUT; leds[red].pwm_cmp = RED_PWM_CMP; leds[red].pwm_cmp_initial_zero = RED_PWM_CMP_INITIAL_ZERO; leds[red].pwm_irq = RED_PWM_IRQ;
复制代码然后在update_rgb_led()中,启用对应的pwm输出,从而控制对应的灯。
而掉电模式,则主要由如下部分配置和处理:
#define TEST_BPOR HPM_BPOR#define TEST_BPOR_POWER_ON_CAUSE bpor_power_on_cause_wbutn bpor_select_power_on_cause(TEST_BPOR, TEST_BPOR_POWER_ON_CAUSE);
复制代码将以上代码编译烧录到开发板,然后使用数字功率计测试不同状态下的运行功耗。
1. 正常运行情况下:
此时的运行电压为4.8V,电流为220+-2ma
2. 掉电状态:
按PBUTN16秒以上,呼吸灯熄灭,进入掉电状态:
此时的运行电压为4.8V,电流为76+-1ma
3. 恢复正常运行:
按PBUTN或者WBUTN 0.5秒以上,系统恢复,呼吸灯重新开始闪烁
此时的运行电压为4.8V,电流为220+-2ma
具体的操作过程视频如下:
通过上面的测试步骤,可以清晰得到,掉电状态下,系统功耗约为正常运行状态下的1/3。
因为上述测试,仅为PWM电量RGB-LED,所以功耗比不是特别大。
如果是运行更多的外设,功耗更大的情况下,那么就会更加的明显。
后续会进一步测试,获得更多的数据。