// 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 #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(read_buffer.data()), read_buffer.size()); } else if (!write_buffer.empty() && read_buffer.empty()) { // Write only transaction. spi_write_blocking(spi_, reinterpret_cast(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(write_buffer.data()), reinterpret_cast(read_buffer.data()), transfer_size); } else { return pw::Status::OutOfRange(); } return OkStatus(); } } // namespace pw::spi