Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How does I2C support various types of slave devices? #12159

Closed
xiaotailang opened this issue Apr 16, 2024 · 3 comments · Fixed by #12166
Closed

How does I2C support various types of slave devices? #12159

xiaotailang opened this issue Apr 16, 2024 · 3 comments · Fixed by #12166

Comments

@xiaotailang
Copy link

I am interested in adding device drivers for I2C-based devices, such as G-sensors (accelerometers), RTCs, and the BH1750 light sensor, within the NuttX operating system. I have noticed existing drivers for devices like ADXL345, DS3231, and DS1307 in the nuttx/drivers directory, but upon examining the implementation of application-layer functions bound to open, write, and read, I find that the i2cdrvr_read and i2cdrvr_write functions lack concrete implementations. I have also seen an implementation for accessing the DS1307 via I2C in the context of STM32F4, where the process involves initializing the I2C bus and binding it to the nSH, although the corresponding i2cdrvr_read and i2cdrvr_write functions remain without specific implementation details. Thus, I am unsure how the DS1307 is being read from and written to within the nSH environment. The implementation supporting the DS1307 on STM32F4 is as follows:
int stm32_ds1307_init(void)
{
struct i2c_master_s *i2c;
static bool initialized = false;
int ret;

/* Have we already initialized? */

if (!initialized)
{
/* No.. Get the I2C bus driver */

  rtcinfo("Initialize I2C%d\n", DS1307_I2C_BUS);
  i2c = stm32_i2cbus_initialize(DS1307_I2C_BUS);
  if (!i2c)
    {
      rtcerr("ERROR: Failed to initialize I2C%d\n", DS1307_I2C_BUS);
      return -ENODEV;
    }

  /* Now bind the I2C interface to the DS1307 RTC driver */

  rtcinfo("Bind the DS1307 RTC driver to I2C%d\n", DS1307_I2C_BUS);
  ret = dsxxxx_rtc_initialize(i2c);
  if (ret < 0)
    {
      rtcerr("ERROR: Failed to bind I2C%d to the DS1307 RTC driver\n",
             DS1307_I2C_BUS);
      return -ENODEV;
    }

#ifdef CONFIG_I2C_DRIVER
/* Register the I2C to get the "nsh> i2c bus" command working */

  ret = i2c_register(i2c, DS1307_I2C_BUS);
  if (ret < 0)
    {
      rtcerr("ERROR: Failed to register I2C%d driver: %d\n", bus, ret);
      return -ENODEV;
    }

#endif

  /* Synchronize the system time to the RTC time */

  clock_synchronize(NULL);

  /* Now we are initialized */

  initialized = true;
}

return OK;
}

@acassis
Copy link
Contributor

acassis commented Apr 16, 2024

Hi @xiaotailang you don't need to do nothing special, just call look the examples inside boards/arm/stm32/common/src/

stm32_bh1750.c:  ret = bh1750fvi_register(devpath, i2c, BH1750FVI_I2C_ADDR);
stm32_bmp180.c:  ret = bmp180_register(devpath, i2c);
stm32_ina219.c:  ret = ina219_register(devpath, i2c, 0x40, 100000, 0x00);
stm32_lcd_backpack.c:  ret = pcf8574_lcd_backpack_register(devpath, i2c, &cfg);
stm32_lm75.c:  ret = lm75_register(devpath, i2c, 0x48);
stm32_mlx90614.c:  ret = mlx90614_register(devpath, i2c, MLX90614_ADDRESS);
stm32_nunchuck.c:  ret = nunchuck_register(devpath, i2c);
stm32_veml6070.c:  ret = veml6070_register(devpath, i2c, VEML6070_I2C_DATA_LSB_CMD_ADDR);

Just initialize the I2C Bus/Port as you saw:

i2c = stm32_i2cbus_initialize(I2C_BUS); /* Bus could be 1, 2 or 3 */

And them you just call the blablabladevicename_register() passing this i2c pointer, as you see in these files.

Actually this code to register the i2c_register(i2c, DS1307_I2C_BUS); is incorrect, because it is already done at stm32_bringup.c. So I will punish the guy who did it! (myself) Hehehe.

@acassis
Copy link
Contributor

acassis commented Apr 17, 2024

I submitted a PR #12166 to fix the i2c_register() at wrong place

@xiaotailang
Copy link
Author

Hi! @acassis Thank you very much for your answer. After examining the examples you provided, I noticed that their file_operations structures indeed implement corresponding read and write functions. Additionally, upon reviewing the ds1307 implementation in dsxxxx_rtc_initialize, I observed that it inherits from the implementation in driver/timer/ds3231.c. Within ds3231.c, I encountered the functions up_rtc_getdatetime and up_rtc_settime, which utilize I2C to interact with the RTC. In contrast, the file_operations for ds1302 do not provide specific implementations but instead rely on NuttX system's xx_rtc_lowerhalf.c to invoke up_rtc_getdatetime or up_rtc_settime.

This leads me to conclude that NuttX provides a generic management interface for RTC devices like the ds1302, such that there is no need to implement the read and write functions within the file_operations structure directly when calling i2c_register. Instead, the system utilizes a pre-established set of lower-level functions to handle the RTC interactions over I2C.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants