Linux掉电保护方案设计

设备异常掉电,通常是嵌入式设备不得不面对的难题。如果处理不当,异常掉电会造成文件系统损坏、数据丢失,严重者还会造成外部器件的损坏。

一个完备的掉电保护方案,从原理上讲,可以从以下几个方面进行加强:

1. 硬件掉电检测

1.1 硬件电路

在这里插入图片描述
硬件掉电保护电路主要提供了以下功能:

1、提供了24V掉电检测和5V掉电检测功能。SIGN_5728这个管脚正常为高电平,在电压降低到一定程度后会变成低电平,产生一个中断给CPU;

2、提供了延时下电功能。电路中加入了几个大容量电容,在外部电源掉电以后,电容可以支持一段时间(几秒钟)核心电路的供电;

针对硬件提供的宝贵的掉电通知和延时掉电机制,软件需要紧密配合:

1、软件在接收到掉电中断以后,在转为电容供电的几秒钟时间里,需要做完系统的保护动作:文件系统同步、系统PowerDown或者Reboot。

1.2 软件实现

1.2.1 DTS 配置

  • 1、首先我们配置掉电检测管脚连接的pin脚为通用gpio功能:

kernel\arch\arm\boot\dts\am57xx-evm-common.dtsi:

&dra7_pmx_core {
    gpio3_3_pins_default: gpio3_3_pins_default {
		pinctrl-single,pins = <
			DRA7XX_CORE_IOPAD(0x34F, (PIN_INPUT_PULLUP | MUX_MODE14)) /* gpio3.3 */
		>;
	};
  • 2、创建一个使用上述掉电检测gpio的platform device:
/ {

    powerdown_protect {
        compatible = "grobot,powerdown_protect";
        
        powerdown_detect_gpio  = <&gpio3 3 GPIO_ACTIVE_HIGH>;
    };
};

1.2.2 driver

创建对应的platform driver:

static int powerdown_protect_remove(struct platform_device *pdev)
{
	free_irq(irq_num, pdev);
	gpio_free(gpio_id);
	return 0;
}


static const struct of_device_id powerdown_protect_match[] = {
	{ .compatible = "grobot,powerdown_protect", },
	{}
};

static struct platform_driver powerdown_protect_driver = {
	.probe = powerdown_protect_probe,
    .remove = powerdown_protect_remove,
	.driver	= {
		.name = "grobot_powerdown_protect",
        .owner = THIS_MODULE,
		.of_match_table	= powerdown_protect_match,
	},
};

在驱动的初始化函数中,初始化掉电检测的gpio,以及注册中断服务:

static int powerdown_protect_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct device_node *node = dev->of_node;
	int ret = -1;

	gpio_id = of_get_named_gpio(node, "powerdown_detect_gpio", 0);
	if (gpio_id >= 0)
	{
		printk("Get power down detect gpio id = %d.\n", gpio_id);
	}
	else
	{
		printk("Get power down detect gpio id fail! (%d)\n", gpio_id);
		return ret;
	}

	ret = gpio_request(gpio_id, "powerdown_detect");
	if (ret)
	{
		printk("Request gpio %d fail! (%d)\n", gpio_id, ret);
		return ret;
	}

	ret = gpio_direction_input(gpio_id);
	if (ret)
	{
		printk("Set gpio %d input direct fail! (%d)\n", gpio_id, ret);
		goto fail;
	}

	ret = gpio_set_debounce(gpio_id, DEBOUNCE_TIME);
	if (ret)
	{
		printk("Set gpio %d debounce %d fail! (%d)\n", gpio_id, DEBOUNCE_TIME, ret);
		goto fail;
	}

	setup_timer(&powerdown_timer, powerdown_timer_func, 0);
	INIT_WORK(&powerdown_work, powerdown_work_func);

	irq_num = gpio_to_irq(gpio_id);
	if (irq_num < 0)
	{
		printk("Get gpio %d irq fail! (%d)\n", gpio_id, ret);
		goto fail;
	}

	ret = request_irq(irq_num, powerdown_detect_irq, IRQFLAGS, IRQDESC, pdev);
	if (ret)
	{
		printk("Claim gpio %d irq %d fail! (%d)\n", gpio_id, irq_num, ret);
		goto fail;
	}

	return 0;

fail:
	gpio_free(gpio_id);
	return ret;
}

在中断服务中同步文件系统,以及发起reboot操作:

static void powerdown_exec(void)
{
	/* 文件系统同步 */
	printk("powerdown detect sync filesystem!\n ");
	sys_sync();
	
	/* 系统reboot */
	printk("powerdown detect reboot system!\n ");
	kernel_restart(IRQDESC);
}

2. 软件增强

2.1 系统分区写保护

为了缩小文件系统可能造成的破坏,可以把文件系统分区,把系统分区设置为只读:

root@am335x-evm:~# mount
rootfs on / type rootfs (rw)
/dev/root on / type yaffs2 (ro,relatime)
/dev/mtdblock8 on /home/root type yaffs2 (rw,sync,relatime)
/dev/mtdblock7 on /mnt/app type yaffs2 (ro,relatime)
root@am335x-evm:~# 

2.2 开机文件系统错误修复

还可以在开机启动的时候,增加一个环节:如果检测到有异常关机的情况,运行fsck文件系统修复程序来修复文件系统中可能存在的错误。

root@am57xx-evm:~# mount -o remount,ro /
[   91.164253] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)
root@am57xx-evm:~# 
root@am57xx-evm:~# fsck /
fsck from util-linux 2.27.1
e2fsck 1.43-WIP (18-May-2015)
fsck.ext2: No such file or directory while trying to open /dev/root
Possibly non-existent device?
root@am57xx-evm:~# 

2.3 运行时功耗优化

降低运行时功耗,可以减少系统耗电,可以延长电容的供电时间。

降低功耗的具体措施可以有:

  • 1、关闭Buck/LDO的供电(Voltage Domain),Linux Regulator的管理;
  • 2、关闭一些小区域的供电(Power Domain);
  • 3、关闭一些运行时钟(Clock Domain),Linux clk的管理;
  • 4、运行时CPU/GPU的降频(DVFS/OPP);

涉及到的模块比较多也比较复杂需要小心处理;

posted @ 2020-11-01 10:14  pwl999  阅读(648)  评论(0编辑  收藏  举报