富芮坤fr8008gp低功耗;重新开启SPI;PD5的bug;设置管脚为PMU模式;VBAT电压低于3.3V需要打开LDO的bypass模式

文章详细描述了在FR8008GP芯片上配置低功耗模式的挑战,特别是PMU的设置对屏幕初始化和睡眠模式的影响。作者遇到的问题包括管脚配置、RTC闹钟、SPI重置以及PD5管脚的特殊处理。通过调整PMU模式保持屏幕状态并在唤醒后重新初始化,实现了功耗的降低,但电流仍有波动,部分情况未达预期。最后提到了VBAT电压和LDO模式对电流的影响。
摘要由CSDN通过智能技术生成

fr8008gp低功耗还是非常难调的,自己搞了半个月才搞定,原厂和代理也是拖拖拉拉,烦不胜烦!
主要在于PMU的配置,这里先弄一个非常简单的工程,只有屏幕一个外设,代码启动后先显示一个界面,5S后直接睡眠:

..................................................
    ota_gatt_add_service();
	
	//touchpad_init_pin(true);
	gc9c01_init();
	//user_time_init();
	
	system_sleep_enable();
.................................................

其中gc9c01_init函数有如下语句:

void gc9c01_init(void)
{
	gc9c01_init_io();
	printf("gc9c01_init_io finish\r\n");
	gc9c01_init_spi();
	gc9c01_init_dma();

	LCD_RELEASE_RESET();
	co_delay_100us(1200);
	LCD_SET_RESET();
	co_delay_100us(3500);
	LCD_RELEASE_RESET();
	co_delay_100us(1200);
	.............................................
	   SPI_CMD(0x29);
   co_delay_100us (1200);
	printf("gc9c01 lcd init ok\r\n");
	//gc9c01_oled_clear(0, 0, GC9C01_LCD_Width, GC9C01_LCD_High,COLOR_RED);//XÖá±ØÐëÊÇ12µÄ±¶Êý

	gc9c01_oled_show_rwb(0, 0, GC9C01_LCD_Width, GC9C01_LCD_High,(uint8_t *)image_rbw);
	printf("oled_clear end\r\n");
//	while(1);

	co_delay_100us (5*10000);//²âÊÔ,˯ÃßÇ°ÏÈ¿´Ò»ÏÂÆÁÄ»
	LCD_DISABLE_BACKLIGHT();
	GC9C01_EnterSleep();
}

对于低功耗user_entry_before_sleep_imp和user_entry_after_sleep_imp这两个函数非常关键,前者为进入睡眠的函数,后者为推出睡眠的函数,fr8008gp要求把需要控制的管脚在进入睡眠钱配置为PMU模式(否则进入睡眠电压不可控),在退出睡眠的时候要重新初始化各个需要的模块:

__attribute__((section("ram_code"))) void user_entry_before_sleep_imp(void)
{
	//pmu_calibration_stop();
    uart_putc_noint_no_wait(UART0, 's');
    co_delay_100us(1);
    pmu_set_pin_to_PMU(GPIO_PORT_A, GPIO_BIT_1);
	
	gc9c01_uninit_io();
}

__attribute__((section("ram_code"))) void user_entry_after_sleep_imp(void)
{
    system_set_port_mux(GPIO_PORT_A, GPIO_BIT_1, PORTA1_FUNC_UART0_TXD);
    pmu_set_pin_to_CPU(GPIO_PORT_A, GPIO_PIN_1);
    uart_init(UART0, LOG_UART_BAUDRATE_CFG);
    fr_uart_enableIrq(UART0, Uart_irq_erbfi);
    uart_putc_noint_no_wait(UART0, 'w');

    NVIC_EnableIRQ(PMU_IRQn);
	pmu_calibration_start(PMU_CALI_SEL_RCLFOSC, LP_RC_CALIB_CNT);
}

既然和IO口有关系这里就涉及到屏幕的管脚的配置,屏幕管脚初始化和睡眠前的去初始化如下:

#define LCD_CS_PORT       GPIO_D
#define LCD_CS_PIN        GPIO_PIN_1

#define LCD_DC_PORT       GPIO_E
#define LCD_DC_PIN        GPIO_PIN_0

#define LCD_REST_PORT       GPIO_E
#define LCD_REST_PIN        GPIO_PIN_1

#define LCD_BACKLIGHT_PORT       GPIO_B
#define LCD_BACKLIGHT_PIN        GPIO_PIN_2

#define LCD_SPI_PORT        GPIO_D
#define LCD_SPI_PIN         (GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_0)

#define LCD_RELEASE_CS()            gpio_write_pin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_SET)
#define LCD_SET_CS()                gpio_write_pin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_CLEAR)

#define LCD_CLEAR_DC()            gpio_write_pin(LCD_DC_PORT, LCD_DC_PIN, GPIO_PIN_CLEAR)
#define LCD_SET_DC()                gpio_write_pin(LCD_DC_PORT, LCD_DC_PIN, GPIO_PIN_SET)

#define LCD_RELEASE_RESET()         pmu_set_gpio_value(LCD_REST_PORT,LCD_REST_PIN,GPIO_PIN_SET)
#define LCD_SET_RESET()             pmu_set_gpio_value(LCD_REST_PORT,LCD_REST_PIN,GPIO_PIN_CLEAR)

#define LCD_ENABLE_BACKLIGHT()         pmu_set_gpio_value((enum system_port_t)LCD_BACKLIGHT_PORT,LCD_BACKLIGHT_PIN,GPIO_PIN_SET)
#define LCD_DISABLE_BACKLIGHT()        pmu_set_gpio_value((enum system_port_t)LCD_BACKLIGHT_PORT,LCD_BACKLIGHT_PIN,GPIO_PIN_CLEAR)

static DMA_LLI_InitTypeDef Gc9c01_Link_Channel[20];
static DMA_HandleTypeDef gc9c01_DMA_Channel;
static dma_LinkParameter_t Gc9c01_LinkParameter;
static volatile bool dma_transfer_done = true;

SPI_HandleTypeDef GC9C01_SPI_Handle;

static void (*dma_trans_done_callback)(void) = NULL;

static void gc9c01_init_io(void)
{
	GPIO_InitTypeDef GPIO_Handle;
	// backlight
	pmu_set_pin_to_PMU((enum system_port_t)LCD_BACKLIGHT_PORT, LCD_BACKLIGHT_PIN);
	pmu_set_pin_dir((enum system_port_t)LCD_BACKLIGHT_PORT, LCD_BACKLIGHT_PIN, GPIO_DIR_OUT);
	// reset
	pmu_set_pin_to_PMU((enum system_port_t)LCD_REST_PORT, LCD_REST_PIN);
	pmu_set_pin_dir((enum system_port_t)LCD_REST_PORT, LCD_REST_PIN, GPIO_DIR_OUT);
	// DC
	GPIO_Handle.Pin       = LCD_DC_PIN;
	GPIO_Handle.Mode      = GPIO_MODE_OUTPUT_PP;
	gpio_init(LCD_DC_PORT, &GPIO_Handle);
	/* CS */
	GPIO_Handle.Pin       = LCD_CS_PIN;
	GPIO_Handle.Mode      = GPIO_MODE_OUTPUT_PP;
	gpio_init(LCD_CS_PORT, &GPIO_Handle);
	
	GPIO_Handle.Pin       = LCD_SPI_PIN;
	GPIO_Handle.Mode      = GPIO_MODE_AF_PP;
	GPIO_Handle.Pull      = GPIO_PULLDOWN;
	GPIO_Handle.Alternate = GPIO_FUNCTION_2;
	gpio_init(LCD_SPI_PORT, &GPIO_Handle);
	LCD_RELEASE_CS();
	LCD_SET_DC();
	LCD_ENABLE_BACKLIGHT();
	#ifdef DEVICE_LCD_PWM
	init_lcd_pwm();
	#endif
}
void gc9c01_uninit_io(void)
{
	pmu_set_pin_to_PMU((enum system_port_t)LCD_DC_PORT, LCD_DC_PIN);
	pmu_set_pin_dir((enum system_port_t)LCD_DC_PORT, LCD_DC_PIN, GPIO_DIR_IN);
	
	pmu_set_pin_to_PMU((enum system_port_t)LCD_CS_PORT, LCD_CS_PIN);
	pmu_set_pin_dir((enum system_port_t)LCD_CS_PORT, LCD_CS_PIN, GPIO_DIR_IN);
	
	pmu_set_pin_to_PMU((enum system_port_t)LCD_SPI_PORT, LCD_SPI_PIN);
	pmu_set_pin_dir((enum system_port_t)LCD_SPI_PORT, LCD_SPI_PIN, GPIO_DIR_IN);
}

经过这样的配置在睡眠的时候低电流为31UA,平均电流65UA:
在这里插入图片描述
其实之前我能够达到10UA的,但是现在不知道为啥总是不行了:
在这里插入图片描述
电流波形数据和代码固件请从如下地址下载:https://download.csdn.net/download/cheng___yi/87455507

重新开启SPI

上面是睡眠后再也不开启SPI进行图片刷图的情况,如果唤醒后要刷图还要重新把SPI等管脚从PMU模式切换成SPI等模式:

void gc9c01_reinit_io(void)
{
    pmu_set_pin_to_CPU ((enum system_port_t)LCD_DC_PORT, LCD_DC_PIN);
    pmu_set_pin_to_CPU ((enum system_port_t)LCD_CS_PORT, LCD_CS_PIN);
    pmu_set_pin_to_CPU ((enum system_port_t)LCD_SPI_PORT, LCD_SPI_PIN);
	gc9c01_init_io();
	printf("gc9c01_init_io finish\r\n");
	gc9c01_init_spi();
	gc9c01_init_dma();
    
    lcd_gpio_state=false;
}
//开机初始化
void gc9c01_init(void)
{
	gc9c01_reinit_io();
	........................................
}

这里用RTC的闹钟功能实现一个5S定时器,然后设置标志位等待主循环切图:

void proj_init(void)
{
......................................
	gc9c01_init();    
    rtc_init();
    rtc_CountUpdate(0);
    rtc_AlarmConfig(AlARM_A,0,0,5);
    NVIC_EnableIRQ(PMU_IRQn);    
	
	system_sleep_enable();
}
void rtc_alarma_handle(void)
{
   system_sleep_disable();
    if(time0_5s_timeout==false)
    {
        time0_5s_timeout=true;
        time0_5s_cnt++;
    }
}

主循环中先配置管脚在切图:

__attribute__((section("ram_code"))) void main_loop(void)
{
    while(1)
    {
    .................
    //ÂÖ²¥Í¼Æ¬
		if((time0_5s_timeout==true) && (first_loop==true))
		{
			printf("time0_5s_timeout %d\r\n",time0_5s_cnt);
            gc9c01_reinit_io();
			switch (time0_5s_cnt)
			{
			............................

经过这样的配置基本可以实现唤醒后切图的效果!

图片5S切换效果

PD5的bug

昨晚调功耗到1点半,莫名其妙搞了好久才知道是因为PD5的问题,我PMU设置了PD5就是不能够正常亮屏,最终放弃了,今天找到原厂技术支持,原厂这样说:
初始化pd5的时候加个pmu_set_pin_mux_cfg_sel(GPIO_PORT_D, PMU_GPIO_MUX_CFG_PK);//设置pmu口一组io配置为gpio功能
这个问题主要是Pmu操作下,pd5没有单独的使能输出功能,和pd4是共用的使能输出。
在这里插入图片描述
看来还是得多沟通呀,经过上面的设置后LVGL工程的电流情况如下:
在这里插入图片描述
电流还是没有达到预期,这个还要继续调试!

设置管脚为PMU模式

fr8008gp的GPIO在睡眠后就被设置成关闭状态(浮空输入),但是对于我们屏幕的RST和背光管脚要在睡眠的时候依旧维持状态不变,这个就要把管脚设置为PMU模式:

#define LCD_REST_PORT       GPIO_PORT_E
#define LCD_REST_PIN        GPIO_BIT_1

#define LCD_BACKLIGHT_PORT       GPIO_PORT_B
#define LCD_BACKLIGHT_PIN        GPIO_BIT_2

#define LCD_RELEASE_RESET()         pmu_set_gpio_value(LCD_REST_PORT,(1 << LCD_REST_PIN),GPIO_PIN_SET)
#define LCD_SET_RESET()             pmu_set_gpio_value(LCD_REST_PORT,(1 << LCD_REST_PIN),GPIO_PIN_CLEAR)

#define LCD_ENABLE_BACKLIGHT()         pmu_set_gpio_value(LCD_BACKLIGHT_PORT,(1 << LCD_BACKLIGHT_PIN),GPIO_PIN_SET)
#define LCD_DISABLE_BACKLIGHT()        pmu_set_gpio_value(LCD_BACKLIGHT_PORT,(1 << LCD_BACKLIGHT_PIN),GPIO_PIN_CLEAR)

static void gc9c01_init_io(void)
{
	------------------------------
	// backlight
    pmu_set_pin_to_PMU(LCD_BACKLIGHT_PORT, (1 << LCD_BACKLIGHT_PIN));
    pmu_set_pin_mux(LCD_BACKLIGHT_PORT, LCD_BACKLIGHT_PIN, PMU_PIN_FUNC_GPIO);
    pmu_set_pin_dir(LCD_BACKLIGHT_PORT, (1 << LCD_BACKLIGHT_PIN), GPIO_DIR_OUT);
    pmu_set_pin_pull(LCD_BACKLIGHT_PORT,(1 << LCD_BACKLIGHT_PIN),GPIO_PULL_NONE);
	// reset
    pmu_set_pin_to_PMU(LCD_REST_PORT, (1 << LCD_REST_PIN));
    pmu_set_pin_mux(LCD_REST_PORT, LCD_REST_PIN, PMU_PIN_FUNC_GPIO);
	pmu_set_pin_dir(LCD_REST_PORT, (1 << LCD_REST_PIN), GPIO_DIR_OUT);
    pmu_set_pin_pull(LCD_REST_PORT,(1 << LCD_REST_PIN),GPIO_PULL_NONE);
    LCD_DISABLE_BACKLIGHT();
    ----------------------------------
}

注意PMU只能够用于控制变化比较慢的管脚.对于速度比较快的管脚不合适!这里经过设置不同的芯片电流不一样,有18UA的和37UA的具体原因不明!
在这里插入图片描述
在这里插入图片描述

VBAT电压低于3.3V需要打开LDO的bypass模式

如上面的"设置管脚为PMU模式"章节的说明,我们功耗有18UA和37UA两种低电流,我这里使用3.0供电,还遇到一个非常奇葩的bug,相同的代码相同的硬件设计不同的板子低电流都不一样,有的板子电流227UA,无语了.
在这里插入图片描述

这个情况是因为没有屏蔽内部的LDO造成的,非常无语,按照原厂的说法电压再3.6V就没有问题!这里尝试关闭LDO模式

void pmu_sub_init(void)
{
	-------------------------------------------    
	ool_write(PMU_REG_IOLDO_CFG_1, ool_read(PMU_REG_IOLDO_CFG_1)|0x20);
}

经过测试原来227UA的电流降低到35UA,这个合理的水平,喜提一坑:
在这里插入图片描述

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 21
    评论
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值