cancel
Showing results for 
Search instead for 
Did you mean: 

How to write 16bit register of i2c slave connected with STM32L031 master?

hbhim
Associate II

Hi,

I am writing a 16bit register 0x3f of i2c device connected at 0x09. After write, if I read the value of 0x3f register it is always '0'. I2C communication is working fine on device.

Below is a code.

#include "main.h"
#define I2C_ADDRESS        0x09<<1
 
#define I2C_TIMING      0x00B1112E /* 400 kHz with analog Filter ON, Rise Time 250ns, Fall Time 100ns */
 
I2C_HandleTypeDef I2cHandle;
 
uint8_t aTxBuffer[] = "00";
uint16_t aRxBuffer[1];
 
void SystemClock_Config(void);
static void Error_Handler(void);
uint16_t read_register(uint16_t);
void write_register(uint16_t, uint16_t);
 
uint16_t x = 0;
 
int main(void)
{
  GPIO_InitTypeDef  GPIO_InitStruct;
  HAL_Init();
  x = 50;
  
  SystemClock_Config();
 
  BSP_LED_Init(LED3);
 
  I2cHandle.Instance              = I2Cx;
  I2cHandle.Init.Timing           = I2C_TIMING;
  I2cHandle.Init.AddressingMode   = I2C_ADDRESSINGMODE_7BIT;
  I2cHandle.Init.DualAddressMode  = I2C_DUALADDRESS_DISABLE;
  I2cHandle.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
  I2cHandle.Init.GeneralCallMode  = I2C_GENERALCALL_DISABLE;
  I2cHandle.Init.NoStretchMode    = I2C_NOSTRETCH_DISABLE;  
  I2cHandle.Init.OwnAddress1      = I2C_ADDRESS;
  I2cHandle.Init.OwnAddress2      = 0xFF;
  
  if(HAL_I2C_Init(&I2cHandle) != HAL_OK)
  {
    Error_Handler();
  }
 
  HAL_I2CEx_ConfigAnalogFilter(&I2cHandle,I2C_ANALOGFILTER_ENABLE);
 
  HAL_Delay(1000);
 
  write_register(0x3f, 0xff);
  x  = read_register(0x3f);
 
  while (HAL_I2C_GetState(&I2cHandle) != HAL_I2C_STATE_READY)
  {
  } 
  
  while (1)
  {
  }
}
 
uint16_t read_register(uint16_t memAddress){
 
	uint16_t tmpData=0;
 
	do
	  {
		if(HAL_I2C_Mem_Read_DMA(&I2cHandle, (uint16_t)I2C_ADDRESS, memAddress, 2, (uint16_t *)aRxBuffer, 2) != HAL_OK)
	    {
	      Error_Handler();
	    }
 
		tmpData = *aRxBuffer;
 
	    while (HAL_I2C_GetState(&I2cHandle) != HAL_I2C_STATE_READY)
	    {
	    }
 
	  }
	  while(HAL_I2C_GetError(&I2cHandle) == HAL_I2C_ERROR_AF);
 
	return tmpData;
}
 
void write_register(uint16_t memAddress, uint16_t register_value){
	do
	  {
		if(HAL_I2C_Mem_Write_DMA(&I2cHandle, (uint16_t)I2C_ADDRESS, memAddress, 2, (uint8_t*)(&register_value),2) != HAL_OK)
	    {
	      Error_Handler();
	    }
 
	    while (HAL_I2C_GetState(&I2cHandle) != HAL_I2C_STATE_READY)
	    {
	    }
 
	  }
	  while(HAL_I2C_GetError(&I2cHandle) == HAL_I2C_ERROR_AF);
}
 
void SystemClock_Config(void)
{
  RCC_ClkInitTypeDef RCC_ClkInitStruct ={0};
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  
  __HAL_RCC_PWR_CLK_ENABLE();
  
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLSource   = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLState    = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLMUL      = RCC_PLL_MUL4;
  RCC_OscInitStruct.PLL.PLLDIV      = RCC_PLL_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct)!= HAL_OK)
  {
    while(1); 
  }
  
  RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;  
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;  
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1)!= HAL_OK)
  {
    while(1); 
  }
}
 
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *I2cHandle)
{
  BSP_LED_Toggle(LED3);
}
 
 
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *I2cHandle)
{
  /* Toggle LED3: Transfer in reception process is correct */
  BSP_LED_Toggle(LED3);
}
 
 
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *I2cHandle)
{
  if (HAL_I2C_GetError(I2cHandle) != HAL_I2C_ERROR_AF)
  {
    Error_Handler();
  }
}
 
static void Error_Handler(void)
{
  while(1)
  {    
    BSP_LED_Toggle(LED3); 
    HAL_Delay(1000);
  } 
}

1 ACCEPTED SOLUTION

Accepted Solutions

Able to get it working using below functions.

HAL_I2C_Mem_Write_DMA(&I2cHandle, (uint16_t)I2C_ADDRESS, memAddress, 1, (uint8_t*)(&register_value),2)

HAL_I2C_Mem_Read_DMA(&I2cHandle, (uint16_t)I2C_ADDRESS, memAddress, 1, (uint16_t *)aRxBuffer, 2)

and writing registers using write_register(0x3f, 0x00ff);

View solution in original post

4 REPLIES 4
AvaTar
Lead

The I2C bus knows only byte transfers.

And your code write_register(0x3f, 0xff); does write only one byte.

Check the specification/datasheet of your slave device. Registers greater than one byte are usually mapped to consecutive byte register addresses.

Writing is usually done by writing the target register address first, followed by writing the value, without stop/start.

And many I2C slave devices have an auto-increment write feature, i.e. follow-up bytes without interceding stop/start will be written to the next register(s).

Or you have to start a new write access, with an interceding stop + start condition, and write the next register address.

Slave device is having single memory address for each 2byte register. I am working with BD99954GW charging IC.

More details of slave is available at https://www.rohm.com/datasheet/BD99954GW/bd99954xxx-e

Section 8.2.1 "Write Word", page 20.

Start->SlaveWriteAddress->command_byte->LowByte->HighByte->End.

Not sure how to map this sequence to HAL code, I never used HAL/Cube.

The command bytes are listed in section 8.3.1.

SMBus is based in I2C, but not quite the same.

Able to get it working using below functions.

HAL_I2C_Mem_Write_DMA(&I2cHandle, (uint16_t)I2C_ADDRESS, memAddress, 1, (uint8_t*)(&register_value),2)

HAL_I2C_Mem_Read_DMA(&I2cHandle, (uint16_t)I2C_ADDRESS, memAddress, 1, (uint16_t *)aRxBuffer, 2)

and writing registers using write_register(0x3f, 0x00ff);