From 3041499ce0ca0d341e531c6896990156a31c5142 Mon Sep 17 00:00:00 2001 From: Henrik Stickann <4376396-Mithradir@users.noreply.gitlab.com> Date: Tue, 19 Apr 2022 23:22:04 +0200 Subject: [PATCH] Implement changes to SPI interfaces --- include/sta/hal/spi.hpp | 64 +++++++++++++++++--- src/hal/spi.cpp | 127 ++++++++++++++++++++++++++-------------- 2 files changed, 140 insertions(+), 51 deletions(-) diff --git a/include/sta/hal/spi.hpp b/include/sta/hal/spi.hpp index dcc6280..7034368 100644 --- a/include/sta/hal/spi.hpp +++ b/include/sta/hal/spi.hpp @@ -23,6 +23,23 @@ namespace sta { + /** + * @brief Get peripheral clock frequency. + * + * @return Clock frequency + */ + using HalSpiPCLKFreqFn = uint32_t (*)(); + + /** + * @brief Info related to HAL SPI interface. + */ + struct HalSpiInterfaceInfo + { + SPI_HandleTypeDef * handle; /**< Interface handle */ + HalSpiPCLKFreqFn getPCLKFreq; /**< Getter for peripheral clock used by interface */ + }; + + /** * @brief Implementation of `SpiInterface` interface using HAL. */ @@ -30,24 +47,23 @@ namespace sta { public: /** - * @param handle SPI handle + * @param info SPI interface info * @param mutex Mutex object for managing access. Pass nullptr for no access control */ - HalSpiInterface(SPI_HandleTypeDef * handle, Mutex * mutex = nullptr); + HalSpiInterface(const HalSpiInterfaceInfo & info, Mutex * mutex = nullptr); void transfer(uint8_t value) override; + void transfer16(uint16_t value) override; void transfer(const uint8_t * buffer, size_t size) override; void transfer(const uint8_t * txBuffer, uint8_t * rxBuffer, size_t size) override; - void transfer16(uint16_t value) override; - - void fill(uint8_t value, size_t count) override; - void fill32(uint32_t value, size_t count) override; - void receive(uint8_t * buffer, size_t size) override; + void fill(uint8_t value, size_t count) override; + + const SpiSettings & settings() const override; private: - SPI_HandleTypeDef * handle_; /**< SPI handle */ + HalSpiInterfaceInfo info_; /**< SPI interface info */ }; @@ -72,6 +88,38 @@ namespace sta } // namespace sta + +/** + * @brief Get function returning PCLK frequency. + * + * @param n Index of peripheral clock + */ +#define STA_HAL_GET_PCLK_FREQ_FN(n) HAL_RCC_GetPCLK ## n ## Freq + +/** + * @brief Get SPI interface info struct. + * + * Check the MCUs Reference Manual RCC register documentation to see which + * peripheral clock is used. + * + * @param n Index of SPI interface (e.g. 2 for SPI2) + * @param pclk Index of peripheral clock used by SPI interface + */ +#define STA_HAL_SPI_INFO_MANUAL(n, pclk) sta::HalSpiInterfaceInfo{&hspi ## n, STA_HAL_GET_PCLK_FREQ_FN(pclk)} + +/** + * @brief Get SPI interface info struct. + * + * Requires STA_HAL_SPI_n_PCLK_IDX set to idx of PCLK used by the interface. + * + * Check the MCUs Reference Manual RCC register documentation to see which + * peripheral clock is used. + * + * @param n Index of SPI interface (e.g. 2 for SPI2) + */ +#define STA_HAL_SPI_INFO(n) STA_HAL_SPI_INFO_MANUAL(n, STA_HAL_SPI_ ## n ## _PCLK_IDX) + + #endif // STA_HAL_SPI_ENABLE #endif // STA_HAL_SPI_HPP diff --git a/src/hal/spi.cpp b/src/hal/spi.cpp index 45b2b88..708a5c2 100644 --- a/src/hal/spi.cpp +++ b/src/hal/spi.cpp @@ -3,12 +3,26 @@ #ifdef STA_HAL_SPI_ENABLE #include +#include #include +#ifdef STA_MCU_LITTLE_ENDIAN +# define STA_HAL_SPI_REVERSE_BIT_ORDER SpiBitOrder::MSB +#elif STA_MCU_BIG_ENDIAN +# define STA_HAL_SPI_REVERSE_BIT_ORDER SpiBitOrder::LSB +#else // !STA_MCU_LITTLE_ENDIAN && !STA_MCU_BIG_ENDIAN +# ifdef STA_HAL_SPI_REVERSE_BIT_ORDER +# warning "Internal STA_HAL_SPI_REVERSE_BIT_ORDER macro manually defined! Better now what you are doing!!!" +# else // !STA_HAL_SPI_REVERSE_BIT_ORDER +# error "Unknown endian-ness. Define STA_MCU_LITTLE_ENDIAN or STA_MCU_BIG_ENDIAN in " +# endif // !STA_HAL_SPI_REVERSE_BIT_ORDER +#endif // !STA_MCU_LITTLE_ENDIAN && !STA_MCU_BIG_ENDIAN + + namespace sta { - static SpiSettings getHalSpiSettings(SPI_HandleTypeDef * handle) + static SpiSettings getHalSpiSettings(SPI_HandleTypeDef * handle, uint32_t pclkFreq) { SpiSettings settings; @@ -16,43 +30,35 @@ namespace sta (handle->Init.CLKPolarity == SPI_POLARITY_LOW) ? SpiClkPolarity::LOW : SpiClkPolarity::HIGH, (handle->Init.CLKPhase == SPI_PHASE_1EDGE) ? SpiClkPhase::EDGE_1 : SpiClkPhase::EDGE_2 ); - settings.dataSize = (handle->Init.DataSize == SPI_DATASIZE_8BIT) ? SpiDataSize::BIT_8 : SpiDataSize::BIT_16; + settings.dataSize = (handle->Init.DataSize == SPI_DATASIZE_8BIT) ? SpiDataSize::SIZE_8 : SpiDataSize::SIZE_16; settings.bitOrder = (handle->Init.FirstBit == SPI_FIRSTBIT_MSB) ? SpiBitOrder::MSB : SpiBitOrder::LSB; uint32_t prescaler = 1; switch (handle->Init.BaudRatePrescaler) { case SPI_BAUDRATEPRESCALER_2: - settings.baudRatePrescaler = SpiBaudRatePrescaler::BRP_2; prescaler = 2; break; case SPI_BAUDRATEPRESCALER_4: - settings.baudRatePrescaler = SpiBaudRatePrescaler::BRP_4; - prescaler = 2; + prescaler = 4; break; case SPI_BAUDRATEPRESCALER_8: - settings.baudRatePrescaler = SpiBaudRatePrescaler::BRP_8; - prescaler = 2; + prescaler = 8; break; case SPI_BAUDRATEPRESCALER_16: - settings.baudRatePrescaler = SpiBaudRatePrescaler::BRP_16; - prescaler = 2; + prescaler = 16; break; case SPI_BAUDRATEPRESCALER_32: - settings.baudRatePrescaler = SpiBaudRatePrescaler::BRP_32; - prescaler = 2; + prescaler = 32; break; case SPI_BAUDRATEPRESCALER_64: - settings.baudRatePrescaler = SpiBaudRatePrescaler::BRP_64; - prescaler = 2; + prescaler = 64; break; case SPI_BAUDRATEPRESCALER_128: - settings.baudRatePrescaler = SpiBaudRatePrescaler::BRP_128; - prescaler = 2; + prescaler = 128; break; case SPI_BAUDRATEPRESCALER_256: - settings.baudRatePrescaler = SpiBaudRatePrescaler::BRP_256; - prescaler = 2; + prescaler = 256; break; default: // Unreachable case @@ -60,29 +66,62 @@ namespace sta STA_UNREACHABLE(); } - settings.clkSpeed = HAL_RCC_GetSysClockFreq() / prescaler; + // SPI clock speed is based of PCLK + settings.clkSpeed = pclkFreq / prescaler; return settings; } - HalSpiInterface::HalSpiInterface(SPI_HandleTypeDef * handle, Mutex * mutex /* = nullptr */) - : SpiInterface(getHalSpiSettings(handle), mutex), handle_{handle} + HalSpiInterface::HalSpiInterface(const HalSpiInterfaceInfo & info, Mutex * mutex /* = nullptr */) + : SpiInterface(mutex), info_{info} { - STA_ASSERT(handle != nullptr); + STA_ASSERT(info.handle != nullptr); + STA_ASSERT(info.getPCLKFreq != nullptr); } - void HalSpiInterface::transfer(uint8_t data) + void HalSpiInterface::transfer(uint8_t value) { - HAL_SPI_Transmit(handle_, &data, 1, HAL_MAX_DELAY); + if (settings().dataSize == SpiDataSize::SIZE_8) + { + HAL_SPI_Transmit(info_.handle, &value, 1, HAL_MAX_DELAY); + } + else + { + // Required since tx buffer is cast to uint16_t * internally + uint16_t dummy = value; + HAL_SPI_Transmit(info_.handle, reinterpret_cast(&dummy), 1, HAL_MAX_DELAY); + } + } + + void HalSpiInterface::transfer16(uint16_t value) + { + static_assert(sizeof(value) == 2, "Unexpected uint16_t size"); + + uint16_t size = 1; + + // Send as two bytes if data size is 8-bit + if (settings().dataSize == SpiDataSize::SIZE_8) + { + size = 2; + + if (settings().bitOrder == STA_HAL_SPI_REVERSE_BIT_ORDER) + { + // Reverse byte order from internal representation + value = STA_UINT16_SWAP_BYTE_ORDER(value); + } + } + + HAL_SPI_Transmit(info_.handle, reinterpret_cast(&value), size, HAL_MAX_DELAY); } void HalSpiInterface::transfer(const uint8_t * buffer, size_t size) { STA_ASSERT(buffer != nullptr); + STA_ASSERT(size != 0); - HAL_SPI_Transmit(handle_, const_cast(buffer), size, HAL_MAX_DELAY); + HAL_SPI_Transmit(info_.handle, const_cast(buffer), size, HAL_MAX_DELAY); } void HalSpiInterface::transfer(const uint8_t * txBuffer, uint8_t * rxBuffer, size_t size) @@ -91,15 +130,14 @@ namespace sta STA_ASSERT(rxBuffer != nullptr); STA_ASSERT(size != 0); - HAL_SPI_TransmitReceive(handle_, const_cast(txBuffer), rxBuffer, size, HAL_MAX_DELAY); + HAL_SPI_TransmitReceive(info_.handle, const_cast(txBuffer), rxBuffer, size, HAL_MAX_DELAY); } - - void HalSpiInterface::transfer16(uint16_t value) + void HalSpiInterface::receive(uint8_t * buffer, size_t size) { - static_assert(sizeof(uint16_t) == 2, "Unexpected uint16_t size"); + STA_ASSERT(buffer != nullptr); - HAL_SPI_Transmit(handle_, reinterpret_cast(&value), 2, HAL_MAX_DELAY); + HAL_SPI_Receive(info_.handle, buffer, size, HAL_MAX_DELAY); } @@ -107,33 +145,36 @@ namespace sta { STA_ASSERT(count != 0); - for (size_t i = 0; i < count; ++i) + if (settings().dataSize == SpiDataSize::SIZE_8) { - transfer(value); + for (size_t i = 0; i < count; ++i) + { + HAL_SPI_Transmit(info_.handle, &value, 1, HAL_MAX_DELAY); + } } - } - - void HalSpiInterface::fill32(uint32_t value, size_t count) - { - static_assert(sizeof(uint32_t) == 4, "Unexpected uint32_t size"); - STA_ASSERT(count != 0); - - for (size_t i = 0; i < count; ++i) + else { - HAL_SPI_Transmit(handle_, reinterpret_cast(&value), 4, HAL_MAX_DELAY); + // Required since tx buffer is cast to uint16_t * internally + uint16_t dummy = value; + for (size_t i = 0; i < count; ++i) + { + HAL_SPI_Transmit(info_.handle, reinterpret_cast(&dummy), 1, HAL_MAX_DELAY); + } } } - void HalSpiInterface::receive(uint8_t * buffer, size_t size) + const SpiSettings & HalSpiInterface::settings() const { - STA_ASSERT(buffer != nullptr); + // Cache settings + static SpiSettings settings = getHalSpiSettings(info_.handle, info_.getPCLKFreq()); - HAL_SPI_Receive(handle_, buffer, size, HAL_MAX_DELAY); + return settings; } + HalSpiDevice::HalSpiDevice(SpiInterface * intf, HalGpioPin csPin) : SpiDevice(intf), csPin_{csPin} {}