This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] BQ4050:数据闪存块读取工作、但单字节寄存器失败

Guru**** 2559970 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/power-management-group/power-management/f/power-management-forum/1105616/bq4050-dataflash-block-reads-work-but-single-byte-registers-fail

器件型号:BQ4050

您好!

我们正在开发一种工具、用于在生产线上对我们的器件进行编程。 它执行以下序列:

  1. 阅读 Battery Management Studio 导出的 gg.csv 文件以及我们的最终配置
  2. 使用块读取命令(0x44)从器件读取数据闪存
  3. 如果这些值不匹配、请写入新值

我们观察到以下情况:

  • 所有块读取为32字节
  • 块读取对于任何长于一个字节的寄存器都是完美的。  
  • 所有单字节寄存器读取失败。 它们似乎与块读取不兼容。
  • 我在寄存器指南中找不到对 DataFlash "word read"的任何引用。 它涵盖了字写入和块读取/写入。
  • 请注意、下面的序列缺少在读取开始前发出的第二个0x44字节。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    更新:
    通过为1字节寄存器创建特殊条件、我们现在可以从539个寄存器中正确读取525。

    尊敬的 TI:不同寄存器的不同 IO 行为有何影响?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    通过对1字节和奇数地址使用相同的 Hack、我们现在可以读取除2个寄存器之外的所有寄存器。

    其他人是否都必须对其进行逆向工程?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    最后一个寄存器为 只读寄存器(制造商名称、器件名称)、因此我们要说这是解析的。 以下是我的 PC 应用程序中的代码:

    // Fill in packet
    byte BQ4050_BLOCK_READ_CMD = 0x44;
    length = 0;
    if ((reg.DataLength == 1) || ( reg.AddressOffset % 2 != 0 ))
    {
        // Word read
        // - Read command
        payload[length++] = (byte)BQ4050_BLOCK_READ_CMD;
    
        // - Length is fixed at 2 (no explanation)
        payload[length++] = 2;
    
        // - Address
        foreach (byte b in BitConverter.GetBytes(SMBAddr))
            payload[length++] = b;
    
        // - CRC
        byte crc = ComputeCRC(payload, length);
        payload[length++] = crc;
    
        // Send to device
        Send();
        var response = Receive(Timeout);
        if (response == null)
        {
            StatusBox.Log(Name + "Read: No response");
            return false;
        }
    
        StatusBox.Log(Name + "ReadWord: Read addr: 0x" + SMBAddr.ToString("X2") + " Length: " + reg.DataLength);
        // Word read
        int read_offset = response.length - BQ4050_BLOCK_READ_LEN;
        if (reg.DataFlashRawValue[0] != response.payload[read_offset])
        {
            error = true;
            StatusBox.Log("Read: Readback mismatch. Readback: " + response.payload[3].ToString("X2") + " Expected: " + reg.DataFlashRawValue[0].ToString("X2"), Color.Red);
        }
    }
    else
    {
        // Block read:
        // - Read command
        payload[length++] = (byte)BQ4050_BLOCK_READ_CMD;
    
        // - Length
        payload[length++] = (byte)reg.DataLength;
    
        // - Address must be aligned
        int alignment = (byte)(reg.AddressOffset % BQ4050_BLOCK_READ_LEN);
        SMBAddr -= (UInt16)(alignment);
        foreach (byte b in BitConverter.GetBytes(SMBAddr))
            payload[length++] = b;
    
        // - CRC
        byte crc = ComputeCRC(payload, length);
        payload[length++] = crc;
    
        // Send to device
        Send();
        var response = Receive(Timeout);
        if (response == null)
        {
            StatusBox.Log(Name + "Read: No response");
            return false;
        }
    
        StatusBox.Log(Name + "ReadBlock: Read addr: 0x" + SMBAddr.ToString("X2") + " Length: " + reg.DataLength);
        // Block read:
        int read_offset = response.length + alignment - BQ4050_BLOCK_READ_LEN;
        for (int i = 0; i < reg.DataFlashRawValue.Count; i++)
        {
            if (reg.DataFlashRawValue[i] != response.payload[i + read_offset])
            {
                error = true;
                StatusBox.Log("Read: Readback mismatch[" + i + "]. Readback: " + response.payload[i + read_offset].ToString("X2") + " Expected: " + reg.DataFlashRawValue[i].ToString("X2"), Color.Red);
            }
        }
    }

    这里是我的 MCU 代码、除了设置读取长度外、大部分都是直通代码。 我认为不需要延迟、但我不想一次性删除它们:

    bool BQ4050FactoryConfigRead( uint8_t *buf, uint16_t *len )
    {
    	uint8_t i = 0;
    	HAL_StatusTypeDef res = HAL_OK;
    
    	PRINTF("TX[%i]: ", *len);
    	for( int i = 0; i < *len; i++)
    		PRINTF("%x ", buf[i]);
    	PRINTF("\n");
    
    	// Write command with address and PEC
    	res = HAL_I2C_Master_Transmit(&hi2c1, BQ4050_ADDRESS, buf, *len, BQ4050_RW_TIMEOUT);
    	if( res != HAL_OK )
    	{
    		HippoAddLog(__FILE__, __FUNCTION__, __LINE__, res, ERR_DESC_I2C);
    		return false;
    	}
    
    	HAL_Delay(20);
    
    	// Write block read command again (no explanation)
    	res = HAL_I2C_Master_Transmit(&hi2c1, BQ4050_ADDRESS, buf, sizeof(uint8_t), BQ4050_RW_TIMEOUT);
    	if( res != HAL_OK )
    	{
    		HippoAddLog(__FILE__, __FUNCTION__, __LINE__, res, ERR_DESC_I2C);
    		return false;
    	}
    
    	// Block read are always 35 bytes
    	// 2 byte command ack + 32 bytes data + 1 byte CRC
    	const int8_t READ_BLOCK_LEN = 35;
    	*len = READ_BLOCK_LEN;
    
    	HAL_Delay(20);
    
    	// Perform read
    	res = HAL_I2C_Master_Receive(&hi2c1, BQ4050_ADDRESS, buf, *len, BQ4050_RW_TIMEOUT);
    	if( res != HAL_OK )
    	{
    		HippoAddLog(__FILE__, __FUNCTION__, __LINE__, res, ERR_DESC_I2C);
    		return false;
    	}
    
    	PRINTF("RX[%i]: ",*len );
    	for( int i = 0; i <*len; i++)
    		PRINTF("%x ", buf[i]);
    	PRINTF("\n");
    
    	return true;
    }

    希望这能为其他人节省两天时间!