当前位置: 首页 > news >正文

[单片机框架][device层] fuelgauge 电量计

通过 DEVICE_INITCALL(“dev-gauge”, fuelgauge_dev_init); 注册驱动,自动在main初始化中运行。
优点:耦合少,可移植性强,适用大团队模块化开发
缺点:抽象度高,小团队开发时间耗时久

battery管理我觉得可以分开为两个部分,一个是电池监控(fuelgauge),另一个是充放电管理(charger),所以我们在内核中也是把它分成了两个驱动来管理。

电池监控(fuelgauge)驱动主要是负责向上层android系统提供当前电池的电量以及健康状态信息等等,另外除了这个以外,它也向charger驱动提供电池的相关信息;

充放电管理(charger)驱动主要负责电源线的插拔检测,以及充放电的过程管理。对于battery管理,硬件上有电量计IC和充放电IC。

对比SW_FG 和HW_FG在硬件及软件上的部分差异,分析电量误差形成的一些原因和已经采取的消除误差的措施。这个算法的思路是这样的:
最终通过开路电压oam_v_ocv_1查ZCV表得到当前的电量值 ->
开路电压需要通过闭路电压v_bat 和 闭路电流oam_i_2 去回溯电池内阻逐次逼近 –>
oam_i_2 通过 另一种方式 电量积分更新的电压oam_v_ocv_2.

通过fuelgauge_drv_match_ids结构体可以同时适配多种电量计
在这里插入图片描述
软电量计具体过程:硬件ADC读取Battery的各路信息:包括温度,电压等。
开发的电量算法分析得到的数据。
Kernel层将电量信息通过写文件节点的方式更新,并通过UEVENT通知上层。
上层Service开启UEVENT LISTENER,监听到UEVENT后,读取battery相关文件节点,获取电量信息。
Service更新数据后,通过Broadcast通知所有开启了相关listener的activities.

硬件电量计:采用cw2015,导入电池模型,进行积分累计,每次充放电都能消除部分误差。±3%剩余电量误差,内部14-bit模数转换器进行温度和电压检测,无需检流电阻,无库伦计累积误差, 无学习周期,低电量警示中断
在这里插入图片描述

在这里插入图片描述

驱动初始化代码:

#include "typedefs.h"
#include "log.h"

#include "modules.h"

extern initcall_t __initcall_start;
extern initcall_t __initcall_end;

void modules_setup(void) {
    initcall_t *call;

    for (call = &__initcall_start; call < &__initcall_end; call++) {
        // LOG_C("[modules]:%s init\r\n", call->name);
        call->initcall();
    }
}


/**
 * @brief  Main function.
 */
int main(void) {
    hardware_init();
    modules_setup(); // 将驱动、设备、app层依次初始化

    LOG_C("[main]:kernel start...\r\n");
    start_kernel();
    while (1) {
    }
}

驱动代码:
fuelgauge_dev.c

#include <string.h>

#include "typedefs.h"
#include "errorno.h"
#include "modules.h"
#include "log.h"

#include "fuelgauge_dev.h"

static char* fuelgauge_drv_match_ids[] = {
    "cw2015", // 硬件电量计
    "gauge-adc", // 软件电量计
};

static int32_t fuelgauge_dev_open(device_t *dev)
{
    uint8_t i = 0;
    fuelgauge_driver_t *pdrv_gauge;

    if (dev == NULL)
    {
        return RETVAL(E_NULL);
    }

    if (dev->dev_drv != NULL)
    {
        return RETVAL(E_OK);
    }

    for (i=0; i<ARRAY_SIZE(fuelgauge_drv_match_ids); i++)
    {
        pdrv_gauge = fuelgauge_driver_find(fuelgauge_drv_match_ids[i]);
        if (pdrv_gauge)
        {
            if (fuelgauge_driver_probe(pdrv_gauge) == RETVAL(E_OK))
            {
                dev->dev_drv = (void*)pdrv_gauge;
                fuelgauge_driver_init((fuelgauge_driver_t*)dev->dev_drv);
                return RETVAL(E_OK);
            }
        }
    }

    return RETVAL(E_FAIL);
}

static int32_t fuelgauge_dev_ioctl(device_t *dev, uint32_t cmd, void *args)
{
    fuelgauge_cmd_argv_t *cmd_argv = args;

    switch (cmd_argv->cmd)
    {
        case FUELGAUGE_IOCTRL_CMD_WORK_MODE:
        {
            fuelgauge_driver_set_work_mode((fuelgauge_driver_t*)dev->dev_drv, (fuelgauge_work_mode_t)cmd_argv->argv);
        }
        break;

        case FUELGAUGE_IOCTRL_CMD_CHARGE_STS:
        {
            fuelgauge_driver_set_charge_state((fuelgauge_driver_t*)dev->dev_drv, (fuelgauge_charge_state_t)cmd_argv->argv, 0);
        }
        default:
        break;
    }

    return RETVAL(E_OK);
}

static int32_t fuelgauge_dev_read(device_t *dev, char *buffer, xsize_t size, xloff_t *pos)
{
    int32_t ret;

    ret = fuelgauge_driver_get_info((fuelgauge_driver_t*)dev->dev_drv, (fuelgauge_info_t*)buffer);
    if (ret < 0)
    {
        LOG_E("[fuelgauge_dev][read]:get_info failed ret=%d\r\n", ret);
    }
    return RETVAL(E_OK);
}

const device_ops_t fuelgauge_dev_ops =
{
   /* (*open)  */ fuelgauge_dev_open,
   /* (*close) */ NULL,
   /* (*read)  */ fuelgauge_dev_read,
   /* (*write) */ NULL,
   /* (*ioctl) */ fuelgauge_dev_ioctl,
};

static void fuelgauge_dev_init(void)
{
    static device_t fuelgauge_dev;
    int32_t ret;

    memset(&fuelgauge_dev, 0, sizeof(device_t));
    fuelgauge_dev.type = DEVICE_CLASS_CHAR;
    fuelgauge_dev.dev_ops = &fuelgauge_dev_ops;

    ret = device_register(&fuelgauge_dev, "dev-gauge", DEVICE_FLAG_WRONLY);
    if (ret < 0)
    {
        LOG_E("[fuelgauge_dev][init]:register failed ret=%d\r\n", ret);
    }
}

DEVICE_INITCALL("dev-gauge", fuelgauge_dev_init);

fuelgauge_dev.h

#ifndef _FUELGAUGE_DEV_H_
#define _FUELGAUGE_DEV_H_

#include "../../object/device.h"
#include "fuelgauge.h"

#endif // _FUELGAUGE_DEV_H_

相关文章:

  • 基于linux的web服务器(问题)
  • 【leetcode top100】两数相加。无重复字符的最长子串,盛水最多的容器,三数之和
  • PIE-Engine 教程:水稻面积提取1(宿迁市)
  • CMSC5707-高级人工智能之语音识别
  • AES(对称加密)学习记录
  • 【技术推荐】WebLogic 反序列化漏洞深入分析
  • 提高 IDC 网络带宽利用率
  • JavaWeb综合案例(黑马程序员2021年JavaWeb课程总结,所有功能均实现,包含数据库sql文件)
  • 卫星通信系统按照工作轨道分类
  • JDBC在idea上的配置
  • Kotlin协程:MutableStateFlow的实现原理
  • ElasticSearch入门笔记
  • Pytorch 自动求导的设计与实现
  • 抖音怎么开启直播
  • 【Servlet】Servlet API
  • SegmentFault for Android 3.0 发布
  • 《Java8实战》-第四章读书笔记(引入流Stream)
  • 【node学习】协程
  • 0x05 Python数据分析,Anaconda八斩刀
  • 2017 前端面试准备 - 收藏集 - 掘金
  • 2017-08-04 前端日报
  • avalon2.2的VM生成过程
  • ES2017异步函数现已正式可用
  • java中的hashCode
  • Js基础——数据类型之Null和Undefined
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • Python进阶细节
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • Vue2 SSR 的优化之旅
  • Yeoman_Bower_Grunt
  • 力扣(LeetCode)21
  • 配置 PM2 实现代码自动发布
  • 使用 QuickBI 搭建酷炫可视化分析
  • 算法系列——算法入门之递归分而治之思想的实现
  • 我与Jetbrains的这些年
  • 【运维趟坑回忆录 开篇】初入初创, 一脸懵
  • 7行Python代码的人脸识别
  • ​猴子吃桃问题:每天都吃了前一天剩下的一半多一个。
  • (poj1.2.1)1970(筛选法模拟)
  • (附表设计)不是我吹!超级全面的权限系统设计方案面世了
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (六)软件测试分工
  • (一)Dubbo快速入门、介绍、使用
  • (一)基于IDEA的JAVA基础1
  • (正则)提取页面里的img标签
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite
  • (转)Sql Server 保留几位小数的两种做法
  • (转)重识new
  • .gitignore文件---让git自动忽略指定文件
  • .NET DataGridView数据绑定说明
  • .Net 代码性能 - (1)
  • .NET 将混合了多个不同平台(Windows Mac Linux)的文件 目录的路径格式化成同一个平台下的路径
  • .net 设置默认首页
  • .Net 应用中使用dot trace进行性能诊断
  • .net开发时的诡异问题,button的onclick事件无效