Configuring the MAX17205 Fuel Gauge Without Writing to Nonvolatile Memory

Introduction

The MAX17205 fuel gauge IC utilizes Maxim’s ModelGaugeTM m5 algorithm to accurately track the state of charge of a multi-series cell battery pack. It combines coulomb counting, voltage monitoring, and temperature compensation to improve accuracy while also offering several useful features such as cell balancing, overcurrent comparators, a configurable alert signal, SHA-256 authentication, smart battery compliant operation, and more. Naturally, this device requires an initial configuration to tailor it the battery’s specifications and enable/disable the desired features. However, it may take several attempts to get every register set correctly to achieve desired device operation and, unfortunately, these nonvolatile registers can only be written 7 times by the user. In order to circumvent this limit for prototyping, the user must be able to load their configuration to the device without storing it in nonvolatile memory.

This article exclusively references the MAX17205 fuel gauge. However, the same principals apply to the MAX17201, MAX17211, and MAX17215 fuel gauges. The only differences between these devices are the cell count and communication interfaces used.

Device Cell Count Comm. Interface
MAX17201 1 I2C
MAX17205 Multiple I2C
MAX17211 1 Maxim 1-Wire®
MAX17215 Multiple Maxim 1-Wire®

The Memory Space

The memory space on the MAX17205 is organized into several functional blocks. A basic understanding of the two most important of these blocks is necessary to fully grasp the process of testing an application specific configuration on the device. The first of these is the discontinuous block of ModelGauge m5 registers, summarized in Table 1. These registers, which span pages 0x00 – 0x04, 0x0B, and 0x0D, are essentially the inputs and outputs of the ModelGauge m5 algorithm. The inputs contain information about the cell, the fuel gauge application, and real-time system measurements. For example; the DesignCap register (0x018) holds the expected capacity of the cell, VAlrtTh (0x001) sets the upper and lower cell voltage limits for the alert function, and Current (0x00A) stores the latest voltage measurement across the current sense resistor. These registers can be read from/written to directly via the I2C communication interface.

Table 1: ModelGauge m5 Register Memory Map [1]

The second major block is the nonvolatile memory, outlined in Table 2. Located in pages 0x18 through 0x1D; this section contains backups of the previously mentioned ModelGauge configuration registers, characterization tables, device information, and general purpose user memory. For example; the value stored in the nDesignCap register (0x1B3) can be configured to restore the DesignCap register (0x018) on power-up or hardware reset, the nXTable registers (0x180 – 0x18B) may contain custom cell characterization information for the ModelGague m5 algorithm, registers 0x1D8 – 0x1DF contain the device serial number and name, and there are several user memory words (label nUser) scattered throughout the nonvolatile block. Unlike the ModelGauge m5 registers, the nonvolatile memory cannot be written to directly via I2C. Rather, the user must read from/write to the shadow RAM located at the same address space and use the COPY NV BLOCK and NV RECALL commands to interface with the nonvolatile memory, as shown in Figure 1. The NV RECALL operation occurs automatically when the IC is powered up and after a hardware reset, but it can also be done manually by writing 0xE001 to register 0x060. To carry out the COPY NV BLOCK operation, the “Nonvolatile Block Programming” section of the datasheet should be consulted as there are many steps involved [1]. The major limitation with this command is that it may only be executed 7 times, leaving very little margin for error when loading a custom configuration on the device.

Table 2: Nonvolatile Register Memory Map [1]


Figure 1: Shadow RAM and Nonvolatile Memory Relationship [1]

Finally, a quick note on the I2C slave addresses of the MAX17205. There are two addresses used to communicate with this device, and which one is used depends on the memory range being accessed. Table 27 of the datasheet specifies that the slave address is 0x6C when accessing memory in the range of 0x000 – 0x0FF and the slave address is 0x16 when accessing memory in the range of 0x180 – 0x1FF [1]. However, the datasheet does not mention that these are 8-bit addresses rather than the more common 7-bit address. Essentially what that this means is that they have been “pre-shifted” to the left by one to make room for the read/write bit, as shown in Figure 2. Therefore, the 7-bit addresses are 0x36 and 0x0B respectively.


Figure 2: MAX17205 I2C Slave Address Clarification

Getting Around the Nonvolatile Memory Write Limit

When configuring the MAX17205, there are many settings to keep track of. Not only must the user figure out how to properly enable all the device’s features that are required by the application, they must also figure out how to disable those that are not. What’s more, the datasheet itself is rather scattered and, on occasion, self-contradictory (see page 78 [1]). It’s highly unlikely that during initial development, there will be no mistakes made on the first (or even 7th) attempt to properly configure the device. One should also keep in mind that the configuration may have to be modified in the future as the application changes or errors in the previous configuration come to light, making it necessary to keep a reserve of available nonvolatile memory updates. Clearly, what is needed is a way of prototyping a configuration before committing it to nonvolatile memory to avoid unnecessarily wasting one of the updates.

As it happens, this device includes a command that can be used exactly for this purpose. The Fuel Gauge Reset command (not to be confused with the Hardware Reset command) will reset the operation of the fuel gauge without restoring the nonvolatile memory block to shadow RAM. This way, the user can modify the values in shadow RAM as they would normally do to configure the device, but then execute a fuel gauge reset rather than a COPY NV BLOCK command. Since the shadow RAM will not be overwritten with the values stored in nonvolatile memory, the ModelGauge m5 registers will be initialized with the desired configuration values before the algorithm begins execution. The obvious drawback in this scenario is that the MAX17205 requires a time-consuming initialization procedure on startup and can no longer act as a standalone device.

Listing 1 shows the pseudocode for a simple initialization function that modifies several shadow RAM registers and finally resets the fuel gauge by writing 0x0001 to the Config2 register (0x0BB). Note the half second delay at the very end. This is used to accommodate the time required for the reset operation to complete (tPOR) as well as the 480ms required for the ModelGauge m5 output registers to become valid [1].

Listing 1: Example initialization pseudocode for MAX17205

void max17205_init( void )
{   
    // max17205_write_reg( addr, value )
    max17205_write_reg( 0x18E, 0x0E0B ); // nODSCTh
    max17205_write_reg( 0x18F, 0x4040 ); // nODSCCfg
    max17205_write_reg( 0x19E, 0x9658 ); // nVEmpty
    max17205_write_reg( 0x1B0, 0x0215 ); // nConfig
    max17205_write_reg( 0x1B3, 0x27D8 ); // nDesignCap
    max17205_write_reg( 0x1A5, 0x3454 ); // nFullCapNom
    max17205_write_reg( 0x1B5, 0x0C02 ); // nPackCfg
    max17205_write_reg( 0x1B8, 0x0930 ); // nNVCfg0
    max17205_write_reg( 0x1B9, 0x080E ); // nNVCfg1
    max17205_write_reg( 0x1C0, 0xD996 ); // nVAltTh
    max17205_write_reg( 0x1C1, 0x2305 ); // nTAlrtTh
    max17205_write_reg( 0x1C2, 0x6401 ); // nSAlrtTh
    max17205_write_reg( 0x1C3, 0x00BC ); // nIAlrtTh
 
    max17205_write_reg( 0x0BB, 0x0001 ); // fuel gauge reset
    wait( 0.5 );
}

Conclusion

Due to its many configuration options, the MAX17205 is a good candidate for a wide array of battery management applications. With all of these settings, however, the user needs to be able to test their configuration so they can be sure they are not wasting one of their limited nonvolatile memory updates. Luckily, the solution to this is very simple and gives the designer every opportunity to verify the correctness of their configuration.

References

[1] Maxim Integrated, “Stand-Alone ModelGauge m5 Fuel Gauge with SHA-256 Authentication,” MAX17201/MAX17205/MAX17211/MAX17215 datasheet , February 2016 [Revised August 2016].

2 Likes

Hello, may I ask if the initial configuration of the chip must configure these registers written in your example

The chip can be configured differently from what the example shows. The registers and values modified in the configuration will depend on the chosen battery and the final application.

Wow, thank you very much for your reply!May I ask if there are any basic registers that must be configured? I expect to read the voltage, current and capacity of the batterys.I am a student, and I am making a simple battery measuring device with this chip, but now I cannot read the voltage of the single battery.

In that case, I would start with the example I provided. In my application, I was reading voltage, current, and capacity. You’ll have to make some changes though as my application utilized two cells and their nominal capacity is likely not the same as your cell. Compare my register settings with the descriptions in the datasheet to see the changes I made from the default configuration.

As for basic registers, I would start with nConfig, nNVCfgx, and nPackCfg.

Here’s the complete code from my application if that helps. Sorry about the lacking comments.

/******************************************************************************/
/*                               Includes                                     */
/******************************************************************************/
#include "mbed.h"


/******************************************************************************/
/*                                Globals                                     */
/******************************************************************************/
I2C max17205( D7, D10 ); // PF_0 and PA11
Serial data_out( PB_6, PB_7, 9600 );
Ticker tick;
DigitalOut led( LED1 );

const int slave_addr = 0x6C;
const int nslave_addr = 0x16;


/******************************************************************************/
/*                           Function Prototypes                              */
/******************************************************************************/
int read_reg( int addr );
void write_reg( int addr, int value );


/******************************************************************************/
/*                       Interrupt Service Routines                           */
/******************************************************************************/
void wake( void )
{
    SCB->SCR &= ~( SCB_SCR_SLEEPONEXIT_Msk );
}


/******************************************************************************/
/*                           Function Definitions                             */
/******************************************************************************/
/*******************************************************************************
* Function:     main 
* Author:       Matt Mielke
* Description:      
* Date:         04/03/17
*******************************************************************************/
int main( void )
{
    float RepSOC; //, VCell;
    //int Current;
    char data_str[100];

    wait( 0.5 );
    write_reg( 0x18E, 0x0A05 ); // nODSCTh
    write_reg( 0x18F, 0x4040 ); // nODSCCfg
    write_reg( 0x19E, 0x9658 ); // nVEmpty
    write_reg( 0x1B0, 0x0215 ); // nConfig
    write_reg( 0x1B3, 0x3454 ); // nDesignCap
    write_reg( 0x1A5, 0x3454 ); // nFullCapNom
    write_reg( 0x1B5, 0x0C02 ); // nPackCfg
    write_reg( 0x1B8, 0x0930 ); // nNVCfg0
    write_reg( 0x1B9, 0x080E ); // nNVCfg1
    write_reg( 0x1C0, 0xD996 ); // nVAltTh
    write_reg( 0x1C1, 0x2305 ); // nTAlrtTh
    write_reg( 0x1C2, 0x6401 ); // nSAlrtTh
    write_reg( 0x1C3, 0x00BC ); // nIAlrtTh
    write_reg( 0x0BB, 0x0001 ); // fuel gauge reset
                
    wait( 0.5 );
    tick.attach( &wake, 5.0 );
    
    while ( 1 )
    {
        led = 1;
    
        RepSOC = read_reg( 0x006 ) / 256.0;
        //VCell = read_reg( 0x009 ) * 0.078125e-3;  
    
        //Current = read_reg( 0x00A );
        //if ( Current & 0x00008000 ) Current |= 0xFFFF0000;
        
        //sprintf( data_str, "%f, %f, %f\n\r", RepSOC, VCell, Current * 1.5625e-6 / 0.0197 );

        data_out.printf( "%03.1f\0", RepSOC );
        
        led = 0;
    
        SCB->SCR &= ~( SCB_SCR_SLEEPDEEP_Msk );
        SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;
        __WFI();        
    }
}


/*******************************************************************************
* Function:     read_reg 
* Author:       Matt Mielke
* Description:    This function utilizes the mbed I2C library to read the value
*               contained in a register on the MAX17205. It distinguishes 
*               between the volitile and non volitile address spaces. If an 
*               error occurs when writing the desired address to the device, the
*               write function will be repeaded until it succeeds. If the 
*               subsequent read operation fails, a value of -1 is returned.  
* Date:         04/03/17
*******************************************************************************/
int read_reg( int addr )
{
    char buffer[2] = {0};
    
    if ( addr & 0x100 )
    {
        addr &= 0xFF;
        while ( max17205.write( nslave_addr, (char*)&addr, 1 ) );
        if ( max17205.read( nslave_addr, buffer, 2 ) )
        {
            return -1;
        }
    }
    else
    {
        addr &= 0xFF;
        while ( max17205.write( slave_addr, (char*)&addr, 1 ) );
        if ( max17205.read( slave_addr, buffer, 2 ) )
        {
            return -1;
        }
    }
    
    return ( buffer[1] << 8 ) | buffer[0];
}


/*******************************************************************************
* Function:     write_reg 
* Author:       Matt Mielke
* Description:    This function utilizes the mbed I2C library to write to a 
*               register on the MAX17205. If the register address is in the non
*               volitile space, the non volitile address is used. The write 
*               function will repeat in a loop if it fails. 
* Date:         04/03/17
*******************************************************************************/
void write_reg( int addr, int value )
{
    char buffer[3] = {0};
    
    buffer[0] = addr & 0xFF;
    buffer[1] = value & 0xFF;
    buffer[2] = ( value >> 8 ) & 0xFF;
    
    if ( addr & 0x100 )
    {
        while ( max17205.write( nslave_addr, buffer, 3 ) );
    }
    else
    {
        while ( max17205.write( slave_addr, buffer, 3 ) );
    }
}
1 Like

OK, thank you very much for your reply.The max17205.read function and the max17205.write function have a distinction between the address of the general register and the address of the non-volatile register.

Hi!,

First of all, thank you a lot for submitting this information, It is the only forum where I found how to properly do the settings for this IC. I have just one question (hope someone could help me): Why do you write the address of the register as “addr & 0xFF” in the “write_reg” function?

Thank you in advance,

Luis

Hi @luis.colque.mi,

Welcome to the TechForum!

The bitwise operation addr & 0xFF explicitly writes the least significant byte of the int sized addr variable to the char sized buffer element (buffer[0]). The compiler would likely do this automatically when converting from int to char, but it’s safe to be unambiguous.

1 Like

HI!

Thank you very much for your reply. I totally agree with what you explained but what happens with the register address that has more than 8 bits long? for example, the register address 0x19E (nVEmpty) is equal to 110011110, and if you do 0x19E & 0xFF you will miss “the most significant bit”. That is not the case of the register address 0x0BB that has a byte long.

From the datasheet (page 26):

Register addresses are described throughout the document as 9-bit internal values from 000h to 1FFh. These addresses must be translated to 8-bit values for the MAX1720x (I2C).

For the MAX1720x, bits 1-8 represent the register address and bit 9 specifies which slave address to use (there is one volatile memory and another for nonvolatile memory).That’s the purpose of the if (addr & 0x100){} conditional. See Table 16 for the memory map…

1 Like

Thanks a lot for your help!

I am trying to save battery configuration using the above process with arduino, But its not working

I am trying to save battery configuration using the above process with arduino, But its not working.


#include <Wire.h>
#include "MAX17205.h"

#define confige 0x001d
#define confige2 0x00bb

#define nConfig 0x01B0
#define DesignCap 0x018
#define ststus2_reg 0x0B0
#define Lock_Register 0x07F
int target_read_reg ;


const int NV_i2c_addr = 0x0B;
const int MAX1720X_ADDR = 0x36;
//const int NV_i2c_addr = 0x16;
//const int MAX1720X_ADDR = 0x6c;

//const int NV_i2c_addr = 0x36;
//const int MAX1720X_ADDR = 0x0b;

uint16_t rem_times_value;
uint8_t dat[11]; // buffer need to be more than 11 number
const int MAX1720X_COMMAND_ADDR = 0x60; // Command register
const int MAX1720X_CONFIG2_ADDR = 0xbb; // Command register
uint16_t response = 0;
float response_float  = 0;

float Rsense;

uint16_t value;
typedef struct {
  float Soc;
  float RemCap;
  float CellVolt;
  float Cur;
  float TimeFull;
  float TimeEmpty;
  float AvgCur;
  float TempOut;
} Output; //Out put values

void setup() {
  delay(2000);
  Wire.begin();
  // put your setup code here, to run once:
  Serial.begin(115200); // Initializes serial port
  // Waits for serial port to connect. Needed for Leonardo only
  while ( !Serial ) ;
  Serial.println("POWER ON");
  get_DevName();

  WriteRegistor( 0x1B5, 0x3a02 ); // nPackCfg
  WriteRegistor( 0x0BB, 0x0001 ); // fuel gauge reset
  delay(1000);
  response = ReadRegistor (nPackCfg);
  response = ReadRegistor (PackCfg);
  while (1);
}
void loop{
}

uint16_t ReadRegistor(uint16_t reg)
{
  if (reg & 0x100)
  {
    //write to NV slave addr
    Serial.println("");
    Serial.println("I2C address= 0X" + String(NV_i2c_addr, HEX));
    Serial.println("Reading from register address 0X" + String(reg, HEX));
    Wire.beginTransmission(NV_i2c_addr);//01CF
    Wire.write(reg & 0xFF);//read_rsense Register addrs
    Wire.write(reg >> 8); //read_rsense Register addrs
    Wire.endTransmission(false);
    Wire.requestFrom(NV_i2c_addr, (int)2);
    uint16_t i2c_reply = Wire.read() | (Wire.read() << 8); // LSB or-ed with MSB
    Serial.println("Read Val 0X" + String(i2c_reply, HEX)); Serial.println(" ");
    return i2c_reply;
  }
  else//read to MAX1720X_ADDR regular i2c
  {
    //write to MAX1720X_ADDR slave addr
    Serial.println("");
    Serial.println("I2C address= 0X" + String(MAX1720X_ADDR, HEX));
    Serial.println("Reading from register 0X" + String(reg, HEX));
    Wire.beginTransmission(MAX1720X_ADDR);
    Wire.write(reg & 0xFF);
    Wire.write(reg >> 8);
    Wire.endTransmission(false);
    Wire.requestFrom(MAX1720X_ADDR, (int)2);
    uint16_t i2c_reply = Wire.read() | (Wire.read() << 8); // LSB or-ed with MSB
    Serial.println("Read Val 0X" + String(i2c_reply, HEX)); Serial.println(" ");
    return i2c_reply;
  }
}
void WriteRegistor(uint16_t reg, uint16_t value)
{
  if (reg & 0x100)
  {
    //    Serial.println("--------------------NON-Volatile register selected, First CONFIRM \"BALANCE NV WRITE CYCLES\"");
    Serial.println("");
    Serial.println("I2C address= 0X" + String(NV_i2c_addr, HEX));
    Serial.println("writing to Register Address 0X" + String(reg, HEX));
    Wire.beginTransmission(NV_i2c_addr);
    Wire.write(reg & 0xFF);
    Wire.write(reg >> 8);
    delay(10);
    Wire.write(value & 0xFF);
    Wire.write(value >> 8);
    Serial.println("writing val=0X" + String(value, HEX)); Serial.println(" ");
    //    delay(200);
    Wire.endTransmission();
  }
  else//write to MAX1720X_ADDR regular i2c
  {
    //write to MAX1720X_ADDR slave addr
    Serial.println("");
    Serial.println("I2C address= 0X" + String(MAX1720X_ADDR, HEX));
    Serial.println("writing to Register Address 0X" + String(reg, HEX));
    Wire.beginTransmission(MAX1720X_ADDR);
    Wire.write(reg & 0xFF);
    Wire.write(reg >> 8);
    delay(10);
    Wire.write(value & 0xFF);
    Wire.write(value >> 8);
    Serial.println("writing val=0X" + String(value, HEX)); Serial.println(" ");
    //    delay(200);
    Wire.endTransmission();
  }
}

void get_DevName()
{
  Wire.beginTransmission(MAX1720X_ADDR);
  Wire.write(0x021);
  Wire.endTransmission(false);
  Wire.requestFrom(MAX1720X_ADDR, (int)2);//
  uint16_t DevName = Wire.read() | (Wire.read() << 8); // LSB or-ed with MSB
  Serial.println("Reading DevName Register(021h)");//correct Decimal 4357        \\19082 wrong
  //  Serial.println("(HEX)=" + String(DevName, HEX));                             //correct HEX = 1105
  DevName = DevName & 0x000F;//mask the unwanted bits
  //  Serial.println("After Mask(HEX)=" + String(DevName, HEX));
  (DevName == 5) ? Serial.println("---------------Detected Fuel Guage is MAX17205----------") : \
  (DevName == 1) ? Serial.println("---------------Detected Fuel Guage is MAX17201----------") : \
  Serial.println("Failed to read correct DevName\n");
}

Serial monitor output

18:18:03.343 → POWER ON
18:18:03.343 → Reading DevName Register(021h)
18:18:03.343 → ---------------Detected Fuel Guage is MAX17205----------
18:18:03.343 →
18:18:03.343 → I2C address= 0Xb
18:18:03.343 → writing to Register Address 0X1b5
18:18:03.343 → writing val=0X3a02
18:18:03.343 →
18:18:03.343 →
18:18:03.343 → I2C address= 0X36
18:18:03.343 → writing to Register Address 0Xbb
18:18:03.343 → writing val=0X1
18:18:03.388 →
18:18:04.357 →
18:18:04.357 → I2C address= 0Xb
18:18:04.357 → Reading from register address 0X1b5
18:18:04.357 → Read Val 0X201
18:18:04.357 →
18:18:04.357 →
18:18:04.357 → I2C address= 0X36
18:18:04.357 → Reading from register 0Xbd
18:18:04.357 → Read Val 0X3a04
18:18:04.357 →

Welcome to the TechForum @salve.dnyaneshvar!

As stated on page 101 of the datasheet for both I2C write and I2C read:

The memory address is sent by the bus master as a single byte value immediately after the slave address.

This is what was done in the write_reg() and read_reg() functions in the code I posted.

To fix your code, simply remove the four lines which contain Wire.write(reg >> 8);

Hi, thank you for your reply.
My code problem is solved.
Issue was, while writing Multibyte value my code was writing only LSB byte.

Hi and thank you for the information that you provided. I am using MAX17320 connected to a microcontroller STM32F105. MAX17320 is similar to MAX17205.
datasheet for MAX17320 https://www.analog.com/media/en/technical-documentation/data-sheets/MAX17320.pdf
I am trying to read the value from the register DevName (021h) and using the slave address 0x6C. but I get the wrong value and I think it is because I did not configure the chip as you explained above. I use I2C communication bus and program in STM32CUbe IDE
my question is, did you unlock the write protection before configuring these registers?

Hello @alisuleimani433,

The MAX17205 does not have write protection so there was nothing for me to disable. That being said, I don’t believe you have to disable write protection or perform any chip configuration in order to read from the DevName register. The value of that register should never change. This sounds more like an issue of correctly performing an I2C read and interpreting the received bytes. If you are willing to supply your source code, I’d be happy to take a closer look…

1 Like

Hello @Matt_Mielke
Thank you for replying me. This is my entire code for the I2C. It seems that I can write to a register but when I try to read from a register I get the wrong value. My problem is that I do not get the correct value.
for example, I write the value 0x0006 to the nPackcfg (0x1B5) register with slave address 0x16 and try to read from the same register to see if I can get the value that I have written to it. The result is not the same. Here is my code:

 HAL_StatusTypeDef MAX17320_ConfigAddress(uint8_t dev_address1)
{
	HAL_StatusTypeDef ret;
     //nPackCfg
	uint16_t register_address = 0x1B5;
	uint16_t sendData = 0x0006;
	// write to the register nPackCfg for configuration
	ret = HAL_I2C_Mem_Write(&hi2c1, dev_address1, register_address, sizeof(register_address), &sendData, sizeof(sendData),HAL_MAX_DELAY);
		if(ret != HAL_OK)
		{
			return ret;
		}

	uint16_t tempData[2];
	// read from the register sDeviceName
	ret = HAL_I2C_Mem_Read(&hi2c1, dev_address1, register_address,sizeof(register_address), &tempData, sizeof(tempData), HAL_MAX_DELAY);
	if(ret != HAL_OK)
	{
		return ret;
	}
	return HAL_OK;

}
And here in side the while loop in main I call the function:

uint16_t dev_address1 = 0x16;
  while (1)
  {
	  MAX17320_ConfigAddress(dev_address1);
  }

The value that I get is 0x6B5 instead of 0x0006.

And Also when I try to read from the register devName(0x21) with slave address 0x6C I get I very strange value. In the datasheet it says that the value should be 0x4209. This is the code for how I try to read the devname register:

HAL_StatusTypeDef MAX30205_readTemp(uint8_t dev_address)
{
	HAL_StatusTypeDef ret;
	uint16_t tempData[2];
	// read from the register sDeviceName
	ret = HAL_I2C_Mem_Read(&hi2c1, dev_address, 0x21, 1, &tempData, sizeof(tempData), HAL_MAX_DELAY);
	if(ret != HAL_OK)
	{
		return ret;
	}
	return HAL_OK;
}

and here I call the function:

     uint16_t dev_address = 0x6C;
      while (1)
      {
    	  MAX30205_readTemp(dev_address);
      }

Here comes a screen shot when I debug my code for the MAX17320_ConfigAddress() function. I have marked with red ring to highlight the the reading value is not the same as what I wrote.


If you have time I can also set up a short digital meeting to show you my code and the hardware.
Sincerely
Ali

Hi Ali,

Let’s start with reading the DevName register. Try changing your third code block to the following and see what gets written to tempData.

HAL_StatusTypeDef MAX30205_readTemp(uint8_t dev_address)
{
	HAL_StatusTypeDef ret;
	uint8_t tempData[2];
	// read from the register sDeviceName
	ret = HAL_I2C_Mem_Read(&hi2c1, dev_address, 0x21, 1, tempData, sizeof(tempData), HAL_MAX_DELAY);
	if(ret != HAL_OK)
	{
		return ret;
	}
	return HAL_OK;
}

Hi @Matt_Mielke
Sorry to bother you.
When I read the register devName(0x21) I get the value 0x420A instead of 0x4209. I thought maybe I have a new version of the IC that I get the LSB as A instead of 9.
There are some other registers like sManfctrName (ox120) to check if the IC operates correctly. But the problem is that according to the datasheet, this registers use SBS not I2C and I do not know really how to use this registers.
Any hint for how to read this register ? I assume I can not use HAL_I2C_Mem_Read () function since it use SBS protocol not I2C.
greeting
ALi