xref: /aosp_15_r20/external/pigweed/pw_i2c/guides.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1.. _module-pw_i2c-quickstart-and-guides:
2
3=====================
4Quickstart and guides
5=====================
6.. pigweed-module-subpage::
7   :name: pw_i2c
8
9.. _module-pw_i2c-quickstart:
10
11----------
12Quickstart
13----------
14.. tab-set::
15
16   .. tab-item:: Bazel
17
18      Depend on the ``pw_i2c`` API and an appropriate implementation of the
19      API like ``pw_i2c_linux``. See :ref:`module-pw_i2c-impl` for the
20      list of existing implementations and to learn how to create your own.
21
22      .. code-block:: python
23
24         cc_library(
25           # ...
26           deps = [
27             # ...
28             "@pigweed//pw_i2c:address",
29             "@pigweed//pw_i2c:device",
30             # ...
31           ] + select({
32             "@platforms//os:linux": [
33               "@pigweed//pw_i2c_linux:initiator",
34             ],
35             "//conditions:default": [
36               # Fake example of a custom implementation.
37               "//lib/pw_i2c_my_device:initiator",
38             ],
39           }),
40         )
41
42      .. note::
43
44         This assumes that your Bazel ``WORKSPACE`` has a `repository
45         <https://bazel.build/concepts/build-ref#repositories>`_ named
46         ``@pigweed`` that points to the upstream Pigweed repository.
47
48      If creating your own implementation, depend on the virtual interface:
49
50      .. code-block:: python
51
52         cc_library(
53           name = "initiator",
54           srcs = ["initiator.cc"],
55           hdrs = ["initiator.h"],
56           deps = ["@pigweed//pw_i2c:initiator"],
57         )
58
59Write some C++ code to interact with an I2C device:
60
61.. include:: ../pw_i2c_rp2040/docs.rst
62   :start-after: .. pw_i2c_rp2040-example-start
63   :end-before: .. pw_i2c_rp2040-example-end
64
65.. _module-pw_i2c-guides:
66
67------
68Guides
69------
70
71.. _module-pw_i2c-guides-mock:
72
73Mock I2C transactions
74=====================
75See the example in :cpp:class:`pw::i2c::MockInitiator`.
76
77.. _module-pw_i2c-guides-registerdevice:
78
79Configure and read an I2C device's registers
80============================================
81.. code-block:: c++
82
83   #include <chrono>
84   #include <cstddef>
85   #include <cstdint>
86
87   #include "pw_bytes/bit.h"
88   #include "pw_i2c/address.h"
89   #include "pw_i2c/register_device.h"
90   #include "pw_log/log.h"
91   #include "pw_status/status.h"
92
93   using ::pw::Status;
94   using namespace std::chrono_literals;
95
96   // Search for `pi4ioe5v6416` in the Kudzu codebase to see real usage of
97   // pw::i2c::RegisterDevice
98   namespace pw::pi4ioe5v6416 {
99
100   namespace {
101
102   constexpr pw::i2c::Address kAddress = pw::i2c::Address::SevenBit<0x20>();
103   enum Register : uint32_t {
104     InputPort0 = 0x0,
105     ConfigPort0 = 0x6,
106     PullUpDownEnablePort0 = 0x46,
107     PullUpDownSelectionPort0 = 0x48,
108   };
109
110   }  // namespace
111
112   // This particular example instantiates `pw::i2c::RegisterDevice`
113   // as part of a higher-level general "device" interface.
114   // See //lib/pi4ioe5v6416/public/pi4ioe5v6416/device.h in Kudzu.
115   Device::Device(pw::i2c::Initiator& initiator)
116       : initiator_(initiator),
117         register_device_(initiator,
118                          kAddress,
119                          endian::little,
120                          pw::i2c::RegisterAddressSize::k1Byte) {}
121
122   Status Device::Enable() {
123     // Set port 0 as inputs for buttons (1=input)
124     device_.WriteRegister8(Register::ConfigPort0,
125                            0xff,
126                            pw::chrono::SystemClock::for_at_least(10ms));
127     // Select pullup resistors for button input (1=pullup)
128     device_.WriteRegister8(Register::PullUpDownSelectionPort0,
129                            0xff,
130                            pw::chrono::SystemClock::for_at_least(10ms));
131     // Enable pullup/down resistors for button input (1=enable)
132     device_.WriteRegister8(Register::PullUpDownEnablePort0,
133                            0xff,
134                            pw::chrono::SystemClock::for_at_least(10ms));
135     return OkStatus();
136   }
137
138   pw::Result<uint8_t> Device::ReadPort0() {
139     return device_.ReadRegister8(Register::InputPort0,
140                                  pw::chrono::SystemClock::for_at_least(10ms));
141   }
142
143   }  // namespace pw::pi4ioe5v6416
144
145The code example above was adapted from :ref:`docs-kudzu`. See the following
146files for real ``pw::i2c::RegisterDevice`` usage:
147
148* `//lib/pi4ioe5v6416/device.cc <https://pigweed.googlesource.com/pigweed/kudzu/+/refs/heads/main/lib/pi4ioe5v6416/device.cc>`_
149* `//lib/pi4ioe5v6416/public/pi4ioe5v6416/device.h <https://pigweed.googlesource.com/pigweed/kudzu/+/refs/heads/main/lib/pi4ioe5v6416/public/pi4ioe5v6416/device.h>`_
150
151.. _module-pw_i2c-guides-rpc:
152
153Access an I2C device's registers over RPC
154=========================================
155.. TODO: b/331292234 - Make this content less confusing and more helpful.
156
157:cpp:class:`pw::i2c::I2cService` enables accessing an I2C device's registers
158over RPC.
159
160Using :ref:`module-pw_console`, invoke the service to perform an I2C read:
161
162.. code-block:: python
163
164   # Read register `0x0e` from the device at `0x22`.
165   device.rpcs.pw.i2c.I2c.I2cRead(
166       bus_index=0,
167       target_address=0x22,
168       register_address=b'\x0e',
169       read_size=1
170   )
171
172For responders that support 4-byte register width, you can specify the register
173address like this:
174
175.. code-block:: python
176
177   device.rpcs.pw.i2c.I2c.I2cRead(
178       bus_index=0,
179       target_address=<address>,
180       register_address=b'\x00\x00\x00\x00',
181       read_size=4
182   )
183
184To perform an I2C write:
185
186.. code-block:: python
187
188   device.rpcs.pw.i2c.I2c.I2cWrite(
189       bus_index=0,
190       target_address=0x22,
191       register_address=b'\x0e',
192       value=b'\xbc'
193   )
194
195Multi-byte writes can also be specified with the bytes fields for
196``register_address`` and ``value``.
197
198I2C responders that require multi-byte access may expect a specific endianness.
199The order of bytes specified in the bytes field will match the order of bytes
200sent or received on the bus. The maximum supported value for multi-byte access
201is 4 bytes.
202