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 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 static_assert(sizeof(Config) == sizeof(uint32_t), 72 "Ensure that the config struct fits in 32-bits"); 73 74 // The Inititor class provides an abstract interface used to configure and 75 // transmit data using a SPI bus. 76 class Initiator { 77 public: 78 virtual ~Initiator() = default; 79 80 // Configure the SPI bus to communicate with peripherals using a given set of 81 // properties, including the clock polarity, clock phase, bit-order, and 82 // bits-per-wrod. 83 // Returns OkStatus() on success, and implementation-specific values on 84 // failure. 85 virtual Status Configure(const Config& config) = 0; 86 87 // Perform a synchronous read/write operation on the SPI bus. Data from the 88 // `write_buffer` object is written to the bus, while the `read_buffer` is 89 // populated with incoming data on the bus. The operation will ensure that 90 // all requested data is written-to and read-from the bus. In the event the 91 // read buffer is smaller than the write buffer (or zero-size), any additional 92 // input bytes are discarded. In the event the write buffer is smaller than 93 // the read buffer (or zero size), the output is padded with 0-bits for the 94 // remainder of the transfer. 95 // Returns OkStatus() on success, and implementation-specific values on 96 // failure. 97 virtual Status WriteRead(ConstByteSpan write_buffer, 98 ByteSpan read_buffer) = 0; 99 }; 100 101 } // namespace pw::spi 102