首页 > 其他分享 >ICM20948 DMP代码详解(25)

ICM20948 DMP代码详解(25)

时间:2024-09-17 11:24:42浏览次数:15  
标签:ICM20948 write 25 memaddr DMP result data size

接前一篇文章: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函数中的后续代码。

 

标签:ICM20948,write,25,memaddr,DMP,result,data,size
From: https://blog.csdn.net/phmatthaus/article/details/142205253

相关文章