blob: cc826c234366dee99f7cec062c129e3043194dff [file] [log] [blame]
// Copyright 2021 The Pigweed Authors
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#pragma once
#include <cstdint>
#include <type_traits>
#include "pw_assert/assert.h"
#include "pw_bytes/span.h"
#include "pw_status/status.h"
namespace pw::spi {
// ClockPolarity is a configuration parameter that specifies whether a SPI
// bus clock signal is active low, or active high.
enum class ClockPolarity : uint8_t {
kActiveHigh, // Corresponds to CPOL = 0
kActiveLow, // Corresponds to CPOL = 1
// ClockPhase is a configuration parameter that specifies whether the
// phase of the SPI bus clock is rising edge or falling edge.
enum class ClockPhase : uint8_t {
kRisingEdge, // Corresponds to CPHA = 0
kFallingEdge, // Corresponds to CPHA = 1
// Configuration parameter, specifying the bit order for data clocked over the
// SPI bus; whether least-significant bit first, or most-significant bit first
enum class BitOrder : uint8_t {
// Configuration object used to represent the number of bits in a SPI
// data word. Devices typically use 8-bit words, although values of 3-32
// are sometimes specified for bus-level optimizations. Values outside
// this range are considered an error.
class BitsPerWord {
constexpr BitsPerWord(uint8_t data_bits) : data_bits_(data_bits) {
PW_ASSERT(data_bits_ >= 3 && data_bits_ <= 32);
uint8_t operator()() const { return data_bits_; }
uint8_t data_bits_;
// This struct contains the necessary configuration details required to
// initialize a SPI bus for communication with a target device.
struct Config {
ClockPolarity polarity;
ClockPhase phase;
BitsPerWord bits_per_word;
BitOrder bit_order;
static_assert(sizeof(Config) == sizeof(uint32_t),
"Ensure that the config struct fits in 32-bits");
// The Inititor class provides an abstract interface used to configure and
// transmit data using a SPI bus.
class Initiator {
virtual ~Initiator() = default;
// Configure the SPI bus to communicate with peripherals using a given set of
// properties, including the clock polarity, clock phase, bit-order, and
// bits-per-wrod.
// Returns OkStatus() on success, and implementation-specific values on
// failure.
virtual Status Configure(const Config& config) = 0;
// Perform a synchronous read/write operation on the SPI bus. Data from the
// `write_buffer` object is written to the bus, while the `read_buffer` is
// populated with incoming data on the bus. The operation will ensure that
// all requested data is written-to and read-from the bus. In the event the
// read buffer is smaller than the write buffer (or zero-size), any additional
// input bytes are discarded. In the event the write buffer is smaller than
// the read buffer (or zero size), the output is padded with 0-bits for the
// remainder of the transfer.
// Returns OkStatus() on success, and implementation-specific values on
// failure.
virtual Status WriteRead(ConstByteSpan write_buffer,
ByteSpan read_buffer) = 0;
} // namespace pw::spi