1 // Copyright 2020 The Pigweed Authors 2 // 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 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 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 13 // the License. 14 #pragma once 15 16 #include <cstdint> 17 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" 22 23 namespace pw::i2c { 24 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". 28 // 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. 32 // 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. 37 class Initiator { 38 public: 39 virtual ~Initiator() = default; 40 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: 45 // 1) Write Only: 46 // START + I2C Address + WRITE(0) + TX_BUFFER_BYTES + STOP 47 // 2) Read Only: 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 55 // 56 // The timeout defines the minimum duration one may block waiting for both 57 // exclusive bus access and the completion of the I2C transaction. 58 // 59 // Preconditions: 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. 62 // 63 // Returns: 64 // Ok - Success. 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 71 // enabled. WriteReadFor(Address device_address,ConstByteSpan tx_buffer,ByteSpan rx_buffer,chrono::SystemClock::duration for_at_least)72 Status WriteReadFor(Address device_address, 73 ConstByteSpan tx_buffer, 74 ByteSpan rx_buffer, 75 chrono::SystemClock::duration for_at_least) { 76 return DoWriteReadFor(device_address, tx_buffer, rx_buffer, for_at_least); 77 } WriteReadFor(Address device_address,const void * tx_buffer,size_t tx_size_bytes,void * rx_buffer,size_t rx_size_bytes,chrono::SystemClock::duration for_at_least)78 Status WriteReadFor(Address device_address, 79 const void* tx_buffer, 80 size_t tx_size_bytes, 81 void* rx_buffer, 82 size_t rx_size_bytes, 83 chrono::SystemClock::duration for_at_least) { 84 return WriteReadFor( 85 device_address, 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), 88 for_at_least); 89 } 90 91 // Write bytes. The signal on the bus should appear as follows: 92 // START + I2C Address + WRITE(0) + TX_BUFFER_BYTES + STOP 93 // 94 // The timeout defines the minimum duration one may block waiting for both 95 // exclusive bus access and the completion of the I2C transaction. 96 // 97 // Preconditions: 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. 100 // 101 // Returns: 102 // Ok - Success. 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 109 // enabled. WriteFor(Address device_address,ConstByteSpan tx_buffer,chrono::SystemClock::duration for_at_least)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); 114 } WriteFor(Address device_address,const void * tx_buffer,size_t tx_size_bytes,chrono::SystemClock::duration 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) { 119 return WriteFor( 120 device_address, 121 std::span(static_cast<const std::byte*>(tx_buffer), tx_size_bytes), 122 for_at_least); 123 } 124 125 // Read bytes. The signal on the bus should appear as follows: 126 // START + I2C Address + READ(1) + RX_BUFFER_BYTES + STOP 127 // 128 // The timeout defines the minimum duration one may block waiting for both 129 // exclusive bus access and the completion of the I2C transaction. 130 // 131 // Preconditions: 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. 134 // 135 // Returns: 136 // Ok - Success. 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 143 // enabled. ReadFor(Address device_address,ByteSpan rx_buffer,chrono::SystemClock::duration for_at_least)144 Status ReadFor(Address device_address, 145 ByteSpan rx_buffer, 146 chrono::SystemClock::duration for_at_least) { 147 return WriteReadFor( 148 device_address, ConstByteSpan(), rx_buffer, for_at_least); 149 } ReadFor(Address device_address,void * rx_buffer,size_t rx_size_bytes,chrono::SystemClock::duration for_at_least)150 Status ReadFor(Address device_address, 151 void* rx_buffer, 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), 156 for_at_least); 157 } 158 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. 161 // 162 // The timeout defines the minimum duration one may block waiting for both 163 // exclusive bus access and the completion of the I2C transaction. 164 // 165 // Preconditions: 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. 168 // 169 // Returns: 170 // Ok - Success. 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 177 // enabled. ProbeDeviceFor(Address device_address,chrono::SystemClock::duration for_at_least)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. 181 return WriteReadFor( 182 device_address, ConstByteSpan(), ignored_buffer, for_at_least); 183 } 184 185 private: 186 virtual Status DoWriteReadFor(Address device_address, 187 ConstByteSpan tx_buffer, 188 ByteSpan rx_buffer, 189 chrono::SystemClock::duration for_at_least) = 0; 190 }; 191 192 } // namespace pw::i2c 193