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