1 // Copyright 2021 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 15 #pragma once 16 17 #include <cstdint> 18 #include <type_traits> 19 20 #include "pw_assert/assert.h" 21 #include "pw_bytes/span.h" 22 #include "pw_status/status.h" 23 24 namespace pw::spi { 25 26 // ClockPolarity is a configuration parameter that specifies whether a SPI 27 // bus clock signal is active low, or active high. 28 enum class ClockPolarity : uint8_t { 29 kActiveHigh, // Corresponds to CPOL = 0 30 kActiveLow, // Corresponds to CPOL = 1 31 }; 32 33 // ClockPhase is a configuration parameter that specifies whether the 34 // phase of the SPI bus clock is rising edge or falling edge. 35 enum class ClockPhase : uint8_t { 36 kRisingEdge, // Corresponds to CPHA = 0 37 kFallingEdge, // Corresponds to CPHA = 1 38 }; 39 40 // Configuration parameter, specifying the bit order for data clocked over the 41 // SPI bus; whether least-significant bit first, or most-significant bit first 42 enum class BitOrder : uint8_t { 43 kLsbFirst, 44 kMsbFirst, 45 }; 46 47 // Configuration object used to represent the number of bits in a SPI 48 // data word. Devices typically use 8-bit words, although values of 3-32 49 // are sometimes specified for bus-level optimizations. Values outside 50 // this range are considered an error. 51 class BitsPerWord { 52 public: BitsPerWord(uint8_t data_bits)53 constexpr BitsPerWord(uint8_t data_bits) : data_bits_(data_bits) { 54 PW_ASSERT(data_bits_ >= 3 && data_bits_ <= 32); 55 } 56 operator()57 constexpr uint8_t operator()() const { return data_bits_; } 58 59 private: 60 uint8_t data_bits_; 61 }; 62 63 // This struct contains the necessary configuration details required to 64 // initialize a SPI bus for communication with a target device. 65 struct Config { 66 ClockPolarity polarity; 67 ClockPhase phase; 68 BitsPerWord bits_per_word; 69 BitOrder bit_order; 70 71 constexpr bool operator==(const Config& rhs) const { 72 return polarity == rhs.polarity && phase == rhs.phase && 73 bits_per_word() == rhs.bits_per_word() && bit_order == rhs.bit_order; 74 } 75 76 constexpr bool operator!=(const Config& rhs) const { return !(*this == rhs); } 77 }; 78 static_assert(sizeof(Config) == sizeof(uint32_t), 79 "Ensure that the config struct fits in 32-bits"); 80 81 // The Initiator class provides an abstract interface used to configure and 82 // transmit data using a SPI bus. 83 class Initiator { 84 public: 85 virtual ~Initiator() = default; 86 87 // Configure the SPI bus to communicate with responders using a given set of 88 // properties, including the clock polarity, clock phase, bit-order, and 89 // bits-per-word. 90 // Returns OkStatus() on success, and implementation-specific values on 91 // failure. Configure(const Config & config)92 Status Configure(const Config& config) { return DoConfigure(config); } 93 94 // Perform a synchronous read/write operation on the SPI bus. Data from the 95 // `write_buffer` object is written to the bus, while the `read_buffer` is 96 // populated with incoming data on the bus. The operation will ensure that 97 // all requested data is written-to and read-from the bus. In the event the 98 // read buffer is smaller than the write buffer (or zero-size), any additional 99 // input bytes are discarded. In the event the write buffer is smaller than 100 // the read buffer (or zero size), the output is padded with 0-bits for the 101 // remainder of the transfer. 102 // Returns OkStatus() on success, and implementation-specific values on 103 // failure. WriteRead(ConstByteSpan write_buffer,ByteSpan read_buffer)104 Status WriteRead(ConstByteSpan write_buffer, ByteSpan read_buffer) { 105 return DoWriteRead(write_buffer, read_buffer); 106 } 107 108 private: 109 // Subclass API: 110 virtual Status DoConfigure(const Config& config) = 0; 111 virtual Status DoWriteRead(ConstByteSpan write_buffer, 112 ByteSpan read_buffer) = 0; 113 }; 114 115 } // namespace pw::spi 116