匿名
未登录
登录
百问网嵌入式Linux wiki
搜索
查看“I2C overview”的源代码
来自百问网嵌入式Linux wiki
名字空间
页面
讨论
更多
更多
页面选项
Read
查看源代码
历史
←
I2C overview
因为以下原因,您没有权限编辑本页:
您所请求的操作仅限于该用户组的用户使用:
用户
您可以查看与复制此页面的源代码。
本文提供有关I2C系统以及如何插入I2C STM32驱动程序的基本信息。 ==Framework purpose== This article aims to explain how to use I2C and more accurately: * how to activate I2C interface on a Linux® BSP * how to access I2C from kernel space * how to access I2C from user space. This article describes Linux<sup>®</sup> I<sup>2</sup>C<ref name="More about I2C">http://www.i2c-bus.org/</ref> interface in '''master''' and '''slave''' modes. An introduction to I<sup>2</sup>C<ref name="I2C introduction">https://bootlin.com/doc/training/linux-kernel/</ref> is proposed through this external resource. For a '''slave''' interface description, see '''slave-interface'''<ref>{{CodeSource | Linux kernel | Documentation/i2c/slave-interface}} slave interface description</ref>.<br /> ==System overview== I<sup>2</sup>C is an acronym for the “Inter-IC” bus, a simple bus protocol which is widely used where low data rate communications suffice.<br /> I2C is the acronym for the microprocessor I<sup>2</sup>C peripheral interface. Around the microprocessor device, the user can add many I<sup>2</sup>C external devices to create a custom board. Each external device can be accessed through the I2C from the user space or the kernel space. {{ImageMap| Image: i2c-overview-new.png {{!}} frame {{!}} center {{!}} Implementation architecture rect 430 114 548 157 [[I2C overview#i2c-tools | I2C Tools]] rect 641 113 759 156 [[I2C overview#Application | Application ]] circle 489 183 10 [[I2C overview#libi2c | I2C Library]] rect 430 205 548 248 [[I2C overview#i2c-tools | I2C Tools]] circle 489 309 10 [[I2C overview#User_space_application | User Space Application]] rect 312 332 430 375 [[I2C overview#Board_peripheral_drivers | Board peripheral drivers]] rect 548 332 666 375 [[I2C overview#Board_peripheral_drivers | Board peripheral drivers]] rect 747 363 865 406 [[I2C overview#Board_peripheral_drivers | Board peripheral drivers]] rect 361 406 615 452 [[I2C overview#i2c-core | I2C core engine]] circle 489 408 10 [[I2C overview#Kernel_space_peripheral_driver | Kernel space peripheral driver]] rect 430 469 548 512 [[I2C overview#i2c-stm32 | STM32 I2C driver]] rect 430 550 548 593 [[I2C_overview#STM32_I2C_internal_peripheral_controller | STM32 I2C peripheral]] rect 746 550 863 593 [[I2C_overview#STM32_I2C_internal_peripheral_controller | STM32 I2C peripheral]] rect 312 642 430 687 [[I2C_overview#Board_external_I2C_devices | Board peripheral]] rect 548 642 666 687 [[I2C_overview#Board_external_I2C_devices | Board peripheral]] rect 747 642 865 687 [[I2C_overview#Board_external_I2C_devices | Board peripheral]] }} ===Component description=== ====Board external I<sup>2</sup>C devices==== * Slave devices X are physical devices (connected to STM32 via I<sup>2</sup>C bus) that behave as Slave with respect to STM32. <br/> STM32 remains the master on the I<sup>2</sup>C bus. * Master devices X are physical devices (connected to STM32 via I<sup>2</sup>C bus) that behave as Master with respect to STM32. <br/>STM32 behaves as a Slave in this case on the I<sup>2</sup>C bus. ====STM32 I2C internal peripheral controller==== It corresponds to STM32 I2C adapter that handles communications with any external device connected on the same bus. <br/>It manages Slave devices (if any) and behaves as Slave if an external Master is connected. STM32 microprocessor devices usually embed several instances of the [[I2C internal peripheral]] allowing to manage multiple I2C buses. A driver is provided that pilots the hardware. ====i2c-stm32==== The internal STM32 I2C controller driver offers ST I2C internal peripheral controller abstraction layer to i2c-core-base.<br/> It defines all I2C transfer method algorithms to be used by I2C Core base, this includes I2C and SMBus<ref name="More about SMBus">https://www.i2c-bus.org/smbus/</ref> transfers API, Register/Unregister slave API and functionality check.<br/> Even if I2C Core can emulate SMBus protocol throughout standard I2C messages, all SMBus functions are implemented within the driver. ====i2c-core==== This is the brain of the communication: it instantiates and manages all buses and peripherals. * '''{{Highlight|i2c-core}}''' as stated by its name, this is the I2C core engine but it is also in charge of parsing device tree entries for both adapter and/or devices * '''{{Highlight|i2c-core-smbus}}''' deals with all SMBus related API. * '''{{Highlight|i2c-core-slave}}''' manages I2C devices acting as slaves running in STM32. * '''{{Highlight|i2c-smbus}}''' handles specific protocol SMBus Alert. (SMBus host notification handled by I2C core base) ====Board peripheral drivers==== This layer represents all drivers associated to physical peripherals.<br/> A peripheral driver can be compiled as a kernel module or directly into the kernel (aka built-in). ====i2c-dev==== i2c-dev is the interface between the user and the peripheral. It is a kernel driver offering I2C bus access to user space application using this dev-interface API. See examples [[I2C overview#API_description|API Description]]. ====i2c-tools==== [[I2C_i2c-tools | I2C Tools]] package provides: * shell commands to access I2C with SMBus protocol via i2c-dev * library to use SMBus functions into a user space application All those functions are described in this smbus-protocol API.<br/> '''Note''' : some peripherals can work without SMBus protocol. ====Application==== An application can control all peripherals using different methods offered by [[I2C_i2c-tools | I2C Tools]], libI2C ([[I2C_i2c-tools|I2C Tools]]), i2c-dev. ===API description=== ====libi2c==== I2C tools<ref name="I2C tools">https://i2c.wiki.kernel.org/index.php/I2C_Tools</ref> package offers a set of shell commands using mostly SMBus protocols to access I2C and an API to develop an application (libi2c).<br/> All tools and libi2c rely on SMBus API but [[I2C_i2c-tools#I2C_Transfer| i2ctransfer]] does not since it relies on standard I2C protocol.<br/> Tools and libi2c access SMBus and I2C API through out '''devfs''' read/write/ioctl call.<br/><br/> The SMBus protocols constitute a subset of the data transfer formats defined in the I<sup>2</sup>C specification. <br/> I2C peripherals that do not comply to these protocols cannot be accessed by standard methods as defined in the SMBus specification. <br/> See external references for further details on '''I<sup>2</sup>C'''<ref name="I2C summary">{{CodeSource | Linux kernel | Documentation/i2c/summary}} I2C and SMBus summary</ref> and '''SMBus protocol'''<ref name="SMBus protocol">{{CodeSource | Linux kernel | Documentation/i2c/smbus-protocol}} SMBus protocol summary</ref>. libi2c API mimics ''SMBus protocol''<ref name="SMBus protocol">{{CodeSource | Linux kernel | Documentation/i2c/smbus-protocol}} SMBus protocol summary</ref> but at user space level. <br/> Same API can be found in this library as in ''SMBus protocol''<ref name="SMBus protocol">{{CodeSource | Linux kernel | Documentation/i2c/smbus-protocol}} SMBus protocol summary</ref>. All SMBus API are duplicated here with the exception of specific SMBus protocol API like SMBus Host Notify and SMBus Alert. ====User space application==== [[#user_space_application| User space application]] is using a kernel driver (i2c-dev) which offers I2C access through devfs.<br /> '''Supported system calls : '''open(), close(), read(), write(), ioctl(), llseek(), release().<br /> {| |+ Supported ioctls commands |- !Constant !Description |- |I2C_SLAVE/I2C_SLAVE_FORCE |Sets slave address for read/write operations |- |I2C_FUNCS |Gets bus functionalities |- |I2C_TENBIT |10bits address support |- |I2C_RDWR |Combined R/W transfer (one STOP only) |- |I2C_SMBUS |Perform an SMBus transfer instead of standard I<sup>2</sup>C |} The above commands are the main ones (more are defined in the framework): see '''dev-interface API'''<ref name="dev-interface API">{{CodeSource | Linux kernel | Documentation/i2c/dev-interface}} dev-interface API</ref> for complete list. ====Kernel space peripheral driver==== [[#Kernel_space_driver| Kernel space peripheral driver]] accesses both I<sup>2</sup>C and SMBus devices and uses following '''I2C core API'''<ref name="I2C core API">https://www.kernel.org/doc/html/latest/driver-api/i2c.html</ref> ==Configuration== ===Kernel configuration=== Activate I2C in kernel configuration with Linux Menuconfig tool: [[Menuconfig or how to configure kernel]]. [x] Device Drivers [x] I2C support [x] I2C device interface [ ] I2C Hardware Bus support [x] STMicroelectronics STM32F7 I2C support This can be done manually in your kernel: CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_STM32F7=y If software needs SMBus specific protocols like SMBus Alert protocol and the SMBus Host Notify protocol, then add: [x] Device Drivers [x] I2C support [x] I2C device interface [ ] Autoselect pertinent helper modules [x] SMBus-specific protocols [ ] I2C Hardware Bus support [x] STMicroelectronics STM32F7 I2C support This can be done manually in your kernel: CONFIG_I2C_SMBUS=y ===Device tree configuration=== Please refer to [[I2C device tree configuration]]. ==How to use the framework== This section describes how to use the framework to access I2C peripherals. ===i2c-tools package=== Using [[I2C_i2c-tools | I2C Tools]] in user space with shell commands based on the '''SMBus API protocol'''<ref name="SMBus protocol">{{CodeSource | Linux kernel | Documentation/i2c/smbus-protocol}} SMBus protocol summary</ref> makes it easy to access I2C quickly without the need to write any code.<br /> '''Use case :''' a lot of shell commands allow detection of I2C bus and access to I2C peripherals by SMBus protocol. The package includes a library in order to use SMBus protocol into a C program.<br /> Full explanation is available via this [[I2C_i2c-tools| link]]. [[File:i2c-tools-overview.png|800px|center|link=|Using i2c-tools overview]] === User space application === Allows to develop an application using the i2c-dev kernel driver in user space with this '''device interface'''<ref name="dev-interface API">{{CodeSource | Linux kernel | Documentation/i2c/dev-interface}} dev-interface API</ref>.<br /> '''Use case :''' by loading i2c-dev module, user can access I2C through the '''/dev''' interface. Access to I2C can be done very easily with functions open(), ioctl(), read(), write() and close(). If the peripheral is compatible, SMBus protocol access is also possible using the [[I2C_i2c-tools | I2C Tools]] library.<br /> [[File:i2c-dev-overview.png|800px|center|link=|Using i2c-dev overview]] === Kernel space driver === Allows to develop a driver compiled into the kernel or inserted as a module using this '''I2C core API'''<ref name="I2C core API"/><br /> The Linux kernel provides example about how to write an I2C client driver.<ref>https://www.kernel.org/doc/html/latest/i2c/writing-clients.html</ref><br /> '''Use case''' : control I2C peripheral with a specific driver inside the kernel space. The driver initializes all parameters while system is booting and creates an access to the peripheral data through sysfs for example.<br /> [[File:i2c-driver-overview.png|800 px|center|link=|Using driver i2c overview]] ===Board description=== To instantiate a peripheral, several methods exist: see '''instantiating devices'''<ref ="instantiating-devices">{{CodeSource | Linux kernel | Documentation/i2c/instantiating-devices}} How to instantiate I2C devices</ref> for more details. <br/> The below information focuses on '''device tree''', '''sysfs''' and '''Application Code'''. ==== Device tree ==== The device tree is a description of the hardware that is used by the kernel to know which devices are connected. In order to add a slave device on an I2C bus, complete the device tree with the information related to the new device.<br /> '''Example :''' with an EEPROM <syntaxhighlight lang="c" line highlight="10-14"> &i2c4 { status = "okay"; i2c-scl-rising-time-ns = <185>; i2c-scl-falling-time-ns = <20>; dmas = <&mdma1 36 0x0 0x40008 0x0 0x0 0>, <&mdma1 37 0x0 0x40002 0x0 0x0 0>; dma-names = "rx", "tx"; eeprom@50 { compatible = "at,24c256"; pagesize = <64>; reg = <0x50>; }; }; </syntaxhighlight> The EEPROM is now instantiated on the bus i2c-X (X depends on how many adapters are probed at runtime) at address 0x50 and it is compatible with the driver registered with the same property.<br/> Please note the driver specifies a SCL rising/falling time as input.<br/> Please refer to [[I2C device tree configuration]] for proper configuration and explanation. Be aware the I2C specification reserves a range of addresses for special purposes, see '''slave addressing'''<ref name="slave addressing">http://www.totalphase.com/support/articles/200349176-7-bit-8-bit-and-10-bit-I2C-Slave-Addressing Slave addressing</ref>.<br /> The below figure shows the relation between the device tree and how it is used :<br /> [[File:i2c-overview-dt.png|840 px|center|link=|relation between device tree and kernel]] ====sysfs==== Through sysfs, i2c-core offers the possibility to instantiate and remove a peripheral: <br /><br /> Add a peripheral "myPeripheralName" attached to the bus x at the address 0xAA<br /> '''Note''' that the field "myPeripheralName" should have the same name as the compatible driver string so that they match one another. <pre> echo myPeripheralName 0xAA > i2c-x/new_device </pre> Remove a peripheral attached to the bus x at the address 0xAA <pre> echo 0xAA > i2c-x/delete_device </pre> Into each driver directory ('''/sys/bus/i2c/drivers/at24/''' for the EEPROM peripheral example), it is possible to:<br /> bind a peripheral with a driver <pre> echo 3-0050 > bind </pre> unbind a peripheral with a driver <pre> echo 3-0050 > unbind </pre> ==== Application code ==== Here is a minimalist code to register a new slave device onto I2C adapter without Device Tree usage. <syntaxhighlight lang="c" line highlight="4-6,18,20"> #include <linux/i2c.h> /* Create a device with slave address <0x42> */ static struct i2c_board_info stm32_i2c_test_board_info = { I2C_BOARD_INFO("i2c_test07", 0x42); }; /* Module define creation skipped */ static int __init i2c_test_probe(void) { struct i2c_adapter *adap; struct i2c_client *client; /* Get I2C controller */ adap = i2c_get_adapter(i); /* Build new devices */ client = i2c_new_device(adap,&stm32_i2c_test_board_info); } </syntaxhighlight> ==How to trace and debug the framework == In Linux<sup>®</sup> kernel, there are standard ways to debug and monitor I2C. The debug can take place at different levels: hardware and software. ===How to trace=== ====Dynamic trace==== Detailed dynamic trace is available here [[How to use the kernel dynamic debug]]<br/> {{Board$}} echo "file i2c-* +p" > /sys/kernel/debug/dynamic_debug/control This command enables all traces related to I2C core and drivers at runtime.<br/><br/> Nonetheless at [[Menuconfig or how to configure kernel | Linux® Kernel menu configuration]] level, it provides the granularity for debugging: Core and/or Bus.<br/> Device Drivers -> [*] I2C support -> [*] I2C Core debugging messages [*] I2C Bus debugging messages * I2C Core debugging messages (CONFIG_I2C_DEBUG_CORE)<br> Compile I2C engine with DEBUG flag. * I2C Bus debugging messages (CONFIG_I2C_DEBUG_BUS)<br> Compile I2C drivers with DEBUG flag. Having both '''I2C Core''' and '''I2C Bus''' debugging messages is equivalent to using the above dynamic debug command: the dmesg output will be the same. ====Bus snooping==== Bus snooping is really convenient for viewing I2C protocol and see what has been exchanged between the STM32 and the devices.<br/> As this debug feature uses [[Ftrace]], please refer to the [[Ftrace]] article for enabling it. In order to access to events for I2C bus snooping, the following kernel configuration is necessary: Kernel hacking -> [*] Tracers -> [*] Trace process context switches and events Depending on the protocol being used, it is necessary to enable i2c and/or smbus tracers as follow: echo 1 > /sys/kernel/debug/tracing/events/i2c/enable echo 1 > /sys/kernel/debug/tracing/events/smbus/enable Then tracing is enabled using the following command: echo 1 > /sys/kernel/debug/tracing/tracing_on After a transaction, trace can be read by looking at the trace file: cat /sys/kernel/debug/tracing/trace Here is part of the output, and how it looks like when using ''i2cdetect'' command on the i2c-0 bus: ... smbus_write: i2c-0 a=003 f=0000 c=0 QUICK l=0 [] ... smbus_result: i2c-0 a=003 f=0000 c=0 QUICK wr res=-6 ... smbus_write: i2c-0 a=004 f=0000 c=0 QUICK l=0 [] ... smbus_result: i2c-0 a=004 f=0000 c=0 QUICK wr res=-6 {{Info|Notice that i2cdetect, i2cget/i2cput, i2cdump are doing smbus protocol based transactions.}} On the contrary, below output shows the result of a transaction done in I2C protocol mode: ... i2c_write: i2c-1 #0 a=042 f=0000 l=1 [45] ... i2c_result: i2c-1 n=1 ret=1 ... i2c_write: i2c-2 #0 a=020 f=0000 l=1 [45] ... i2c_result: i2c-2 n=1 ret=1 The utilization of traces of I2C bus is well described here '''I2C bus snooping'''<ref name="I2C bus snooping">https://linuxtv.org/wiki/index.php/Bus_snooping/sniffing#i2c I2C Bus Snooping</ref>. ===How to debug=== ====Detect I2C configuration==== =====sysfs===== When a peripheral is instantiated, i2c-core and the kernel export different files through sysfs :<br /> '''/sys/class/i2c-adapter/i2c-x''' shows all instantiated I2C buses with 'x' being the I2C bus number.<br /> '''/sys/bus/i2c/devices''' lists all instantiated peripherals. For example, there is a directory named '''3-0050''' that corresponds to the EEPROM peripheral at address 0x50 on bus number 3.<br /> '''/sys/bus/i2c/drivers''' lists all instantiated drivers. Directory named '''at24/''' is the driver of EEPROM.<br /> <pre> /sys/bus/i2c/devices/3-0050/ / / / /i2c-3/3-0050/ / /drivers/at24/3-0050/ </pre> <pre> /sys/class/i2c-adapter/i2c-0/ /i2c-1/ /i2c-2/ /i2c-3/3-0050/ /i2c-4/ /i2c-5/ </pre> ====devfs==== If i2c-dev driver is compiled into the kernel, the directory '''dev''' contains all I2C bus names numbered i2c-0 to i2c-n. <pre> /dev/i2c-0 /i2c-1 /i2c-2 /i2c-3 /i2c-4 /i2c-n </pre> ====i2c-tools==== Check all I2C instantiated adapters: {{Board$}}i2cdetect -l See [[I2C_i2c-tools| i2c-tools]] for full description. ==Source code location== * I2C Framework driver is in {{CodeSource | Linux kernel | drivers/i2c drivers/i2c}} * I2C STM32 Driver is in {{CodeSource | Linux kernel | drivers/i2c/busses/i2c-stm32f7.c}} * User API for I2C bus is in {{CodeSource | Linux kernel | include/uapi/linux/i2c.h}} and I2C dev is {{CodeSource | Linux kernel | include/uapi/linux/i2c-dev.h}}. ==To go further== Bootlin has written a nice walkthrough article: ''Building a Linux system for the STM32MP1: connecting an I2C sensor''<ref name="Building a Linux system for the STM32MP1: connecting an I2C sensor">https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-connecting-an-i2c-sensor/</ref> ==References== <references />
该页面使用的模板:
模板:Board$
(
查看源代码
)
模板:CodeSource
(
查看源代码
)
模板:Highlight
(
查看源代码
)
模板:ImageMap
(
查看源代码
)
模板:Info
(
查看源代码
)
模板:STDarkBlue
(
查看源代码
)
返回至
I2C overview
。
导航
导航
WIKI首页
官方店铺
资料下载
交流社区
所有页面
所有产品
MPU-Linux开发板
MCU-单片机开发板
Linux开发系列视频
单片机开发系列视频
所有模块配件
Wiki工具
Wiki工具
特殊页面
页面工具
页面工具
用户页面工具
更多
链入页面
相关更改
页面信息
页面日志