blob: 892b2326ed8aa68fddac5915cc5497fbaae751fb [file] [log] [blame]
// Copyright 2022 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_stm32cube/initiator.h"
#include <algorithm>
#include "pw_log/log.h"
#include "pw_status/try.h"
#include "stm32cube/stm32cube.h"
namespace pw::spi {
namespace {
constexpr uint32_t kTimeout = 10000;
constexpr Status ConvertStatus(HAL_StatusTypeDef status) {
switch (status) {
case HAL_OK:
return OkStatus();
case HAL_ERROR:
return Status::Internal();
case HAL_BUSY:
return Status::Unavailable();
case HAL_TIMEOUT:
return Status::DeadlineExceeded();
}
return Status::NotFound(); // Unreachable.
}
uint32_t GetDataSize(BitsPerWord bits_per_word) {
if (bits_per_word() == 8) {
return SPI_DATASIZE_8BIT;
} else if (bits_per_word() == 16) {
return SPI_DATASIZE_16BIT;
}
PW_UNREACHABLE;
return SPI_DATASIZE_8BIT;
}
constexpr uint32_t GetBitOrder(BitOrder bit_order) {
switch (bit_order) {
case BitOrder::kLsbFirst:
return SPI_FIRSTBIT_LSB;
case BitOrder::kMsbFirst:
return SPI_FIRSTBIT_MSB;
}
PW_UNREACHABLE;
return SPI_FIRSTBIT_MSB;
}
constexpr uint32_t GetPhase(ClockPhase phase) {
switch (phase) {
case ClockPhase::kFallingEdge:
return SPI_PHASE_1EDGE;
case ClockPhase::kRisingEdge:
return SPI_PHASE_2EDGE;
}
PW_UNREACHABLE;
return SPI_PHASE_1EDGE;
}
constexpr uint32_t GetPolarity(ClockPolarity polarity) {
switch (polarity) {
case ClockPolarity::kActiveHigh:
return SPI_POLARITY_HIGH;
case ClockPolarity::kActiveLow:
return SPI_POLARITY_LOW;
}
PW_UNREACHABLE;
return SPI_POLARITY_HIGH;
}
} // namespace
Stm32CubeInitiator::Stm32CubeInitiator()
: spi_handle{.Instance = SPI5,
.Init{.Mode = SPI_MODE_MASTER,
.Direction = SPI_DIRECTION_2LINES,
.DataSize = SPI_DATASIZE_8BIT,
.CLKPolarity = SPI_POLARITY_LOW,
.CLKPhase = SPI_PHASE_1EDGE,
.NSS = SPI_NSS_SOFT,
.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2,
.FirstBit = SPI_FIRSTBIT_MSB,
.TIMode = SPI_TIMODE_DISABLE,
.CRCCalculation = SPI_CRCCALCULATION_DISABLE,
.CRCPolynomial = 7}} {}
Stm32CubeInitiator::~Stm32CubeInitiator() = default;
Status Stm32CubeInitiator::LazyInit() {
if (initialized)
return init_status;
init_status = InitSPI();
initialized = true;
PW_LOG_INFO("Stm32CubeInitiator::LazyInit: %s", init_status.str());
return init_status;
}
Status Stm32CubeInitiator::InitSPI() {
auto s = HAL_SPI_Init(&spi_handle);
auto status = ConvertStatus(s);
PW_LOG_INFO("HAL_SPI_Init =>: %s", status.str());
return status;
}
Status Stm32CubeInitiator::Configure(const Config& config) {
spi_handle.Init.DataSize = GetDataSize(config.bits_per_word);
spi_handle.Init.FirstBit = GetBitOrder(config.bit_order);
spi_handle.Init.CLKPhase = GetPhase(config.phase);
spi_handle.Init.CLKPolarity = GetPolarity(config.polarity);
PW_TRY(LazyInit());
return OkStatus();
}
Status Stm32CubeInitiator::WriteRead(ConstByteSpan write_buffer,
ByteSpan read_buffer) {
PW_TRY(LazyInit());
HAL_StatusTypeDef status;
if (!write_buffer.empty()) {
if (!read_buffer.empty()) {
// TODO(cmumford): Not yet conforming to the WriteRead contract.
uint16_t size = std::min(write_buffer.size(), read_buffer.size());
status = HAL_SPI_TransmitReceive(
&spi_handle,
reinterpret_cast<uint8_t*>(
const_cast<std::byte*>(write_buffer.data())),
reinterpret_cast<uint8_t*>(read_buffer.data()),
size,
kTimeout);
} else {
status =
HAL_SPI_Transmit(&spi_handle,
reinterpret_cast<uint8_t*>(
const_cast<std::byte*>(write_buffer.data())),
write_buffer.size(),
kTimeout);
if (status != HAL_OK) {
PW_LOG_ERROR("Stm32CubeInitiator::WriteRead: write:%ld B, s:%s",
write_buffer.size(),
ConvertStatus(status).str());
}
}
} else {
status = HAL_SPI_Receive(&spi_handle,
reinterpret_cast<uint8_t*>(read_buffer.data()),
read_buffer.size(),
kTimeout);
}
return ConvertStatus(status);
}
} // namespace pw::spi