ICM20948 DMP代码详解(25)

news2024/11/15 21:40:53

接前一篇文章:ICM20948 DMP代码详解(24)

 

上一回讲到了inv_icm20948_load_firmware函数,对于大体功能进行了介绍,本回深入其具体实现代码细节。为了便于理解和回顾,再次贴出相关代码:

	//Setup Ivory DMP.
	result |= inv_icm20948_load_firmware(s, dmp3_image, dmp3_image_size);
	if(result)
		return result;
	else
		s->base_state.firmware_loaded = 1;
/** Loads the dmp firmware for the icm20948 part.
* @param[in] dmp_image_sram Load DMP3 image from SRAM.
*/
int inv_icm20948_load_firmware(struct inv_icm20948 *s, const unsigned char *dmp3_image, unsigned int dmp3_image_size)
{
	return inv_icm20948_firmware_load(s, dmp3_image, dmp3_image_size, DMP_LOAD_START);
}
int inv_icm20948_firmware_load(struct inv_icm20948 *s, const unsigned char *data_start, unsigned short size_start, unsigned short load_addr)
{ 
    int write_size;
    int result;
    unsigned short memaddr;
    const unsigned char *data;
    unsigned short size;
    unsigned char data_cmp[INV_MAX_SERIAL_READ];
    int flag = 0;

	if(s->base_state.firmware_loaded)
		return 0;
		
    // Write DMP memory
    data = data_start;
    size = size_start;
    memaddr = load_addr;
    while (size > 0) {
        write_size = min(size, INV_MAX_SERIAL_WRITE);
        if ((memaddr & 0xff) + write_size > 0x100) {
            // Moved across a bank
            write_size = (memaddr & 0xff) + write_size - 0x100;
        }
        result = inv_icm20948_write_mems(s, memaddr, write_size, (unsigned char *)data);
        if (result)  
            return result;
        data += write_size;
        size -= write_size;
        memaddr += write_size;
    }

    // Verify DMP memory

    data = data_start;
    size = size_start;
    memaddr = load_addr;
    while (size > 0) {
        write_size = min(size, INV_MAX_SERIAL_READ);
        if ((memaddr & 0xff) + write_size > 0x100) {
            // Moved across a bank
            write_size = (memaddr & 0xff) + write_size - 0x100;
        }
        result = inv_icm20948_read_mems(s, memaddr, write_size, data_cmp);
        if (result)
            flag++; // Error, DMP not written correctly
        if (memcmp(data_cmp, data, write_size))
            return -1;
        data += write_size;
        size -= write_size;
        memaddr += write_size;
    }

#if defined(WIN32)   
    //if(!flag)
      // inv_log("DMP Firmware was updated successfully..\r\n");
#endif

    return 0;
}

先看以下代码片段:

    // Write DMP memory
    data = data_start;
    size = size_start;
    memaddr = load_addr;
    while (size > 0) {
        write_size = min(size, INV_MAX_SERIAL_WRITE);
        if ((memaddr & 0xff) + write_size > 0x100) {
            // Moved across a bank
            write_size = (memaddr & 0xff) + write_size - 0x100;
        }
        result = inv_icm20948_write_mems(s, memaddr, write_size, (unsigned char *)data);
        if (result)  
            return result;
        data += write_size;
        size -= write_size;
        memaddr += write_size;
    }

data = data_start,对应的实际是dmp3_image数组的地址;size = size_start,对应的实际是dmp3_image数组的长度;memaddr = load_addr,对应的实际是DMP_LOAD_START。DMP_LOAD_START宏在EMD-Core\sources\Invn\Devices\Drivers\ICM20948\Icm20948Dmp3Driver.c和EMD-Core\sources\Invn\Devices\Drivers\ICM20948\Icm20948Defs.h中都有定义,不过值都是一样的。

#define DMP_LOAD_START      0x90

接下来进入while循环。

一上来先确定write_size即本次写入的数据长度。

        write_size = min(size, INV_MAX_SERIAL_WRITE);

write_size取size和INV_MAX_SERIAL_WRITE的较小者。一开始的时候,size为size_start,也就是sizeof(dmp3_image),非常大(#define DMP_CODE_SIZE 14301);而INV_MAX_SERIAL_WRITE前文书提到过,只有16,因此write_size为16。

这里实际上就能知道,这个写入是每次最多写入16个字节,最后一次写入的很有可能小于16个字节。

接下来要做的是调整write_size:

        if ((memaddr & 0xff) + write_size > 0x100) {
            // Moved across a bank
            write_size = (memaddr & 0xff) + write_size - 0x100;
        }

memaddr当前是0x90,write_size当前是0,两者加在一起为0x90,小于0x100即256,因此不会进入判断体,无需调整。

那么什么时候需要调整呢?每次写16个字节,当某一次memaddr加上write_size大于0x100(256)的时候,就不再写write_size字节了,而是写(memaddr & 0xff) + write_size - 0x100个字节。这样实际上就保证了memaddr按照以bank为模进行写入,也就是注释中的“Moved across a bank”。

为何要这样做?笔者理解是因为dmp3_image数组中是以bank为单位的,一个bank是256个字节。

d1f4f3cb121545a78120d6f2bdca9cb3.png

96867e13ebf647839362401705ecccd8.png

bank0的长度为0x100-0x90=256-144=112(0x70),正好是7行。从bank1开始,就是16行了。

接下来来到以下代码片段:

        result = inv_icm20948_write_mems(s, memaddr, write_size, (unsigned char *)data);
        if (result)  
            return result;
        data += write_size;
        size -= write_size;
        memaddr += write_size;

从memaddr开始写入write_size个字节的数据。memaddr一开始是0x90,第一次写入16个字节后,变为0x90+0x10=0xA0(160),size减小16,data即dmp3_image数组的指针也向后移16个字节。第二次重复这一过程……这样依次循环,直到size<=0(实际上只能是==0)为止。

写完之后就来到以下代码片段:

    // Verify DMP memory

    data = data_start;
    size = size_start;
    memaddr = load_addr;
    while (size > 0) {
        write_size = min(size, INV_MAX_SERIAL_READ);
        if ((memaddr & 0xff) + write_size > 0x100) {
            // Moved across a bank
            write_size = (memaddr & 0xff) + write_size - 0x100;
        }
        result = inv_icm20948_read_mems(s, memaddr, write_size, data_cmp);
        if (result)
            flag++; // Error, DMP not written correctly
        if (memcmp(data_cmp, data, write_size))
            return -1;
        data += write_size;
        size -= write_size;
        memaddr += write_size;
    }

这段很好理解。就是写入之后,再从DMP_LOAD_START(0x90)开始读取sizeof(dmp3_image)大小的数据(当然,还是每次最多16个字节的机制),并与dmp3_image原始数据进行比较,最终完全一致,则证明写入正确,返回0;中间有任何一次不正确,则返回-1,表示DMP固件加载失败。

这里提一下DMP_LOAD_START(0x90)这个寄存器,也可以说是内存。你如果在芯片手册中找,是找不到的。感觉这个DMP像个后门似的,在手册中不体现,一般不让用户知道。

至此,inv_icm20948_firmware_load函数就解析完了,inv_icm20948_load_firmware函数也就解析完了。回到inv_icm20948_initialize_lower_driver函数中的代码片段:

​	//Setup Ivory DMP.
	result |= inv_icm20948_load_firmware(s, dmp3_image, dmp3_image_size);
	if(result)
		return result;
	else
		s->base_state.firmware_loaded = 1;

如果正常没有问题即返回了0,则走else分支,将s->base_state.firmware_loaded设置为1。

下一回继续解析inv_icm20948_initialize_lower_driver函数中的后续代码。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2142542.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【个人博客hexo版】hexo安装时会出现的一些问题

项目场景&#xff1a; 项目场景&#xff1a;在完成了GitHub仓库和git的连接之后&#xff0c;就要新建一个文件夹&#xff08;例如hexo blog&#xff09;进行下一步hexo的使用 问题描述 例如&#xff1a;如图所示 原因分析&#xff1a; 这些error不用看它到底是什么&#xf…

Chrome谷歌浏览器登录账号next无反应

文章目录 问题描述 我们的Chrome浏览器在更新之后&#xff0c;会出现登录谷歌账号的时候&#xff0c;当你输入你的谷歌邮箱之后&#xff0c;点击 n e x t next next,也就是下一步的时候&#xff0c;页面没有反应&#xff0c;也就是没有跳转到输入密码的页面。 分析 根据logs里…

CLIP模型也能处理点云信息(论文复现)

CLIP模型也能处理点云信息&#xff08;论文复现&#xff09; 本文所涉及所有资源均在传知代码平台可获取 文章目录 CLIP模型也能处理点云信息&#xff08;论文复现&#xff09;概述模型结构模型总览图点云的投影视图间适配器 演示效果零样本投影少样本投影 核心逻辑使用方式部署…

Mamba环境配置教程【自用】

1. 新建一个Conda虚拟环境 conda create -n mamba python3.102. 进入该环境 conda activate mamba3. 安装torch&#xff08;建议2.3.1版本&#xff09;以及相应的 torchvison、torchaudio 直接进入pytorch离线包下载网址&#xff0c;在里面寻找对应的pytorch以及torchvison、…

VTD激光雷达(5)——05_OptiX_GPU

文章目录 前言一、总结 前言 一、 1 2 3 总结

随着访问范围的扩大 OpenAI o1-mini 现已向免费用户开放

上周&#xff0c;OpenAI 展示了其最新的大型语言模型&#xff08;LLM&#xff09;–OpenAI o1及其小兄弟 OpenAI o1-mini。该公司在公告中称&#xff0c;Plus 和 Team 用户可在公告发布之日起访问该模型。企业和教育用户将在本周获得该模型&#xff0c;而免费用户最终将获得 o1…

线性代数之QR分解和SVD分解

文章目录 1.QR分解Schmidt正交化Householder变换QR分解的应用 2. 求矩阵特征值、特征向量的基本方法3.SVD分解SVD分解的应用 参考文献 1.QR分解 矩阵的正交分解又称为QR分解&#xff0c;是将矩阵分解为一个正交矩阵Q和一个上三角矩阵R的乘积的形式。 任意实数方阵A&#xff0c…

2022高教社杯全国大学生数学建模竞赛C题 问题一(1) Python代码

目录 问题 11.1 对这些玻璃文物的表面风化与其玻璃类型、纹饰和颜色的关系进行分析数据探索 -- 单个分类变量的绘图树形图条形图扇形图雷达图Cramer’s V 相关分析统计检验列联表分析卡方检验Fisher检验绘图堆积条形图分组条形图分类模型Logistic回归随机森林import matplotlib…

SpaceX实现人类首次商业太空行走:航天历史新篇章

导语 2023年9月&#xff0c;SpaceX成功完成了人类历史上首次商业太空行走&#xff0c;这不仅是航天领域的重要突破&#xff0c;也是商业航天的一次重大胜利。这一事件标志着普通人离太空更近了一步&#xff0c;为未来的太空探索和火星移民奠定了基础。 一、背景介绍&#xff1a…

【MySQL】数据类型【mysql当中各自经典的数据类型的学习和使用】

目录 数据类型1数据类型分类2.数值类型2.1tinyint类型2.2bit类型2.3小数类型2.3.1float2.3.2decimal 3.字符串类型3.1char3.2varchar3.3char和varchar的对比 4.日期和时间类型5.enum和set5.1对enum和set进行插入5.2对enum和set进行查询 数据类型 数据类型本身就是mysql当中天然…

YOLOv8 的安装与训练

YOLOv8 是 YOLO 系列实时目标检测器中的较新迭代版本&#xff0c;在准确性和速度方面提供了前沿性能。基于之前 YOLO 版本的进步&#xff0c;YOLOv8 引入了新的特性和优化&#xff0c;使其成为各种应用中各种目标检测任务的理想选择。 一、安装显卡驱动与CUDA&#xff1a; 这个…

成都院干翻华东院成第一水电设计院!

注&#xff1a;文章来源于百度。版权归原作者所有。。 昨天中国电建发布了2024年中报&#xff0c;一般中报我是不怎么研究的&#xff0c;除非利益相关。 但今年电建的中报亮点很多&#xff0c;其中最显眼的就要数电建成都院在上半年干翻了传统龙头老大——华东院。 在净利润…

【C++】一次rustdesk-server编译记录

RustDesk Server 是一个开源的远程桌面解决方案&#xff0c;允许用户自托管自己的远程桌面服务器。该项目是免费且开源的&#xff0c;支持多种平台和环境。RustDesk Server 提供了 ID/Rendezvous 服务器和 Relay 服务器&#xff0c;以及一些 CLI 工具&#xff0c;方便用户进行远…

[Redis] Redis中的set和zset类型

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

动手学深度学习8.5. 循环神经网络的从零开始实现-笔记练习(PyTorch)

本节课程地址&#xff1a;从零开始实现_哔哩哔哩_bilibili 本节教材地址&#xff1a;8.5. 循环神经网络的从零开始实现 — 动手学深度学习 2.0.0 documentation (d2l.ai) 本节开源代码&#xff1a;...>d2l-zh>pytorch>chapter_multilayer-perceptrons>rnn-scratc…

【优化器】Optimizer——深度学习中的优化器是什么作用呢?

【优化器】Optimizer——深度学习中的优化器是什么作用呢&#xff1f; 【优化器】Optimizer——深度学习中的优化器是什么作用呢&#xff1f; 文章目录 【优化器】Optimizer——深度学习中的优化器是什么作用呢&#xff1f;1.什么是优化器&#xff1f;梯度下降法3. 常见的优化…

数据结构易错整理1

目录 数据结构的基础概念 数据结构基础概念 数据结构的逻辑结构 数据结构的物理结构 算法分析 时间复杂度 例题 数据结构的基础概念 数据结构基础概念 设计存储结构时不仅要存储格数据元素的值&#xff0c;而且还要存储数据元素之间的关系 数据结构具有特定关系的数据…

C/C++语言基础--从C到C++的不同(下),15个部分说明C与C++的不同

本专栏目的 更新C/C的基础语法&#xff0c;包括C的一些新特性 前言 1-10在上篇C/C语言基础–从C到C的不同(上&#xff09;&#xff1b;当然C和C的不同还有很多&#xff0c;本人暂时只总结这些&#xff0c;其他的慢慢更新&#xff1b;上一篇C/C语言基础–从C到C的不同(上&…

Sass实现文字两侧横线及Sass常用方案

Sass常用方案及Sass实现文字两侧横线 1.Sass实现文字两侧横线2.用Sass简化媒体查询3.使用继承占位符实现样式复用4.Sass 模块化5.lighten 和 darken 自我记录 1.Sass实现文字两侧横线 mixin 的基本作用&#xff1a; 代码复用&#xff1a;把常用的样式封装在一起&#xff0c;…

C++和OpenGL实现3D游戏编程【目录】

欢迎来到zhooyu的专栏。 个人主页&#xff1a;【zhooyu】 文章专栏&#xff1a;【OpenGL实现3D游戏编程】 贝塞尔曲面演示&#xff1a; 贝塞尔曲面演示zhooyu 本专栏内容&#xff1a; 我们从游戏的角度出发&#xff0c;用C去了解一下游戏中的功能都是怎么实现的。这一切还是要…