1 // Copyright 2020 The Pigweed Authors
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
7 // https://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
18 #include "pw_bytes/span.h"
19 #include "pw_chrono/system_clock.h"
20 #include "pw_i2c/address.h"
21 #include "pw_status/status.h"
25 // Base driver interface for I2C initiating I2C transactions in a thread safe
26 // manner. Other documentation sources may call this style of interface an I2C
27 // "master", "central" or "controller".
29 // The Initiator is not required to support 10bit addressing. If only 7bit
30 // addressing is supported, the Initiator will assert when given an address
31 // which is out of 7bit address range.
33 // The implementer of this pure virtual interface is responsible for ensuring
34 // thread safety and enabling functionality such as initialization,
35 // configuration, enabling/disabling, unsticking SDA, and detecting device
36 // address registration collisions.
39 virtual ~Initiator() = default;
41 // Write bytes and then read bytes as either one atomic or two independent I2C
42 // transaction. If the I2C bus is a multi-initiator bus then the implementer
43 // MUST ensure it is a single atomic I2C transaction.
44 // The signal on the bus should appear as follows:
46 // START + I2C Address + WRITE(0) + TX_BUFFER_BYTES + STOP
48 // START + I2C Address + READ(1) + RX_BUFFER_BYTES + STOP
49 // 3A) Write + Read (atomic):
50 // START + I2C Address + WRITE(0) + TX_BUFFER_BYTES +
51 // START + I2C Address + READ(1) + RX_BUFFER_BYTES + STOP
52 // 3B) Write + Read (separate):
53 // START + I2C Address + WRITE(0) + TX_BUFFER_BYTES + STOP
54 // START + I2C Address + READ(1) + RX_BUFFER_BYTES + STOP
56 // The timeout defines the minimum duration one may block waiting for both
57 // exclusive bus access and the completion of the I2C transaction.
60 // The Address must be supported by the Initiator, i.e. do not use a 10
61 // address if the Initiator only supports 7 bit. This will assert.
65 // InvalidArgument - device_address is larger than the 10 bit address space.
66 // DeadlineExceeded - Was unable to acquire exclusive Initiator access
67 // and complete the I2C transaction in time.
68 // Unavailable - NACK condition occurred, meaning the addressed device did
69 // not respond or was unable to process the request.
70 // FailedPrecondition - The interface is not currently initialized and/or
72 Status WriteReadFor(Address device_address,
73 ConstByteSpan tx_buffer,
75 chrono::SystemClock::duration for_at_least) {
76 return DoWriteReadFor(device_address, tx_buffer, rx_buffer, for_at_least);
78 Status WriteReadFor(Address device_address,
79 const void* tx_buffer,
83 chrono::SystemClock::duration for_at_least) {
86 std::span(static_cast<const std::byte*>(tx_buffer), tx_size_bytes),
87 std::span(static_cast<std::byte*>(rx_buffer), rx_size_bytes),
91 // Write bytes. The signal on the bus should appear as follows:
92 // START + I2C Address + WRITE(0) + TX_BUFFER_BYTES + STOP
94 // The timeout defines the minimum duration one may block waiting for both
95 // exclusive bus access and the completion of the I2C transaction.
98 // The Address must be supported by the Initiator, i.e. do not use a 10
99 // address if the Initiator only supports 7 bit. This will assert.
103 // InvalidArgument - device_address is larger than the 10 bit address space.
104 // DeadlineExceeded - Was unable to acquire exclusive Initiator access
105 // and complete the I2C transaction in time.
106 // Unavailable - NACK condition occurred, meaning the addressed device did
107 // not respond or was unable to process the request.
108 // FailedPrecondition - The interface is not currently initialized and/or
110 Status WriteFor(Address device_address,
111 ConstByteSpan tx_buffer,
112 chrono::SystemClock::duration for_at_least) {
113 return WriteReadFor(device_address, tx_buffer, ByteSpan(), for_at_least);
115 Status WriteFor(Address device_address,
116 const void* tx_buffer,
117 size_t tx_size_bytes,
118 chrono::SystemClock::duration for_at_least) {
121 std::span(static_cast<const std::byte*>(tx_buffer), tx_size_bytes),
125 // Read bytes. The signal on the bus should appear as follows:
126 // START + I2C Address + READ(1) + RX_BUFFER_BYTES + STOP
128 // The timeout defines the minimum duration one may block waiting for both
129 // exclusive bus access and the completion of the I2C transaction.
132 // The Address must be supported by the Initiator, i.e. do not use a 10
133 // address if the Initiator only supports 7 bit. This will assert.
137 // InvalidArgument - device_address is larger than the 10 bit address space.
138 // DeadlineExceeded - Was unable to acquire exclusive Initiator access
139 // and complete the I2C transaction in time.
140 // Unavailable - NACK condition occurred, meaning the addressed device did
141 // not respond or was unable to process the request.
142 // FailedPrecondition - The interface is not currently initialized and/or
144 Status ReadFor(Address device_address,
146 chrono::SystemClock::duration for_at_least) {
148 device_address, ConstByteSpan(), rx_buffer, for_at_least);
150 Status ReadFor(Address device_address,
152 size_t rx_size_bytes,
153 chrono::SystemClock::duration for_at_least) {
154 return ReadFor(device_address,
155 std::span(static_cast<std::byte*>(rx_buffer), rx_size_bytes),
159 // Probes the device for an I2C ACK after only writing the address.
160 // This is done by attempting to read a single byte from the specified device.
162 // The timeout defines the minimum duration one may block waiting for both
163 // exclusive bus access and the completion of the I2C transaction.
166 // The Address must be supported by the Initiator, i.e. do not use a 10
167 // address if the Initiator only supports 7 bit. This will assert.
171 // InvalidArgument - device_address is larger than the 10 bit address space.
172 // DeadlineExceeded - Was unable to acquire exclusive Initiator access
173 // and complete the I2C transaction in time.
174 // Unavailable - NACK condition occurred, meaning the addressed device did
175 // not respond or was unable to process the request.
176 // FailedPrecondition - The interface is not currently initialized and/or
178 Status ProbeDeviceFor(Address device_address,
179 chrono::SystemClock::duration for_at_least) {
180 std::byte ignored_buffer[1] = {}; // Read a dummy byte to probe.
182 device_address, ConstByteSpan(), ignored_buffer, for_at_least);
186 virtual Status DoWriteReadFor(Address device_address,
187 ConstByteSpan tx_buffer,
189 chrono::SystemClock::duration for_at_least) = 0;
192 } // namespace pw::i2c