文章目录
设备异常掉电,通常是嵌入式设备不得不面对的难题。如果处理不当,异常掉电会造成文件系统损坏、数据丢失,严重者还会造成外部器件的损坏。
一个完备的掉电保护方案,从原理上讲,可以从以下几个方面进行加强:
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);
涉及到的模块比较多也比较复杂需要小心处理;