blob: 8918b6364ee7b60584efabf6c2db9b819d7a758e [file] [log] [blame]
// Copyright 2023 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
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// 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.
#include "pw_spi_rp2040/initiator.h"
#include <algorithm>
#include "hardware/spi.h"
#include "pico/stdlib.h"
#include "pw_assert/check.h"
#include "pw_log/log.h"
#include "pw_status/try.h"
namespace pw::spi {
namespace {
constexpr spi_order_t GetBitOrder(BitOrder bit_order) {
switch (bit_order) {
case BitOrder::kLsbFirst:
return SPI_LSB_FIRST;
case BitOrder::kMsbFirst:
return SPI_MSB_FIRST;
default:
PW_CRASH("Unknown bit order");
}
}
constexpr spi_cpha_t GetPhase(ClockPhase phase) {
switch (phase) {
case ClockPhase::kRisingEdge:
return SPI_CPHA_0;
case ClockPhase::kFallingEdge:
return SPI_CPHA_1;
default:
PW_CRASH("Unknown phase");
}
}
constexpr spi_cpol_t GetPolarity(ClockPolarity polarity) {
switch (polarity) {
case ClockPolarity::kActiveHigh:
return SPI_CPOL_0;
case ClockPolarity::kActiveLow:
return SPI_CPOL_1;
default:
PW_CRASH("Unknown polarity");
}
}
} // namespace
Status Rp2040Initiator::DoConfigure(const Config& config) {
PW_ASSERT(config.bits_per_word() == 8);
spi_set_format(spi_,
config.bits_per_word(),
GetPolarity(config.polarity),
GetPhase(config.phase),
GetBitOrder(config.bit_order));
return OkStatus();
}
Status Rp2040Initiator::DoWriteRead(ConstByteSpan write_buffer,
ByteSpan read_buffer) {
if (write_buffer.empty() && !read_buffer.empty()) {
// Read only transaction.
spi_read_blocking(spi_,
/*repeated_tx_data=*/0,
reinterpret_cast<uint8_t*>(read_buffer.data()),
read_buffer.size());
} else if (!write_buffer.empty() && read_buffer.empty()) {
// Write only transaction.
spi_write_blocking(spi_,
reinterpret_cast<const uint8_t*>(write_buffer.data()),
write_buffer.size());
} else if (!write_buffer.empty() && !read_buffer.empty()) {
// Write & read transaction.
// Take the smallest as the size of transaction
auto transfer_size = write_buffer.size() < read_buffer.size()
? write_buffer.size()
: read_buffer.size();
spi_write_read_blocking(
spi_,
reinterpret_cast<const uint8_t*>(write_buffer.data()),
reinterpret_cast<uint8_t*>(read_buffer.data()),
transfer_size);
} else {
return pw::Status::OutOfRange();
}
return OkStatus();
}
} // namespace pw::spi