1 // Copyright 2023 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 #include "pw_spi_rp2040/initiator.h"
16
17 #include <algorithm>
18
19 #include "hardware/spi.h"
20 #include "pico/stdlib.h"
21 #include "pw_assert/check.h"
22 #include "pw_log/log.h"
23 #include "pw_status/try.h"
24
25 namespace pw::spi {
26
27 namespace {
28
GetBitOrder(BitOrder bit_order)29 constexpr spi_order_t GetBitOrder(BitOrder bit_order) {
30 switch (bit_order) {
31 case BitOrder::kLsbFirst:
32 return SPI_LSB_FIRST;
33 case BitOrder::kMsbFirst:
34 return SPI_MSB_FIRST;
35 default:
36 PW_CRASH("Unknown bit order");
37 }
38 }
39
GetPhase(ClockPhase phase)40 constexpr spi_cpha_t GetPhase(ClockPhase phase) {
41 switch (phase) {
42 case ClockPhase::kRisingEdge:
43 return SPI_CPHA_0;
44 case ClockPhase::kFallingEdge:
45 return SPI_CPHA_1;
46 default:
47 PW_CRASH("Unknown phase");
48 }
49 }
50
GetPolarity(ClockPolarity polarity)51 constexpr spi_cpol_t GetPolarity(ClockPolarity polarity) {
52 switch (polarity) {
53 case ClockPolarity::kActiveHigh:
54 return SPI_CPOL_0;
55 case ClockPolarity::kActiveLow:
56 return SPI_CPOL_1;
57 default:
58 PW_CRASH("Unknown polarity");
59 }
60 }
61
62 } // namespace
63
DoConfigure(const Config & config)64 Status Rp2040Initiator::DoConfigure(const Config& config) {
65 PW_ASSERT(config.bits_per_word() == 8);
66
67 spi_set_format(spi_,
68 config.bits_per_word(),
69 GetPolarity(config.polarity),
70 GetPhase(config.phase),
71 GetBitOrder(config.bit_order));
72
73 return OkStatus();
74 }
75
DoWriteRead(ConstByteSpan write_buffer,ByteSpan read_buffer)76 Status Rp2040Initiator::DoWriteRead(ConstByteSpan write_buffer,
77 ByteSpan read_buffer) {
78 if (write_buffer.empty() && !read_buffer.empty()) {
79 // Read only transaction.
80 spi_read_blocking(spi_,
81 /*repeated_tx_data=*/0,
82 reinterpret_cast<uint8_t*>(read_buffer.data()),
83 read_buffer.size());
84 } else if (!write_buffer.empty() && read_buffer.empty()) {
85 // Write only transaction.
86 spi_write_blocking(spi_,
87 reinterpret_cast<const uint8_t*>(write_buffer.data()),
88 write_buffer.size());
89 } else if (!write_buffer.empty() && !read_buffer.empty()) {
90 // Write & read transaction.
91 // Take the smallest as the size of transaction
92 auto transfer_size = write_buffer.size() < read_buffer.size()
93 ? write_buffer.size()
94 : read_buffer.size();
95 spi_write_read_blocking(
96 spi_,
97 reinterpret_cast<const uint8_t*>(write_buffer.data()),
98 reinterpret_cast<uint8_t*>(read_buffer.data()),
99 transfer_size);
100 } else {
101 return pw::Status::OutOfRange();
102 }
103
104 return OkStatus();
105 }
106
107 } // namespace pw::spi
108