cancel
Showing results for 
Search instead for 
Did you mean: 

Read/Write specific register value on I2C

hbhim
Associate II

Hi,

I am using STM32L031K6 MCU and SW4STM32 IDE for development. I want to read/write specific register value of i2c slave device from MCU(i2c master)

Below is a code I am using.

#include "main.h"
 
#define I2C_ADDRESS        0x3c
#define MASTER_BOARD
#define I2C_TIMING      0x00B1112E 
 
I2C_HandleTypeDef I2cHandle;
 
uint8_t aTxBuffer[] = "ff";
uint8_t aRxBuffer[4];
 
void SystemClock_Config(void);
static uint16_t Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength);
static void Error_Handler(void);
 
int main(void)
{
  GPIO_InitTypeDef  GPIO_InitStruct;
  HAL_Init();
  SystemClock_Config();
  BSP_LED_Init(LED3);
 
  I2cHandle.Instance             = I2Cx;
  I2cHandle.Init.Timing          = I2C_TIMING;
  I2cHandle.Init.OwnAddress1     = I2C_ADDRESS;
  I2cHandle.Init.AddressingMode  = I2C_ADDRESSINGMODE_7BIT;
  I2cHandle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  I2cHandle.Init.OwnAddress2     = 0xFF;
  I2cHandle.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
  I2cHandle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  I2cHandle.Init.NoStretchMode   = I2C_NOSTRETCH_DISABLE;  
  
  if(HAL_I2C_Init(&I2cHandle) == HAL_ERROR)
  {
    Error_Handler();
  }
 
  
 HAL_I2CEx_ConfigAnalogFilter(&I2cHandle,I2C_ANALOGFILTER_ENABLE);
  do
  {
    if(HAL_I2C_Mem_Read(&I2cHandle, (uint16_t)I2C_ADDRESS, (uint16_t)0x00, I2C_MEMADD_SIZE_8BIT, (uint8_t *)aRxBuffer, 1, 10) != HAL_OK)
    {
      Error_Handler();
    }
    while (HAL_I2C_GetState(&I2cHandle) != HAL_I2C_STATE_READY)
    {
    }
  }
  while(HAL_I2C_GetError(&I2cHandle) == HAL_I2C_ERROR_AF);
 
  HAL_Delay(1000);
  while (1)
  {
  }
}
 
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)
  {
    /* Initialization Error */
    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)
  {
    /* Initialization Error */
    while(1); 
  }
}
 
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *I2cHandle)
{
  BSP_LED_Toggle(LED3);
}
 
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *I2cHandle)
{
  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);
    }
}

HAL_I2C_Mem_Read is not returning HAL_OK and starts blinking LED3 from Error_Handler().

Please advice, thank you!

11 REPLIES 11
S.Ma
Principal

Not clear. Is the STM32 a master or a slave? If master talking to a mems, the mcu own address should be unique from other devices. If master, start with gpio sw bit bang i2c emulation to validate the hw and system, then activate the Hw I2c peripheral. If the Mcu should behave as slave, no comments.

hbhim
Associate II

MCU is a master device. There is only once slave connected on i2c bus.

S.Ma
Principal

I2cHandle.Init.OwnAddress1 = I2C_ADDRESS;

replace by

I2cHandle.Init.OwnAddress1 = 0xAA; // an unused address

And check if this makes a difference

Mon2
Senior III

Try,

//  Actual I2C address to use is 0x3c = 0011 1100 << 1 = 0111 1000
I2cHandle.Init.OwnAddress1 = 0x78; 

I2cHandle.Init.OwnAddress1 = 0x78; // that is your I2C address of 0x3c = 0011 1100 << 1 = 0111 1000

also,

  if(HAL_I2C_Mem_Read(&I2cHandle, (uint16_t)I2C_ADDRESS, (uint16_t)0x00, I2C_MEMADD_SIZE_8BIT, (uint8_t *)aRxBuffer, 1, 10) != HAL_OK)

The 0x00 is the register address you will be R/W from I2C slave.

hbhim
Associate II

Thank you for the answer. Tried with 0x78 I2C address, but no luck. Found same behaviour.

Hi. Meant to say to use:

#define I2C_ADDRESS        0x78

Is that what you tested?

Q1: Did you apply the required pull-up resistors onto your I2C port pins? Confirm this as they are mandatory. The value is not critical but often the values are 2k2 to 10k for the pull-up on SCL and SDA port pins to +3v3. This is because I2C is an open drain architecture, meaning that there is a logic low definition but no logic high. So the pull-up resistors are required else will not work correctly.

Q2: What is the I2C widget you are using? What does the datasheet report as the I2C address?

Q3: In your code, where is the error being raised? Comment out line 44 and see if you still get the error handler being called. That is, perhaps the error being raised is somewhere else.

Is that what you tested?

-> Yes I have tested with I2C address 0x78.

Did you apply the required pull-up resistors onto your I2C port pins?

-> Slave device is having pull up resister of 4.7k value. I have probed the SDA and SCL line and both are high (3.3v)

In your code, where is the error being raised? Comment out line 44 and see if you still get the error handler being called.

-> Debug output stuck in while loop between line no 46 to 50. Debug shows that I2C_WaitOnTXISFlagUntilTimeout callback is returning HAL_ERROR.

Thank you!

Try this suggestion:

Rework your code a bit to perform a loop on the I2C address so that the range is 00..7Fh - once the slave ACKs back, stop the looping.

Check your wiring and confirm that your I2C slave is powered correctly; I2C address of the slave is as you have noted.

Using almost the same routines on a STM32F4 with success for the past few days. Code was generated by CubeMX 5.0.0 tool. My hardware I2C address is 0x2C but needed to pass a value of 0x58 (ie. 0010 1100 << 1 = 0101 1000 to the ST routines). Working well and confirmed with the Beagle I2C bus analyzer.

Confirm that you indeed have SCL to SCL, SDA to SDA and common ground in your setup.

Connection of SCL, SDA and ground is okay. I will try to loop i2c address and update.

Thank you for the help.