diff --git a/CMakeLists.txt b/CMakeLists.txt index 23a2c3a93..affa6eabe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -218,7 +218,7 @@ list(FILTER STLIB_HIGH_CPP_NO_ETH EXCLUDE REGEX "${STLIB_HIGH_ETH_REGEX}") # Librería STLIB_LIBRARY # ============================ -add_library(${STLIB_LIBRARY} STATIC +add_library(${STLIB_LIBRARY} OBJECT $<$:${HAL_SOURCES_COMMON}> $<$,$>:${HAL_SOURCES_ETH}> $<$,$>:${LWIP_SOURCES}> diff --git a/Inc/HALAL/HALAL.hpp b/Inc/HALAL/HALAL.hpp index 396f99eb4..cd6482eba 100644 --- a/Inc/HALAL/HALAL.hpp +++ b/Inc/HALAL/HALAL.hpp @@ -4,7 +4,8 @@ #include "HALAL/Models/Pin.hpp" #include "HALAL/Models/HALconfig/HALconfig.hpp" -#include "HALAL/Models/DMA/DMA.hpp" +//#include "HALAL/Models/DMA/DMA.hpp" +#include "HALAL/Models/DMA/DMA2.hpp" #include "HALAL/Services/DigitalOutputService/DigitalOutputService.hpp" #include "HALAL/Services/DigitalInputService/DigitalInputService.hpp" @@ -28,6 +29,7 @@ #include "HALAL/Services/Encoder/Encoder.hpp" #include "HALAL/Services/EXTI/EXTI.hpp" +#include "HALAL/Models/SPI/SPI2.hpp" #include "HALAL/Services/Communication/SPI/SPI.hpp" #include "HALAL/Services/Communication/UART/UART.hpp" #include "HALAL/Services/Communication/I2C/I2C.hpp" diff --git a/Inc/HALAL/Models/DMA/DMA.hpp b/Inc/HALAL/Models/DMA/DMA.hpp index 74d7864aa..a9799cbb9 100644 --- a/Inc/HALAL/Models/DMA/DMA.hpp +++ b/Inc/HALAL/Models/DMA/DMA.hpp @@ -39,4 +39,4 @@ class DMA { private: static vector available_streams; static vector inscribed_streams; -}; +}; \ No newline at end of file diff --git a/Inc/HALAL/Models/DMA/DMA2.hpp b/Inc/HALAL/Models/DMA/DMA2.hpp new file mode 100644 index 000000000..2f7757120 --- /dev/null +++ b/Inc/HALAL/Models/DMA/DMA2.hpp @@ -0,0 +1,359 @@ +#pragma once +#include "C++Utilities/CppUtils.hpp" +#include "stm32h7xx_hal.h" +#include "main.h" +#include "HALAL/Models/MPUManager/MPUManager.hpp" +#include +#include +#include +#include +#include + +using std::array; +using std::size_t; +using std::span; +using std::tuple; + +#define MAX_STREAMS 16 + + +extern "C" { + inline DMA_HandleTypeDef *dma_irq_table[16] = {nullptr}; +} + + +namespace ST_LIB { + extern void compile_error(const char *msg); + struct DMA_Domain { + + enum class Instance : uint8_t {none, adc1, adc2, adc3, + i2c1, i2c2, i2c3, i2c5, + spi1, spi2, spi3, spi4, spi5, + fmac}; + + enum class Stream : uint8_t {dma1_stream0, dma1_stream1, dma1_stream2, dma1_stream3, + dma1_stream4, dma1_stream5, dma1_stream6, dma1_stream7, + dma2_stream0, dma2_stream1, dma2_stream2, dma2_stream3, + dma2_stream4, dma2_stream5, dma2_stream6, dma2_stream7}; + + + static inline DMA_Stream_TypeDef* stream_to_DMA_StreamTypeDef(Stream s) { + switch (s) { + case Stream::dma1_stream0: return DMA1_Stream0; + case Stream::dma1_stream1: return DMA1_Stream1; + case Stream::dma1_stream2: return DMA1_Stream2; + case Stream::dma1_stream3: return DMA1_Stream3; + case Stream::dma1_stream4: return DMA1_Stream4; + case Stream::dma1_stream5: return DMA1_Stream5; + case Stream::dma1_stream6: return DMA1_Stream6; + case Stream::dma1_stream7: return DMA1_Stream7; + + case Stream::dma2_stream0: return DMA2_Stream0; + case Stream::dma2_stream1: return DMA2_Stream1; + case Stream::dma2_stream2: return DMA2_Stream2; + case Stream::dma2_stream3: return DMA2_Stream3; + case Stream::dma2_stream4: return DMA2_Stream4; + case Stream::dma2_stream5: return DMA2_Stream5; + case Stream::dma2_stream6: return DMA2_Stream6; + case Stream::dma2_stream7: return DMA2_Stream7; + } + return nullptr; + } + + struct Entry { + Instance instance; + Stream stream; + IRQn_Type irqn; + uint8_t id; + }; + + template + struct DMA { + using domain = DMA_Domain; + + std::array e{}; + + + consteval DMA(Instance instance) { + static_assert(sizeof...(Ss) <= 3, "Máximo 3 streams"); + + Stream streams[] = { Ss... }; + constexpr uint8_t n = sizeof...(Ss); + + for (uint8_t j = 0; j < n; j++) { + e[j].instance = instance; + e[j].stream = streams[j]; + e[j].irqn = get_irqn(streams[j]); + e[j].id = j; + } + + } + + template + consteval array inscribe(Ctx &ctx) const { + array indices{}; + for (size_t i = 0; i < sizeof...(Ss); i++) { + indices[i] = ctx.template add(e[i], this); + } + return indices; + } + }; + + static constexpr std::size_t max_instances {MAX_STREAMS}; + static_assert(max_instances > 0, "The number of instances must be greater than 0"); + + static inline constexpr IRQn_Type get_irqn(Stream stream) { + if (stream == Stream::dma1_stream0) return DMA1_Stream0_IRQn; + else if (stream == Stream::dma1_stream1) return DMA1_Stream1_IRQn; + else if (stream == Stream::dma1_stream2) return DMA1_Stream2_IRQn; + else if (stream == Stream::dma1_stream3) return DMA1_Stream3_IRQn; + else if (stream == Stream::dma1_stream4) return DMA1_Stream4_IRQn; + else if (stream == Stream::dma1_stream5) return DMA1_Stream5_IRQn; + else if (stream == Stream::dma1_stream6) return DMA1_Stream6_IRQn; + else if (stream == Stream::dma1_stream7) return DMA1_Stream7_IRQn; + + else if (stream == Stream::dma2_stream0) return DMA2_Stream0_IRQn; + else if (stream == Stream::dma2_stream1) return DMA2_Stream1_IRQn; + else if (stream == Stream::dma2_stream2) return DMA2_Stream2_IRQn; + else if (stream == Stream::dma2_stream3) return DMA2_Stream3_IRQn; + else if (stream == Stream::dma2_stream4) return DMA2_Stream4_IRQn; + else if (stream == Stream::dma2_stream5) return DMA2_Stream5_IRQn; + else if (stream == Stream::dma2_stream6) return DMA2_Stream6_IRQn; + else if (stream == Stream::dma2_stream7) return DMA2_Stream7_IRQn; + else ErrorHandler("Unknown DMA stream"); + return DMA1_Stream0_IRQn; // Nunca se alcanza + } + + static constexpr inline bool is_one_of(Instance instance, auto... bases) { + return ((instance == bases) || ...); + } + + static constexpr inline bool is_spi(Instance instance) { + return is_one_of(instance, Instance::spi1, Instance::spi2, + Instance::spi3, Instance::spi4, Instance::spi5); + } + + static constexpr inline bool is_i2c(Instance instance) { + return is_one_of(instance, Instance::i2c1, Instance::i2c2, + Instance::i2c3, Instance::i2c5); + } + + static constexpr inline bool is_adc(Instance instance) { + return is_one_of(instance, Instance::adc1, Instance::adc2, Instance::adc3); + } + + static constexpr inline bool is_fmac(Instance instance) { + return instance == Instance::fmac; + } + + static constexpr inline bool is_none(Instance instance){ + return instance == Instance::none; + } + + static consteval inline uint32_t get_Request(Instance instance, uint8_t i) { + if (instance == Instance::none) return DMA_REQUEST_MEM2MEM; + + if (instance == Instance::adc1) return DMA_REQUEST_ADC1; + if (instance == Instance::adc2) return DMA_REQUEST_ADC2; + if (instance == Instance::adc3) return DMA_REQUEST_ADC3; + + if (instance == Instance::i2c1 && i == 0) return DMA_REQUEST_I2C1_RX; + if (instance == Instance::i2c1 && i == 1) return DMA_REQUEST_I2C1_TX; + if (instance == Instance::i2c2 && i == 0) return DMA_REQUEST_I2C2_RX; + if (instance == Instance::i2c2 && i == 1) return DMA_REQUEST_I2C2_TX; + if (instance == Instance::i2c3 && i == 0) return DMA_REQUEST_I2C3_RX; + if (instance == Instance::i2c3 && i == 1) return DMA_REQUEST_I2C3_TX; + if (instance == Instance::i2c5 && i == 0) return DMA_REQUEST_I2C5_RX; + if (instance == Instance::i2c5 && i == 1) return DMA_REQUEST_I2C5_TX; + + if (instance == Instance::spi1 && i == 0) return DMA_REQUEST_SPI1_RX; + if (instance == Instance::spi1 && i == 1) return DMA_REQUEST_SPI1_TX; + if (instance == Instance::spi2 && i == 0) return DMA_REQUEST_SPI2_RX; + if (instance == Instance::spi2 && i == 1) return DMA_REQUEST_SPI2_TX; + if (instance == Instance::spi3 && i == 0) return DMA_REQUEST_SPI3_RX; + if (instance == Instance::spi3 && i == 1) return DMA_REQUEST_SPI3_TX; + if (instance == Instance::spi4 && i == 0) return DMA_REQUEST_SPI4_RX; + if (instance == Instance::spi4 && i == 1) return DMA_REQUEST_SPI4_TX; + if (instance == Instance::spi5 && i == 0) return DMA_REQUEST_SPI5_RX; + if (instance == Instance::spi5 && i == 1) return DMA_REQUEST_SPI5_TX; + + if (instance == Instance::fmac && i == 0) return DMA_REQUEST_MEM2MEM; + if (instance == Instance::fmac && i == 1) return DMA_REQUEST_FMAC_WRITE; + if (instance == Instance::fmac && i == 2) return DMA_REQUEST_FMAC_READ; + + ErrorHandler("Invalid DMA request configuration"); + return 0; + } + + static consteval inline uint32_t get_Direction(Instance instance, uint8_t i) { + if ((is_fmac(instance) && i == 0) || instance == Instance::none) { + return DMA_MEMORY_TO_MEMORY; + } + else if ((is_i2c(instance) && i == 1) || + (is_spi(instance) && i == 1) || + (is_fmac(instance) && i == 1)){ + return DMA_MEMORY_TO_PERIPH; + } + return DMA_PERIPH_TO_MEMORY; + } + + static consteval inline uint32_t get_PeriphInc(Instance instance, uint8_t i) { + if ((is_fmac(instance) && i == 0) || is_none(instance)){ + return DMA_PINC_ENABLE; + } + return DMA_PINC_DISABLE; + } + + static consteval inline uint32_t get_MemInc(Instance instance, uint8_t i) { + if (is_fmac(instance) && i == 0){ + return DMA_MINC_DISABLE; + } + return DMA_MINC_ENABLE; + } + + static consteval inline uint32_t get_PeriphDataAlignment(Instance instance, uint8_t i) { + if (is_spi(instance) || is_i2c(instance)){ + return DMA_PDATAALIGN_BYTE; + } + else if (is_none(instance)){ + return DMA_PDATAALIGN_WORD; + } + return DMA_PDATAALIGN_HALFWORD; + } + + static consteval inline uint32_t get_MemDataAlignment(Instance instance, uint8_t i) { + if (is_i2c(instance)){ + return DMA_MDATAALIGN_WORD; + } + else if (is_spi(instance)){ + return DMA_MDATAALIGN_BYTE; + } + + return DMA_MDATAALIGN_HALFWORD; + } + + static consteval inline uint32_t get_Mode(Instance instance, uint8_t i) { + if (is_spi(instance) || is_fmac(instance) || is_none(instance)){ + return DMA_NORMAL; + } + + return DMA_CIRCULAR; + } + + static consteval inline uint32_t get_Priority(Instance instance, uint8_t i) { + if (is_fmac(instance)){ + return DMA_PRIORITY_HIGH; + } + + return DMA_PRIORITY_LOW; + } + + static consteval inline uint32_t get_FIFOMode(Instance instance, uint8_t i) { + if (is_fmac(instance)){ + return DMA_FIFOMODE_ENABLE; + } + return DMA_FIFOMODE_DISABLE; + } + + static consteval inline uint32_t get_FIFOThreshold(Instance instance, uint8_t i) { + if (is_spi(instance)){ + return DMA_FIFO_THRESHOLD_FULL; + } + return DMA_FIFO_THRESHOLD_HALFFULL; + } + + static consteval inline uint32_t get_MemBurst(Instance instance, uint8_t i) { + return DMA_MBURST_SINGLE; + } + + static consteval inline uint32_t get_PeriphBurst(Instance instance, uint8_t i) { + return DMA_PBURST_SINGLE; + } + + struct Config { + std::tuple + init_data{}; + }; + + template + static consteval std::array build(span instances) { + std::array cfgs{}; + + for (std::size_t i = 0; i < N; ++i){ + const auto &e = instances[i]; + + for (std::size_t j = 0; j < i; ++j){ + const auto &prev = instances[j]; + if (prev.stream == e.stream){ + compile_error("DMA stream already in use"); + } + } + + DMA_InitTypeDef DMA_InitStruct; + DMA_InitStruct.Request = get_Request(e.instance, e.id); + DMA_InitStruct.Direction = get_Direction(e.instance, e.id); + DMA_InitStruct.PeriphInc = get_PeriphInc(e.instance, e.id); + DMA_InitStruct.MemInc = get_MemInc(e.instance, e.id); + DMA_InitStruct.PeriphDataAlignment = get_PeriphDataAlignment(e.instance, e.id); + DMA_InitStruct.MemDataAlignment = get_MemDataAlignment(e.instance, e.id); + DMA_InitStruct.Mode = get_Mode(e.instance, e.id); + DMA_InitStruct.Priority = get_Priority(e.instance, e.id); + DMA_InitStruct.FIFOMode = get_FIFOMode(e.instance, e.id); + DMA_InitStruct.FIFOThreshold = get_FIFOThreshold(e.instance, e.id); + DMA_InitStruct.MemBurst = get_MemBurst(e.instance, e.id); + DMA_InitStruct.PeriphBurst = get_PeriphBurst(e.instance, e.id); + + + cfgs[i].init_data = std::make_tuple(e.instance, + DMA_InitStruct, + e.stream, + e.irqn, + e.id); + } + return cfgs; + } + + + + struct Instances_ { + DMA_HandleTypeDef dma; + + void start(uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength){ + HAL_DMA_Start_IT(&dma, SrcAddress, DstAddress, DataLength); + } + }; + + + template struct Init { + static inline std::array instances{}; + + static void init(std::span cfgs) { + if (N == 0) return; + __HAL_RCC_DMA1_CLK_ENABLE(); + __HAL_RCC_DMA2_CLK_ENABLE(); + for (std::size_t i = 0; i < N; ++i) { + const auto &e = cfgs[i]; + auto [instance, dma_init, stream, irqn, id] = e.init_data; + + instances[i].dma = {}; + instances[i].dma.Instance = stream_to_DMA_StreamTypeDef(stream); + instances[i].dma.Init = dma_init; + + if (HAL_DMA_Init(&instances[i].dma) != HAL_OK) { + ErrorHandler("DMA Init failed"); + } + else{ + HAL_NVIC_SetPriority(irqn, 0, 0); + HAL_NVIC_EnableIRQ(irqn); + dma_irq_table[static_cast(stream)] = &instances[i].dma; + } + } + } + }; + }; +} + diff --git a/Inc/HALAL/Models/Pin.hpp b/Inc/HALAL/Models/Pin.hpp index 97096e90c..d8dade25b 100644 --- a/Inc/HALAL/Models/Pin.hpp +++ b/Inc/HALAL/Models/Pin.hpp @@ -22,7 +22,7 @@ constexpr GPIODomain::Pin PA11{A, GPIO_PIN_11, 0b0101111110010011}; constexpr GPIODomain::Pin PA12{A, GPIO_PIN_12, 0b0011111110010111}; constexpr GPIODomain::Pin PA13{A, GPIO_PIN_13, 0b1000000000000001}; constexpr GPIODomain::Pin PA14{A, GPIO_PIN_14, 0b1000000000000001}; -constexpr GPIODomain::Pin PA15{A, GPIO_PIN_15, 0b0111010111111011}; +constexpr GPIODomain::Pin PA15{A, GPIO_PIN_15, 0b1100111111010011}; // Port B constexpr GPIODomain::Pin PB0{B, GPIO_PIN_0, 0b0111110011111011}; diff --git a/Inc/HALAL/Models/SPI/SPI2.hpp b/Inc/HALAL/Models/SPI/SPI2.hpp new file mode 100644 index 000000000..97c137422 --- /dev/null +++ b/Inc/HALAL/Models/SPI/SPI2.hpp @@ -0,0 +1,1134 @@ +/* + * SPI2.hpp + * + * Created on: 27 dec. 2025 + * Author: Boris + */ + +#ifndef SPI2_HPP +#define SPI2_HPP + +#include "C++Utilities/CppImports.hpp" +#include "HALAL/Models/GPIO.hpp" +#include "HALAL/Models/Pin.hpp" +#include "ErrorHandler/ErrorHandler.hpp" +#include "HALAL/Models/DMA/DMA2.hpp" +#include "HALAL/Models/SPI/SPIConfig.hpp" + +using ST_LIB::GPIODomain; +using ST_LIB::DMA_Domain; +using ST_LIB::SPIConfigTypes; + +// Forward declaration of IRQ handlers and HAL callbacks +extern "C" { + void SPI1_IRQHandler(void); + void SPI2_IRQHandler(void); + void SPI3_IRQHandler(void); + void SPI4_IRQHandler(void); + void SPI5_IRQHandler(void); + void SPI6_IRQHandler(void); + + void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi); + void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi); + void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi); + void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi); +} + +namespace ST_LIB { +extern void compile_error(const char *msg); + +struct SPIDomain { + +/** + * ========================================= + * Internal working things + * ========================================= + */ + + // Configuration types + using ClockPolarity = SPIConfigTypes::ClockPolarity; + using ClockPhase = SPIConfigTypes::ClockPhase; + using BitOrder = SPIConfigTypes::BitOrder; + using NSSMode = SPIConfigTypes::NSSMode; + using DataSize = SPIConfigTypes::DataSize; + using Direction = SPIConfigTypes::Direction; + using FIFOThreshold = SPIConfigTypes::FIFOThreshold; + using NSSPolarity = SPIConfigTypes::NSSPolarity; + using CRCLength = SPIConfigTypes::CRCLength; + using SPIConfig = SPIConfigTypes::SPIConfig; + + enum class SPIPeripheral : uintptr_t { + spi1 = SPI1_BASE, + spi2 = SPI2_BASE, + spi3 = SPI3_BASE, + spi4 = SPI4_BASE, + spi5 = SPI5_BASE, + spi6 = SPI6_BASE, + }; + + enum class SPIMode : bool { + MASTER = true, + SLAVE = false, + }; + + static consteval bool compare_pin(const GPIODomain::Pin &p1, const GPIODomain::Pin &p2) { + return (p1.port == p2.port) && (p1.pin == p2.pin); + } + + static consteval GPIODomain::AlternateFunction get_af(const GPIODomain::Pin &pin, SPIPeripheral peripheral) { + + if (peripheral == SPIPeripheral::spi2) { + if (compare_pin(pin, PB4)) return GPIODomain::AlternateFunction::AF7; + } + if (peripheral == SPIPeripheral::spi3) { + if (compare_pin(pin, PA4)) return GPIODomain::AlternateFunction::AF6; + if (compare_pin(pin, PA15)) return GPIODomain::AlternateFunction::AF6; + if (compare_pin(pin, PB2)) return GPIODomain::AlternateFunction::AF7; + if (compare_pin(pin, PB3)) return GPIODomain::AlternateFunction::AF6; + if (compare_pin(pin, PB4)) return GPIODomain::AlternateFunction::AF6; + if (compare_pin(pin, PB5)) return GPIODomain::AlternateFunction::AF7; + if (compare_pin(pin, PC10)) return GPIODomain::AlternateFunction::AF6; + if (compare_pin(pin, PC11)) return GPIODomain::AlternateFunction::AF6; + if (compare_pin(pin, PC12)) return GPIODomain::AlternateFunction::AF6; + } + if (peripheral == SPIPeripheral::spi6) { + if (compare_pin(pin, PA4)) return GPIODomain::AlternateFunction::AF8; + if (compare_pin(pin, PA5)) return GPIODomain::AlternateFunction::AF8; + if (compare_pin(pin, PA6)) return GPIODomain::AlternateFunction::AF8; + if (compare_pin(pin, PA7)) return GPIODomain::AlternateFunction::AF8; + if (compare_pin(pin, PA15)) return GPIODomain::AlternateFunction::AF7; + if (compare_pin(pin, PB3)) return GPIODomain::AlternateFunction::AF8; + if (compare_pin(pin, PB4)) return GPIODomain::AlternateFunction::AF8; + if (compare_pin(pin, PB5)) return GPIODomain::AlternateFunction::AF8; + } + + return GPIODomain::AlternateFunction::AF5; // Default AF for everything else + } + + static constexpr uint32_t get_prescaler_flag(uint32_t prescaler) { + switch (prescaler) { + case 2: return SPI_BAUDRATEPRESCALER_2; + case 4: return SPI_BAUDRATEPRESCALER_4; + case 8: return SPI_BAUDRATEPRESCALER_8; + case 16: return SPI_BAUDRATEPRESCALER_16; + case 32: return SPI_BAUDRATEPRESCALER_32; + case 64: return SPI_BAUDRATEPRESCALER_64; + case 128: return SPI_BAUDRATEPRESCALER_128; + case 256: return SPI_BAUDRATEPRESCALER_256; + default: + if consteval { + compile_error("Invalid prescaler value"); + } else { + ErrorHandler("Invalid prescaler value"); + return SPI_BAUDRATEPRESCALER_256; + } + } + } + + // Forward declaration + static uint32_t calculate_prescaler(uint32_t src_freq, uint32_t max_baud); + + static constexpr std::size_t max_instances{6}; + + struct Entry { + SPIPeripheral peripheral; + SPIMode mode; + + std::size_t sck_gpio_idx; + std::size_t miso_gpio_idx; + std::size_t mosi_gpio_idx; + std::optional nss_gpio_idx; + + std::size_t dma_rx_idx; + std::size_t dma_tx_idx; + + uint32_t max_baudrate; // Will set the baudrate as fast as possible under this value + SPIConfig config; // User-defined SPI configuration + }; + + struct Config { + SPIPeripheral peripheral; + SPIMode mode; + + std::size_t sck_gpio_idx; + std::size_t miso_gpio_idx; + std::size_t mosi_gpio_idx; + std::optional nss_gpio_idx; + + std::size_t dma_rx_idx; + std::size_t dma_tx_idx; + + uint32_t max_baudrate; // Will set the baudrate as fast as possible under this value + SPIConfig config; // User-defined SPI configuration + }; + + +/** + * ========================================= + * Request Object + * ========================================= + */ + template + struct Device { + using domain = SPIDomain; + + SPIPeripheral peripheral; + SPIMode mode; + uint32_t max_baudrate; // Will set the baudrate as fast as possible under this value + SPIConfig config; // User-defined SPI configuration + + GPIODomain::GPIO sck_gpio; + GPIODomain::GPIO miso_gpio; + GPIODomain::GPIO mosi_gpio; + std::optional nss_gpio; + + DMA_Domain::DMA dma_rx_tx; + + consteval Device(SPIMode mode, SPIPeripheral peripheral, uint32_t max_baudrate, + GPIODomain::Pin sck_pin, GPIODomain::Pin miso_pin, + GPIODomain::Pin mosi_pin, GPIODomain::Pin nss_pin, + SPIConfig config = SPIConfig{}) + : peripheral{peripheral}, mode{mode}, max_baudrate{max_baudrate}, + config{config}, + sck_gpio(sck_pin, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, get_af(sck_pin, peripheral)), + miso_gpio(miso_pin, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, get_af(miso_pin, peripheral)), + mosi_gpio(mosi_pin, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, get_af(mosi_pin, peripheral)), + nss_gpio(GPIODomain::GPIO(nss_pin, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, get_af(nss_pin, peripheral))), + dma_rx_tx(dma_instance(peripheral)) + { + config.validate(); + + if (config.nss_mode == NSSMode::SOFTWARE) { + compile_error("Use NSSMode::SOFTWARE, and omit NSS pin for software NSS management, it is handled externally"); + } + + validate_nss_pin(peripheral, nss_pin); + + validate_spi_pins(peripheral, sck_pin, miso_pin, mosi_pin); + } + + // Constructor without NSS pin (for software NSS mode) + consteval Device(SPIMode mode, SPIPeripheral peripheral, uint32_t max_baudrate, + GPIODomain::Pin sck_pin, GPIODomain::Pin miso_pin, + GPIODomain::Pin mosi_pin, + SPIConfig config) + : peripheral{peripheral}, mode{mode}, max_baudrate{max_baudrate}, + config{config}, + sck_gpio(sck_pin, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, get_af(sck_pin, peripheral)), + miso_gpio(miso_pin, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, get_af(miso_pin, peripheral)), + mosi_gpio(mosi_pin, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, get_af(mosi_pin, peripheral)), + nss_gpio(std::nullopt), // No NSS GPIO + dma_rx_tx(dma_instance(peripheral)) + { + config.validate(); + + if (config.nss_mode == NSSMode::HARDWARE) { + compile_error("NSS pin must be provided for hardware NSS mode, or use NSSMode::SOFTWARE"); + } + + validate_spi_pins(peripheral, sck_pin, miso_pin, mosi_pin); + } + + template + consteval std::size_t inscribe(Ctx &ctx) const { + auto dma_indices = dma_rx_tx.inscribe(ctx); + + // Conditionally add NSS GPIO if provided + std::optional nss_idx = std::nullopt; + if (nss_gpio.has_value()) { + nss_idx = nss_gpio.value().inscribe(ctx); + } + + Entry e{ + .peripheral = peripheral, + .mode = mode, + .sck_gpio_idx = sck_gpio.inscribe(ctx), + .miso_gpio_idx = miso_gpio.inscribe(ctx), + .mosi_gpio_idx = mosi_gpio.inscribe(ctx), + .nss_gpio_idx = nss_idx, + .dma_rx_idx = dma_indices[0], + .dma_tx_idx = dma_indices[1], + .max_baudrate = max_baudrate, + .config = config + }; + + return ctx.template add(e, this); + } + + private: + // Helper function to validate SPI pins (SCK, MISO, MOSI only) + static consteval void validate_spi_pins(SPIPeripheral peripheral, + GPIODomain::Pin sck_pin, + GPIODomain::Pin miso_pin, + GPIODomain::Pin mosi_pin) { + switch (peripheral) { + case SPIPeripheral::spi1: + if (!compare_pin(sck_pin, PB3) && + !compare_pin(sck_pin, PG11) && + !compare_pin(sck_pin, PA5)) { + compile_error("Invalid SCK pin for SPI1"); + } + if (!compare_pin(miso_pin, PB4) && + !compare_pin(miso_pin, PG9) && + !compare_pin(miso_pin, PA6)) { + compile_error("Invalid MISO pin for SPI1"); + } + if (!compare_pin(mosi_pin, PB5) && + !compare_pin(mosi_pin, PD7) && + !compare_pin(mosi_pin, PA7)) { + compile_error("Invalid MOSI pin for SPI1"); + } + break; + + case SPIPeripheral::spi2: + if (!compare_pin(sck_pin, PD3) && + !compare_pin(sck_pin, PA12) && + !compare_pin(sck_pin, PA9) && + !compare_pin(sck_pin, PB13) && + !compare_pin(sck_pin, PB10)) { + compile_error("Invalid SCK pin for SPI2"); + } + if (!compare_pin(miso_pin, PC2) && + !compare_pin(miso_pin, PB14)) { + compile_error("Invalid MISO pin for SPI2"); + } + if (!compare_pin(mosi_pin, PC3) && + !compare_pin(mosi_pin, PC1) && + !compare_pin(mosi_pin, PB15)) { + compile_error("Invalid MOSI pin for SPI2"); + } + break; + + case SPIPeripheral::spi3: + if (!compare_pin(sck_pin, PB3) && + !compare_pin(sck_pin, PC10)) { + compile_error("Invalid SCK pin for SPI3"); + } + if (!compare_pin(miso_pin, PB4) && + !compare_pin(miso_pin, PC11)) { + compile_error("Invalid MISO pin for SPI3"); + } + if (!compare_pin(mosi_pin, PB5) && + !compare_pin(mosi_pin, PD6) && + !compare_pin(mosi_pin, PC12) && + !compare_pin(mosi_pin, PB2)) { + compile_error("Invalid MOSI pin for SPI3"); + } + break; + + case SPIPeripheral::spi4: + if (!compare_pin(sck_pin, PE2) && + !compare_pin(sck_pin, PE12)) { + compile_error("Invalid SCK pin for SPI4"); + } + if (!compare_pin(miso_pin, PE5) && + !compare_pin(miso_pin, PE13)) { + compile_error("Invalid MISO pin for SPI4"); + } + if (!compare_pin(mosi_pin, PE6) && + !compare_pin(mosi_pin, PE14)) { + compile_error("Invalid MOSI pin for SPI4"); + } + break; + + case SPIPeripheral::spi5: + if (!compare_pin(sck_pin, PF7)) { + compile_error("Invalid SCK pin for SPI5"); + } + if (!compare_pin(miso_pin, PF8)) { + compile_error("Invalid MISO pin for SPI5"); + } + if (!compare_pin(mosi_pin, PF9) && + !compare_pin(mosi_pin, PF11)) { + compile_error("Invalid MOSI pin for SPI5"); + } + break; + + case SPIPeripheral::spi6: + if (!compare_pin(sck_pin, PB3) && + !compare_pin(sck_pin, PG13) && + !compare_pin(sck_pin, PC10) && + !compare_pin(sck_pin, PA7)) { + compile_error("Invalid SCK pin for SPI6"); + } + if (!compare_pin(miso_pin, PB4) && + !compare_pin(miso_pin, PG12) && + !compare_pin(miso_pin, PA6)) { + compile_error("Invalid MISO pin for SPI6"); + } + if (!compare_pin(mosi_pin, PB5) && + !compare_pin(mosi_pin, PG14) && + !compare_pin(mosi_pin, PA7)) { + compile_error("Invalid MOSI pin for SPI6"); + } + break; + + default: + compile_error("Invalid SPI peripheral specified in SPIDomain::Device"); + } + } + + // Helper function to validate NSS pin (only called for hardware NSS mode) + static consteval void validate_nss_pin(SPIPeripheral peripheral, GPIODomain::Pin nss_pin) { + switch (peripheral) { + case SPIPeripheral::spi1: + if (!compare_pin(nss_pin, PA4) && + !compare_pin(nss_pin, PA15) && + !compare_pin(nss_pin, PG10)) { + compile_error("Invalid NSS pin for SPI1"); + } + break; + + case SPIPeripheral::spi2: + if (!compare_pin(nss_pin, PA11) && + !compare_pin(nss_pin, PB9) && + !compare_pin(nss_pin, PB4) && + !compare_pin(nss_pin, PB12)) { + compile_error("Invalid NSS pin for SPI2"); + } + break; + + case SPIPeripheral::spi3: + if (!compare_pin(nss_pin, PA15) && + !compare_pin(nss_pin, PA4)) { + compile_error("Invalid NSS pin for SPI3"); + } + break; + + case SPIPeripheral::spi4: + if (!compare_pin(nss_pin, PE4) && + !compare_pin(nss_pin, PE11)) { + compile_error("Invalid NSS pin for SPI4"); + } + break; + + case SPIPeripheral::spi5: + if (!compare_pin(nss_pin, PF6)) { + compile_error("Invalid NSS pin for SPI5"); + } + break; + + case SPIPeripheral::spi6: + if (!compare_pin(nss_pin, PA0) && + !compare_pin(nss_pin, PA15) && + !compare_pin(nss_pin, PG8) && + !compare_pin(nss_pin, PA4)) { + compile_error("Invalid NSS pin for SPI6"); + } + break; + + default: + compile_error("Invalid SPI peripheral specified in SPIDomain::Device"); + } + } + + static consteval DMA_Domain::Instance dma_instance(SPIPeripheral peripheral) { + switch (peripheral) { + case SPIPeripheral::spi1: + return DMA_Domain::Instance::spi1; + case SPIPeripheral::spi2: + return DMA_Domain::Instance::spi2; + case SPIPeripheral::spi3: + return DMA_Domain::Instance::spi3; + case SPIPeripheral::spi4: + return DMA_Domain::Instance::spi4; + case SPIPeripheral::spi5: + return DMA_Domain::Instance::spi5; + // case SPIPeripheral::spi6: + // return DMA_Domain::Instance::spi6; + default: + compile_error("Invalid SPI peripheral specified in SPIDomain::Device"); + } + } + }; + + +/** + * ========================================= + * Instance (state holder) + * ========================================= + */ + template struct Init; // Forward declaration + template struct SPIWrapper; // Forward declaration + struct Instance { + template friend struct Init; + template friend struct SPIWrapper; + friend void ::SPI1_IRQHandler(void); + friend void ::SPI2_IRQHandler(void); + friend void ::SPI3_IRQHandler(void); + friend void ::SPI4_IRQHandler(void); + friend void ::SPI5_IRQHandler(void); + friend void ::SPI6_IRQHandler(void); + friend void ::HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi); + friend void ::HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi); + friend void ::HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi); + friend void ::HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi); + + private: + SPI_HandleTypeDef hspi; + SPI_TypeDef* instance; + + volatile bool* operation_flag; + }; + + + static inline Instance* spi_instances[max_instances]; +/** + * ========================================= + * Wrapper, public API + * ========================================= + */ + + // SPI Wrapper primary template + template + struct SPIWrapper; + + /** + * @brief SPI Wrapper for Master mode operations. + */ + template + struct SPIWrapper { + static constexpr uint32_t data_bits = static_cast(device_request.config.data_size); + static constexpr uint32_t frame_size = (data_bits <= 8) ? 1 : ((data_bits <= 16) ? 2 : 4); + + SPIWrapper(Instance &instance) : spi_instance{instance} {} + + /** + * @brief Sends data over SPI in blocking mode. + */ + template + bool send(span data) { + if (data.size_bytes() % frame_size != 0) { + ErrorHandler("SPI data size (%d) not aligned to frame size (%d)", data.size_bytes(), frame_size); + return false; + } + auto error_code = HAL_SPI_Transmit(&spi_instance.hspi, (uint8_t*)data.data(), data.size_bytes() / frame_size, 10); + return check_error_code(error_code); + } + + /** + * @brief Sends a trivially copyable data type over SPI in blocking mode. + */ + template + bool send(const T& data) requires std::is_trivially_copyable_v { + if (sizeof(T) % frame_size != 0) { + ErrorHandler("SPI data type size (%d) not aligned to frame size (%d)", sizeof(T), frame_size); + return false; + } + auto error_code = HAL_SPI_Transmit(&spi_instance.hspi, reinterpret_cast(&data), sizeof(T) / frame_size, 10); + return check_error_code(error_code); + } + + /** + * @brief Receives data over SPI in blocking mode. + */ + template + bool receive(span data) { + if (data.size_bytes() % frame_size != 0) { + ErrorHandler("SPI data size (%d) not aligned to frame size (%d)", data.size_bytes(), frame_size); + return false; + } + auto error_code = HAL_SPI_Receive(&spi_instance.hspi, (uint8_t*)data.data(), data.size_bytes() / frame_size, 10); + return check_error_code(error_code); + } + + /** + * @brief Receives a trivially copyable data type over SPI in blocking mode. + */ + template + bool receive(T& data) requires std::is_trivially_copyable_v { + if (sizeof(T) % frame_size != 0) { + ErrorHandler("SPI data type size (%d) not aligned to frame size (%d)", sizeof(T), frame_size); + return false; + } + auto error_code = HAL_SPI_Receive(&spi_instance.hspi, reinterpret_cast(&data), sizeof(T) / frame_size, 10); + return check_error_code(error_code); + } + + /** + * @brief Sends and receives data over SPI in blocking mode. + */ + template + bool transceive(span tx_data, span rx_data) { + size_t size = std::min(tx_data.size_bytes(), rx_data.size_bytes()); + if (size % frame_size != 0) { + ErrorHandler("SPI transaction size (%d) not aligned to frame size (%d)", size, frame_size); + return false; + } + auto error_code = HAL_SPI_TransmitReceive(&spi_instance.hspi, (uint8_t*)tx_data.data(), (uint8_t*)rx_data.data(), size / frame_size, 10); + return check_error_code(error_code); + } + + /** + * @brief Sends and receives a trivially copyable data type over SPI in blocking mode. + */ + template + bool transceive(span tx_data, T& rx_data) requires std::is_trivially_copyable_v { + size_t size = std::min(tx_data.size_bytes(), sizeof(T)); + if (size % frame_size != 0) { + ErrorHandler("SPI transaction size (%d) not aligned to frame size (%d)", size, frame_size); + return false; + } + auto error_code = HAL_SPI_TransmitReceive(&spi_instance.hspi, (uint8_t*)tx_data.data(), reinterpret_cast(&rx_data), size / frame_size, 10); + return check_error_code(error_code); + } + + /** + * @brief Sends and receives a trivially copyable data type over SPI in blocking mode. + */ + template + bool transceive(const T& tx_data, span rx_data) requires std::is_trivially_copyable_v { + size_t size = std::min(sizeof(T), rx_data.size_bytes()); + if (size % frame_size != 0) { + ErrorHandler("SPI transaction size (%d) not aligned to frame size (%d)", size, frame_size); + return false; + } + auto error_code = HAL_SPI_TransmitReceive(&spi_instance.hspi, reinterpret_cast(&tx_data), (uint8_t*)rx_data.data(), size / frame_size, 10); + return check_error_code(error_code); + } + + /** + * @brief Sends and receives a trivially copyable data type over SPI in blocking mode. + */ + template + bool transceive(const T1& tx_data, T2& rx_data) requires (std::is_trivially_copyable_v && std::is_trivially_copyable_v) { + size_t size = std::min(sizeof(T1), sizeof(T2)); + if (size % frame_size != 0) { + ErrorHandler("SPI transaction size (%d) not aligned to frame size (%d)", size, frame_size); + return false; + } + auto error_code = HAL_SPI_TransmitReceive(&spi_instance.hspi, reinterpret_cast(&tx_data), reinterpret_cast(&rx_data), size / frame_size, 10); + return check_error_code(error_code); + } + + /** + * @brief Sends data over SPI using DMA, uses an optional operation flag to signal completion. + */ + template + bool send_DMA(span data, volatile bool* operation_flag = nullptr) { + spi_instance.operation_flag = operation_flag; + if (data.size_bytes() % frame_size != 0) { + ErrorHandler("SPI data size (%d) not aligned to frame size (%d)", data.size_bytes(), frame_size); + return false; + } + auto error_code = HAL_SPI_Transmit_DMA(&spi_instance.hspi, (uint8_t*)data.data(), data.size_bytes() / frame_size); + return check_error_code(error_code); + } + + /** + * @brief Sends a trivially copyable data type over SPI using DMA, uses an optional operation flag to signal completion. + */ + template + bool send_DMA(const T& data, volatile bool* operation_flag = nullptr) requires std::is_trivially_copyable_v { + spi_instance.operation_flag = operation_flag; + if (sizeof(T) % frame_size != 0) { + ErrorHandler("SPI data size (%d) not aligned to frame size (%d)", sizeof(T), frame_size); + return false; + } + auto error_code = HAL_SPI_Transmit_DMA(&spi_instance.hspi, reinterpret_cast(&data), sizeof(T) / frame_size); + return check_error_code(error_code); + } + + /** + * @brief Receives data over SPI using DMA, uses an optional operation flag to signal completion. + */ + template + bool receive_DMA(span data, volatile bool* operation_flag = nullptr) { + spi_instance.operation_flag = operation_flag; + if (data.size_bytes() % frame_size != 0) { + ErrorHandler("SPI data size (%d) not aligned to frame size (%d)", data.size_bytes(), frame_size); + return false; + } + auto error_code = HAL_SPI_Receive_DMA(&spi_instance.hspi, (uint8_t*)data.data(), data.size_bytes() / frame_size); + return check_error_code(error_code); + } + + /** + * @brief Receives a trivially copyable data type over SPI using DMA, uses an optional operation flag to signal completion. + */ + template + bool receive_DMA(T& data, volatile bool* operation_flag = nullptr) requires std::is_trivially_copyable_v { + spi_instance.operation_flag = operation_flag; + if (sizeof(T) % frame_size != 0) { + ErrorHandler("SPI data size (%d) not aligned to frame size (%d)", sizeof(T), frame_size); + return false; + } + auto error_code = HAL_SPI_Receive_DMA(&spi_instance.hspi, reinterpret_cast(&data), sizeof(T) / frame_size); + return check_error_code(error_code); + } + + /** + * @brief Sends and receives data over SPI using DMA, uses an optional operation flag to signal completion. + */ + template + bool transceive_DMA(span tx_data, span rx_data, volatile bool* operation_flag = nullptr) { + spi_instance.operation_flag = operation_flag; + auto size = std::min(tx_data.size_bytes(), rx_data.size_bytes()); + if (size % frame_size != 0) { + ErrorHandler("SPI transaction size (%d) not aligned to frame size (%d)", size, frame_size); + return false; + } + auto error_code = HAL_SPI_TransmitReceive_DMA(&spi_instance.hspi, (uint8_t*)tx_data.data(), (uint8_t*)rx_data.data(), size / frame_size); + return check_error_code(error_code); + } + + /** + * @brief Sends a span and receives a trivially copyable type over SPI using DMA, uses an optional operation flag to signal completion. + */ + template + bool transceive_DMA(span tx_data, T& rx_data, volatile bool* operation_flag = nullptr) requires std::is_trivially_copyable_v { + spi_instance.operation_flag = operation_flag; + auto size = std::min(tx_data.size_bytes(), sizeof(T)); + if (size % frame_size != 0) { + ErrorHandler("SPI transaction size (%d) not aligned to frame size (%d)", size, frame_size); + return false; + } + auto error_code = HAL_SPI_TransmitReceive_DMA(&spi_instance.hspi, (uint8_t*)tx_data.data(), reinterpret_cast(&rx_data), size / frame_size); + return check_error_code(error_code); + } + + /** + * @brief Sends a trivially copyable type and receives a span over SPI using DMA, uses an optional operation flag to signal completion. + */ + template + bool transceive_DMA(const T& tx_data, span rx_data, volatile bool* operation_flag = nullptr) requires std::is_trivially_copyable_v { + spi_instance.operation_flag = operation_flag; + auto size = std::min(sizeof(T), rx_data.size_bytes()); + if (size % frame_size != 0) { + ErrorHandler("SPI transaction size (%d) not aligned to frame size (%d)", size, frame_size); + return false; + } + auto error_code = HAL_SPI_TransmitReceive_DMA(&spi_instance.hspi, reinterpret_cast(&tx_data), (uint8_t*)rx_data.data(), size / frame_size); + return check_error_code(error_code); + } + + /** + * @brief Sends and receives a trivially copyable data type over SPI using DMA, uses an optional operation flag to signal completion. + */ + template + bool transceive_DMA(const T1& tx_data, T2& rx_data, volatile bool* operation_flag = nullptr) requires (std::is_trivially_copyable_v && std::is_trivially_copyable_v) { + spi_instance.operation_flag = operation_flag; + auto size = std::min(sizeof(T1), sizeof(T2)); + if (size % frame_size != 0) { + ErrorHandler("SPI transaction size (%d) not aligned to frame size (%d)", size, frame_size); + return false; + } + auto error_code = HAL_SPI_TransmitReceive_DMA(&spi_instance.hspi, reinterpret_cast(&tx_data), reinterpret_cast(&rx_data), size / frame_size); + return check_error_code(error_code); + } + + private: + Instance& spi_instance; + bool check_error_code(HAL_StatusTypeDef error_code) { + if (error_code == HAL_OK) { + return true; + } else if (error_code == HAL_BUSY) { + return false; + } else { + ErrorHandler("SPI transmit error: %u", static_cast(error_code)); + return false; + } + } + }; + + /** + * @brief SPI Wrapper for Slave mode operations. Doesn't allow for blocking operations. + */ + template + struct SPIWrapper { + static constexpr uint32_t data_bits = static_cast(device_request.config.data_size); + static constexpr uint32_t frame_size = (data_bits <= 8) ? 1 : ((data_bits <= 16) ? 2 : 4); + + SPIWrapper(Instance &instance) : spi_instance{instance} {} + + void set_software_nss(bool selected) requires (device_request.config.nss_mode == SPIConfigTypes::NSSMode::SOFTWARE) { + if (selected) { + CLEAR_BIT(spi_instance.instance->CR1, SPI_CR1_SSI); + } else { + SET_BIT(spi_instance.instance->CR1, SPI_CR1_SSI); + } + } + + /** + * @brief Listens for data over SPI using DMA, uses an optional operation flag to signal completion. + */ + template + bool listen(span data, volatile bool* operation_flag = nullptr) { + spi_instance.operation_flag = operation_flag; + if (data.size_bytes() % frame_size != 0) { + ErrorHandler("SPI data size (%d) not aligned to frame size (%d)", data.size_bytes(), frame_size); + return false; + } + auto error_code = HAL_SPI_Receive_DMA(&spi_instance.hspi, (uint8_t*)data.data(), data.size_bytes() / frame_size); + return check_error_code(error_code); + } + + /** + * @brief Listens for trivially copyable data type over SPI using DMA, uses an optional operation flag to signal completion. + */ + template + bool listen(T& data, volatile bool* operation_flag = nullptr) requires std::is_trivially_copyable_v { + spi_instance.operation_flag = operation_flag; + if (sizeof(T) % frame_size != 0) { + ErrorHandler("SPI data size (%d) not aligned to frame size (%d)", sizeof(T), frame_size); + return false; + } + auto error_code = HAL_SPI_Receive_DMA(&spi_instance.hspi, reinterpret_cast(&data), sizeof(T) / frame_size); + return check_error_code(error_code); + } + + /** + * @brief Arms the SPI to send data over DMA when requested, uses an optional operation flag to signal completion. + */ + template + bool arm(span tx_data, volatile bool* operation_flag = nullptr) { + spi_instance.operation_flag = operation_flag; + if (tx_data.size_bytes() % frame_size != 0) { + ErrorHandler("SPI data size (%d) not aligned to frame size (%d)", tx_data.size_bytes(), frame_size); + return false; + } + auto error_code = HAL_SPI_Transmit_DMA(&spi_instance.hspi, (uint8_t*)tx_data.data(), tx_data.size_bytes() / frame_size); + return check_error_code(error_code); + } + + /** + * @brief Arms the SPI to send a trivially copyable data type over DMA when requested, uses an optional operation flag to signal completion. + */ + template + bool arm(const T& data, volatile bool* operation_flag = nullptr) requires std::is_trivially_copyable_v { + spi_instance.operation_flag = operation_flag; + if (sizeof(T) % frame_size != 0) { + ErrorHandler("SPI data size (%d) not aligned to frame size (%d)", sizeof(T), frame_size); + return false; + } + auto error_code = HAL_SPI_Transmit_DMA(&spi_instance.hspi, reinterpret_cast(&data), sizeof(T) / frame_size); + return check_error_code(error_code); + } + + /** + * @brief Sends and receives data over SPI using DMA, uses an optional operation flag to signal completion. + */ + template + bool transceive(span tx_data, span rx_data, volatile bool* operation_flag = nullptr) { + spi_instance.operation_flag = operation_flag; + auto size = std::min(tx_data.size_bytes(), rx_data.size_bytes()); + if (size % frame_size != 0) { + ErrorHandler("SPI transaction size (%d) not aligned to frame size (%d)", size, frame_size); + return false; + } + auto error_code = HAL_SPI_TransmitReceive_DMA(&spi_instance.hspi, (uint8_t*)tx_data.data(), (uint8_t*)rx_data.data(), size / frame_size); + return check_error_code(error_code); + } + + /** + * @brief Sends a span and receives a trivially copyable type over SPI using DMA, uses an optional operation flag to signal completion. + */ + template + bool transceive(span tx_data, T& rx_data, volatile bool* operation_flag = nullptr) requires std::is_trivially_copyable_v { + spi_instance.operation_flag = operation_flag; + auto size = std::min(tx_data.size_bytes(), sizeof(T)); + if (size % frame_size != 0) { + ErrorHandler("SPI transaction size (%d) not aligned to frame size (%d)", size, frame_size); + return false; + } + auto error_code = HAL_SPI_TransmitReceive_DMA(&spi_instance.hspi, (uint8_t*)tx_data.data(), reinterpret_cast(&rx_data), size / frame_size); + return check_error_code(error_code); + } + + /** + * @brief Sends a trivially copyable type and receives a span over SPI using DMA, uses an optional operation flag to signal completion. + */ + template + bool transceive(const T& tx_data, span rx_data, volatile bool* operation_flag = nullptr) requires std::is_trivially_copyable_v { + spi_instance.operation_flag = operation_flag; + auto size = std::min(sizeof(T), rx_data.size_bytes()); + if (size % frame_size != 0) { + ErrorHandler("SPI transaction size (%d) not aligned to frame size (%d)", size, frame_size); + return false; + } + auto error_code = HAL_SPI_TransmitReceive_DMA(&spi_instance.hspi, reinterpret_cast(&tx_data), (uint8_t*)rx_data.data(), size / frame_size); + return check_error_code(error_code); + } + + /** + * @brief Sends and receives a trivially copyable data type over SPI using DMA, uses an optional operation flag to signal completion. + */ + template + bool transceive(const T1& tx_data, T2& rx_data, volatile bool* operation_flag = nullptr) requires (std::is_trivially_copyable_v && std::is_trivially_copyable_v) { + spi_instance.operation_flag = operation_flag; + auto size = std::min(sizeof(T1), sizeof(T2)); + if (size % frame_size != 0) { + ErrorHandler("SPI transaction size (%d) not aligned to frame size (%d)", size, frame_size); + return false; + } + auto error_code = HAL_SPI_TransmitReceive_DMA(&spi_instance.hspi, reinterpret_cast(&tx_data), reinterpret_cast(&rx_data), size / frame_size); + return check_error_code(error_code); + } + + private: + Instance& spi_instance; + bool check_error_code(HAL_StatusTypeDef error_code) { + if (error_code == HAL_OK) { + return true; + } else if (error_code == HAL_BUSY) { + return false; + } else { + ErrorHandler("SPI transmit error: %u", static_cast(error_code)); + return false; + } + } + }; + + +/** + * ========================================= + * Internal working things + * ========================================= + */ + template + static consteval array build(span entries) { + array cfgs{}; + + if (N == 0) { + return cfgs; + } + + bool used_peripherals[6] = {false}; + + for (std::size_t i = 0; i < N; ++i) { + cfgs[i].peripheral = entries[i].peripheral; + cfgs[i].mode = entries[i].mode; + cfgs[i].sck_gpio_idx = entries[i].sck_gpio_idx; + cfgs[i].miso_gpio_idx = entries[i].miso_gpio_idx; + cfgs[i].mosi_gpio_idx = entries[i].mosi_gpio_idx; + cfgs[i].nss_gpio_idx = entries[i].nss_gpio_idx; + cfgs[i].dma_rx_idx = entries[i].dma_rx_idx; + cfgs[i].dma_tx_idx = entries[i].dma_tx_idx; + cfgs[i].max_baudrate = entries[i].max_baudrate; + cfgs[i].config = entries[i].config; + + auto peripheral = entries[i].peripheral; + + if (peripheral == SPIPeripheral::spi1) { + if (used_peripherals[0]) { + compile_error("SPI1 peripheral already used"); + } + used_peripherals[0] = true; + } else if (peripheral == SPIPeripheral::spi2) { + if (used_peripherals[1]) { + compile_error("SPI2 peripheral already used"); + } + used_peripherals[1] = true; + } else if (peripheral == SPIPeripheral::spi3) { + if (used_peripherals[2]) { + compile_error("SPI3 peripheral already used"); + } + used_peripherals[2] = true; + } else if (peripheral == SPIPeripheral::spi4) { + if (used_peripherals[3]) { + compile_error("SPI4 peripheral already used"); + } + used_peripherals[3] = true; + } else if (peripheral == SPIPeripheral::spi5) { + if (used_peripherals[4]) { + compile_error("SPI5 peripheral already used"); + } + used_peripherals[4] = true; + } else if (peripheral == SPIPeripheral::spi6) { + if (used_peripherals[5]) { + compile_error("SPI6 peripheral already used"); + } + used_peripherals[5] = true; + } + } + + return cfgs; + } + + template + struct Init { + static inline std::array instances{}; + + static void init(std::span cfgs, + std::span gpio_instances, + std::span dma_instances) { + for (std::size_t i = 0; i < N; ++i) { + const auto &e = cfgs[i]; + + SPIPeripheral peripheral = e.peripheral; + instances[i].instance = reinterpret_cast(e.peripheral); + + // Configure clock and store handle + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + uint8_t spi_number = 0; + if (peripheral == SPIPeripheral::spi1) { + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI1; + PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { + ErrorHandler("Unable to configure SPI1 clock"); + } + __HAL_RCC_SPI1_CLK_ENABLE(); + spi_number = 1; + } else if (peripheral == SPIPeripheral::spi2) { + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI2; + PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { + ErrorHandler("Unable to configure SPI2 clock"); + } + __HAL_RCC_SPI2_CLK_ENABLE(); + spi_number = 2; + } else if (peripheral == SPIPeripheral::spi3) { + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI3; + PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { + ErrorHandler("Unable to configure SPI3 clock"); + } + __HAL_RCC_SPI3_CLK_ENABLE(); + spi_number = 3; + } else if (peripheral == SPIPeripheral::spi4) { + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI4; + PeriphClkInitStruct.Spi45ClockSelection = RCC_SPI45CLKSOURCE_PLL2; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { + ErrorHandler("Unable to configure SPI4 clock"); + } + __HAL_RCC_SPI4_CLK_ENABLE(); + spi_number = 4; + } else if (peripheral == SPIPeripheral::spi5) { + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI5; + PeriphClkInitStruct.Spi45ClockSelection = RCC_SPI45CLKSOURCE_PLL2; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { + ErrorHandler("Unable to configure SPI5 clock"); + } + __HAL_RCC_SPI5_CLK_ENABLE(); + spi_number = 5; + } else if (peripheral == SPIPeripheral::spi6) { + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI6; + PeriphClkInitStruct.Spi6ClockSelection = RCC_SPI6CLKSOURCE_PLL2; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { + ErrorHandler("Unable to configure SPI6 clock"); + } + __HAL_RCC_SPI6_CLK_ENABLE(); + spi_number = 6; + } + + auto& hspi = instances[i].hspi; + hspi.Instance = instances[i].instance; + + auto& dma_rx = dma_instances[e.dma_rx_idx]; + auto& dma_tx = dma_instances[e.dma_tx_idx]; + + // DMA handles are already configured and initialized by DMA_Domain + hspi.hdmarx = &dma_rx.dma; + hspi.hdmatx = &dma_tx.dma; + + // Link back from DMA to SPI (required by HAL) + dma_rx.dma.Parent = &hspi; + dma_tx.dma.Parent = &hspi; + + if (e.config.data_size > DataSize::SIZE_16BIT) { + dma_rx.dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_rx.dma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dma_tx.dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_tx.dma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + } else if (e.config.data_size > DataSize::SIZE_8BIT) { + dma_rx.dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + dma_rx.dma.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; + dma_tx.dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + dma_tx.dma.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; + } + + HAL_DMA_Init(hspi.hdmarx); + HAL_DMA_Init(hspi.hdmatx); + + auto& init = hspi.Init; + if (e.mode == SPIMode::MASTER) { + init.Mode = SPI_MODE_MASTER; + // Baudrate prescaler calculation + uint32_t pclk_freq; + if (peripheral == SPIPeripheral::spi1 || + peripheral == SPIPeripheral::spi2 || + peripheral == SPIPeripheral::spi3) { + pclk_freq = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI123); + } else if (peripheral == SPIPeripheral::spi4 || + peripheral == SPIPeripheral::spi5) { + pclk_freq = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI45); + } else { + pclk_freq = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI6); + } + init.BaudRatePrescaler = calculate_prescaler(pclk_freq, e.max_baudrate); + } else { + init.Mode = SPI_MODE_SLAVE; + } + + init.NSS = SPIConfigTypes::translate_nss_mode(e.config.nss_mode, e.mode == SPIMode::MASTER); + init.Direction = SPIConfigTypes::translate_direction(e.config.direction); + init.DataSize = SPIConfigTypes::translate_data_size(e.config.data_size); + init.CLKPolarity = SPIConfigTypes::translate_clock_polarity(e.config.polarity); + init.CLKPhase = SPIConfigTypes::translate_clock_phase(e.config.phase); + init.FirstBit = SPIConfigTypes::translate_bit_order(e.config.bit_order); + init.TIMode = SPIConfigTypes::translate_ti_mode(e.config.ti_mode); + init.CRCCalculation = SPIConfigTypes::translate_crc_calculation(e.config.crc_calculation); + if (e.config.crc_calculation) { + init.CRCPolynomial = e.config.crc_polynomial; + init.CRCLength = SPIConfigTypes::translate_crc_length(e.config.crc_length); + } + init.NSSPMode = SPIConfigTypes::translate_nss_pulse(e.config.nss_pulse); + init.NSSPolarity = SPIConfigTypes::translate_nss_polarity(e.config.nss_polarity); + init.FifoThreshold = SPIConfigTypes::translate_fifo_threshold(e.config.fifo_threshold); + init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN; + init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN; + init.MasterSSIdleness = SPIConfigTypes::translate_ss_idleness(e.config.master_ss_idleness); + init.MasterInterDataIdleness = SPIConfigTypes::translate_interdata_idleness(e.config.master_interdata_idleness); + init.MasterReceiverAutoSusp = SPIConfigTypes::translate_rx_autosusp(e.config.master_rx_autosusp); + init.MasterKeepIOState = SPIConfigTypes::translate_keep_io_state(e.config.keep_io_state); + init.IOSwap = SPIConfigTypes::translate_io_swap(e.config.io_swap); + + if (HAL_SPI_Init(&hspi) != HAL_OK) { + ErrorHandler("Unable to init SPI%u", spi_number); + return; + } + + // Enable NVIC + if (peripheral == SPIPeripheral::spi1) { + HAL_NVIC_SetPriority(SPI1_IRQn, 1, 0); + HAL_NVIC_EnableIRQ(SPI1_IRQn); + } else if (peripheral == SPIPeripheral::spi2) { + HAL_NVIC_SetPriority(SPI2_IRQn, 1, 0); + HAL_NVIC_EnableIRQ(SPI2_IRQn); + } else if (peripheral == SPIPeripheral::spi3) { + HAL_NVIC_SetPriority(SPI3_IRQn, 1, 0); + HAL_NVIC_EnableIRQ(SPI3_IRQn); + } else if (peripheral == SPIPeripheral::spi4) { + HAL_NVIC_SetPriority(SPI4_IRQn, 1, 0); + HAL_NVIC_EnableIRQ(SPI4_IRQn); + } else if (peripheral == SPIPeripheral::spi5) { + HAL_NVIC_SetPriority(SPI5_IRQn, 1, 0); + HAL_NVIC_EnableIRQ(SPI5_IRQn); + } else if (peripheral == SPIPeripheral::spi6) { + HAL_NVIC_SetPriority(SPI6_IRQn, 1, 0); + HAL_NVIC_EnableIRQ(SPI6_IRQn); + } + + // Map instance pointer + if (peripheral == SPIPeripheral::spi1) { + spi_instances[0] = &instances[i]; + } else if (peripheral == SPIPeripheral::spi2) { + spi_instances[1] = &instances[i]; + } else if (peripheral == SPIPeripheral::spi3) { + spi_instances[2] = &instances[i]; + } else if (peripheral == SPIPeripheral::spi4) { + spi_instances[3] = &instances[i]; + } else if (peripheral == SPIPeripheral::spi5) { + spi_instances[4] = &instances[i]; + } else if (peripheral == SPIPeripheral::spi6) { + spi_instances[5] = &instances[i]; + } + } + } + }; +}; + +} // namespace ST_LIB + + +#endif // SPI2_HPP \ No newline at end of file diff --git a/Inc/HALAL/Models/SPI/SPIConfig.hpp b/Inc/HALAL/Models/SPI/SPIConfig.hpp new file mode 100644 index 000000000..0215de56d --- /dev/null +++ b/Inc/HALAL/Models/SPI/SPIConfig.hpp @@ -0,0 +1,295 @@ +/* + * SPIConfig.hpp + * + * Created on: 19 jan. 2026 + * Author: Boris + */ + +#ifndef SPICONFIG_HPP +#define SPICONFIG_HPP + +#include "C++Utilities/CppImports.hpp" +#include "ErrorHandler/ErrorHandler.hpp" + +namespace ST_LIB { + +struct SPIConfigTypes { + + enum class ClockPolarity : bool { + LOW = false, // Clock idle state is low (CPOL=0) + HIGH = true // Clock idle state is high (CPOL=1) + }; + + enum class ClockPhase : bool { + FIRST_EDGE = false, // Data sampled on first clock edge (CPHA=0) + SECOND_EDGE = true // Data sampled on second clock edge (CPHA=1) + }; + + enum class BitOrder : bool { + MSB_FIRST = false, + LSB_FIRST = true + }; + + enum class NSSMode { + SOFTWARE, // Software NSS management (manual control) + HARDWARE // Hardware NSS management (automatic) + }; + + enum class DataSize : uint8_t { + SIZE_4BIT = 4, + SIZE_5BIT = 5, + SIZE_6BIT = 6, + SIZE_7BIT = 7, + SIZE_8BIT = 8, + SIZE_9BIT = 9, + SIZE_10BIT = 10, + SIZE_11BIT = 11, + SIZE_12BIT = 12, + SIZE_13BIT = 13, + SIZE_14BIT = 14, + SIZE_15BIT = 15, + SIZE_16BIT = 16, + SIZE_17BIT = 17, + SIZE_18BIT = 18, + SIZE_19BIT = 19, + SIZE_20BIT = 20, + SIZE_21BIT = 21, + SIZE_22BIT = 22, + SIZE_23BIT = 23, + SIZE_24BIT = 24, + SIZE_25BIT = 25, + SIZE_26BIT = 26, + SIZE_27BIT = 27, + SIZE_28BIT = 28, + SIZE_29BIT = 29, + SIZE_30BIT = 30, + SIZE_31BIT = 31, + SIZE_32BIT = 32 + }; + + enum class Direction { + FULL_DUPLEX, // 2-line bidirectional (most common) + HALF_DUPLEX, // 1-line bidirectional + SIMPLEX_TX_ONLY, // Transmit only + SIMPLEX_RX_ONLY // Receive only + }; + + enum class FIFOThreshold : uint8_t { + THRESHOLD_01DATA = 1, + THRESHOLD_02DATA = 2, + THRESHOLD_03DATA = 3, + THRESHOLD_04DATA = 4, + THRESHOLD_05DATA = 5, + THRESHOLD_06DATA = 6, + THRESHOLD_07DATA = 7, + THRESHOLD_08DATA = 8, + THRESHOLD_09DATA = 9, + THRESHOLD_10DATA = 10, + THRESHOLD_11DATA = 11, + THRESHOLD_12DATA = 12, + THRESHOLD_13DATA = 13, + THRESHOLD_14DATA = 14, + THRESHOLD_15DATA = 15, + THRESHOLD_16DATA = 16 + }; + + enum class NSSPolarity { + ACTIVE_LOW = false, + ACTIVE_HIGH = true + }; + + enum class CRCLength : uint8_t { + DATASIZE = 0, // CRC length matches data size + CRC_4BIT = 4, + CRC_5BIT = 5, + CRC_6BIT = 6, + CRC_7BIT = 7, + CRC_8BIT = 8, + CRC_9BIT = 9, + CRC_10BIT = 10, + CRC_11BIT = 11, + CRC_12BIT = 12, + CRC_13BIT = 13, + CRC_14BIT = 14, + CRC_15BIT = 15, + CRC_16BIT = 16, + CRC_17BIT = 17, + CRC_18BIT = 18, + CRC_19BIT = 19, + CRC_20BIT = 20, + CRC_21BIT = 21, + CRC_22BIT = 22, + CRC_23BIT = 23, + CRC_24BIT = 24, + CRC_25BIT = 25, + CRC_26BIT = 26, + CRC_27BIT = 27, + CRC_28BIT = 28, + CRC_29BIT = 29, + CRC_30BIT = 30, + CRC_31BIT = 31, + CRC_32BIT = 32 + }; + + /** + * @brief User-facing SPI configuration options + */ + struct SPIConfig { + // Core settings + ClockPolarity polarity = ClockPolarity::LOW; + ClockPhase phase = ClockPhase::FIRST_EDGE; + BitOrder bit_order = BitOrder::MSB_FIRST; + NSSMode nss_mode = NSSMode::HARDWARE; + + // Data format + DataSize data_size = DataSize::SIZE_8BIT; + Direction direction = Direction::FULL_DUPLEX; + FIFOThreshold fifo_threshold = FIFOThreshold::THRESHOLD_01DATA; + + // NSS settings + bool nss_pulse = false; // NSS pulse between data frames (master only) + NSSPolarity nss_polarity = NSSPolarity::ACTIVE_LOW; + + // Master timing settings + uint8_t master_ss_idleness = 0; // Cycles (0-15) between NSS and first data + uint8_t master_interdata_idleness = 0; // Cycles (0-15) between data frames + + // Advanced options + bool keep_io_state = true; // Keep pin states when idle (prevents floating) + bool master_rx_autosusp = false; // Auto-suspend in master RX mode to prevent overrun + bool io_swap = false; // Swap MISO/MOSI pins + + // Protocol options + bool ti_mode = false; // Enable TI synchronous serial frame format (Microwire compatible) + + // CRC options (hardware CRC calculation) + bool crc_calculation = false; // Enable hardware CRC calculation + uint32_t crc_polynomial = 0x07; // CRC polynomial (must be odd, default for CRC-8) + CRCLength crc_length = CRCLength::DATASIZE; // CRC length (default: matches data size) + + constexpr SPIConfig() = default; + + constexpr SPIConfig(ClockPolarity pol, ClockPhase ph, + BitOrder order = BitOrder::MSB_FIRST, + NSSMode nss = NSSMode::HARDWARE) + : polarity(pol), phase(ph), bit_order(order), nss_mode(nss) {} + + // Compile-time validation + constexpr void validate() const { + // Validate CRC polynomial if CRC is enabled + if (crc_calculation) { + if (crc_polynomial == 0 || crc_polynomial > 0xFFFF) { + compile_error("CRC polynomial must be between 1 and 65535"); + } + if ((crc_polynomial & 1) == 0) { + compile_error("CRC polynomial must be odd"); + } + } + + // Validate timing parameters + if (master_ss_idleness > 15) { + compile_error("master_ss_idleness must be 0-15"); + } + if (master_interdata_idleness > 15) { + compile_error("master_interdata_idleness must be 0-15"); + } + } + }; + + static constexpr uint32_t translate_nss_mode(NSSMode mode, bool is_master) { + if (mode == NSSMode::SOFTWARE) { + return SPI_NSS_SOFT; + } + // Hardware mode - depends on master/slave + return (is_master) ? SPI_NSS_HARD_OUTPUT : SPI_NSS_HARD_INPUT; + } + + // Translation functions from custom config to HAL constants + static constexpr uint32_t translate_clock_polarity(ClockPolarity pol) { + return (pol == ClockPolarity::LOW) ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH; + } + + static constexpr uint32_t translate_clock_phase(ClockPhase phase) { + return (phase == ClockPhase::FIRST_EDGE) ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE; + } + + static constexpr uint32_t translate_bit_order(BitOrder order) { + return (order == BitOrder::MSB_FIRST) ? SPI_FIRSTBIT_MSB : SPI_FIRSTBIT_LSB; + } + + static constexpr uint32_t translate_data_size(DataSize size) { + // HAL uses SIZE-1 (e.g., 8 bits = 0x07) + return static_cast(size) - 1; + } + + static constexpr uint32_t translate_direction(Direction dir) { + switch (dir) { + case Direction::FULL_DUPLEX: + return SPI_DIRECTION_2LINES; + case Direction::HALF_DUPLEX: + return SPI_DIRECTION_1LINE; + case Direction::SIMPLEX_TX_ONLY: + return SPI_DIRECTION_2LINES_TXONLY; + case Direction::SIMPLEX_RX_ONLY: + return SPI_DIRECTION_2LINES_RXONLY; + } + return SPI_DIRECTION_2LINES; + } + + static constexpr uint32_t translate_fifo_threshold(FIFOThreshold threshold) { + // HAL uses (value-1) << 5 for FIFO threshold + return (static_cast(threshold) - 1) << 5; + } + + static constexpr uint32_t translate_nss_polarity(NSSPolarity pol) { + return (pol == NSSPolarity::ACTIVE_LOW) ? SPI_NSS_POLARITY_LOW : SPI_NSS_POLARITY_HIGH; + } + + static constexpr uint32_t translate_nss_pulse(bool enable) { + return enable ? SPI_NSS_PULSE_ENABLE : SPI_NSS_PULSE_DISABLE; + } + + static constexpr uint32_t translate_ss_idleness(uint8_t cycles) { + // Clamp to valid range 0-15 + if (cycles > 15) cycles = 15; + return cycles; + } + + static constexpr uint32_t translate_interdata_idleness(uint8_t cycles) { + // Clamp to valid range 0-15, shift to proper position + if (cycles > 15) cycles = 15; + return (cycles << 4); // These are in bits 7:4 of CFG2 + } + + static constexpr uint32_t translate_keep_io_state(bool enable) { + return enable ? SPI_MASTER_KEEP_IO_STATE_ENABLE : SPI_MASTER_KEEP_IO_STATE_DISABLE; + } + + static constexpr uint32_t translate_rx_autosusp(bool enable) { + return enable ? SPI_MASTER_RX_AUTOSUSP_ENABLE : SPI_MASTER_RX_AUTOSUSP_DISABLE; + } + + static constexpr uint32_t translate_io_swap(bool enable) { + return enable ? SPI_IO_SWAP_ENABLE : SPI_IO_SWAP_DISABLE; + } + + static constexpr uint32_t translate_ti_mode(bool enable) { + return enable ? SPI_TIMODE_ENABLE : SPI_TIMODE_DISABLE; + } + + static constexpr uint32_t translate_crc_calculation(bool enable) { + return enable ? SPI_CRCCALCULATION_ENABLE : SPI_CRCCALCULATION_DISABLE; + } + + static constexpr uint32_t translate_crc_length(CRCLength length) { + if (length == CRCLength::DATASIZE) { + return SPI_CRC_LENGTH_DATASIZE; + } + // HAL uses (value-1) << 16 for CRC length + return (static_cast(length) - 1) << 16; + } +}; + +} // namespace ST_LIB + +#endif // SPICONFIG_HPP diff --git a/Inc/HALAL/Services/ADC/ADC.hpp b/Inc/HALAL/Services/ADC/ADC.hpp index 633dba883..2c17d0a16 100644 --- a/Inc/HALAL/Services/ADC/ADC.hpp +++ b/Inc/HALAL/Services/ADC/ADC.hpp @@ -42,11 +42,10 @@ class ADC { uint32_t resolution; uint32_t external_trigger; vector channels; - DMA::Stream dma_stream; string name; InitData() = default; - InitData(ADC_TypeDef* adc, uint32_t resolution, uint32_t external_trigger, vector& channels, DMA::Stream dma_stream, string name); + InitData(ADC_TypeDef* adc, uint32_t resolution, uint32_t external_trigger, vector& channels, string name); }; class Peripheral { diff --git a/Inc/HALAL/Services/Communication/I2C/I2C.hpp b/Inc/HALAL/Services/Communication/I2C/I2C.hpp index 53c57388a..16f2adb23 100644 --- a/Inc/HALAL/Services/Communication/I2C/I2C.hpp +++ b/Inc/HALAL/Services/Communication/I2C/I2C.hpp @@ -33,8 +33,6 @@ class I2C { Pin &SDA; I2C_HandleTypeDef *hi2c; I2C_TypeDef *instance; - DMA::Stream RX_DMA; - DMA::Stream TX_DMA; uint8_t address = 0; uint32_t speed_frequency_kHz = 100; uint32_t data_length_in_bits = 8; diff --git a/Inc/HALAL/Services/Communication/SPI/SPI.hpp b/Inc/HALAL/Services/Communication/SPI/SPI.hpp index 99000a78f..ad3af9a79 100644 --- a/Inc/HALAL/Services/Communication/SPI/SPI.hpp +++ b/Inc/HALAL/Services/Communication/SPI/SPI.hpp @@ -55,8 +55,7 @@ class SPI{ SPI_HandleTypeDef* hspi; /**< HAL spi struct pin. */ SPI_TypeDef* instance; /**< HAL spi instance. */ - DMA::Stream hdma_tx; /**< HAL DMA handler for writting */ - DMA::Stream hdma_rx; /**< HAL DMA handler for reading */ + uint32_t baud_rate_prescaler; /**< SPI baud prescaler.*/ uint32_t mode = SPI_MODE_MASTER; /**< SPI mode. */ diff --git a/Inc/HALAL/Services/FMAC/FMAC.hpp b/Inc/HALAL/Services/FMAC/FMAC.hpp index 9348dd94c..65ad277f2 100644 --- a/Inc/HALAL/Services/FMAC/FMAC.hpp +++ b/Inc/HALAL/Services/FMAC/FMAC.hpp @@ -58,10 +58,6 @@ class MultiplierAccelerator{ struct FMACInstance{ FMACmodes mode; FMAC_HandleTypeDef *hfmac; - DMA::Stream dma_preload; - DMA::Stream dma_read; - DMA::Stream dma_write; - }; static FMACInstance Instance; diff --git a/Inc/ST-LIB.hpp b/Inc/ST-LIB.hpp index a9acb61f2..f717542e2 100644 --- a/Inc/ST-LIB.hpp +++ b/Inc/ST-LIB.hpp @@ -83,9 +83,9 @@ template struct BuildCtx { } }; -using DomainsCtx = BuildCtx; +using DomainsCtx = BuildCtx; template struct Board { static consteval auto build_ctx() { @@ -101,33 +101,41 @@ template struct Board { } static consteval auto build() { + constexpr std::size_t mpuN = domain_size(); constexpr std::size_t gpioN = domain_size(); constexpr std::size_t timN = domain_size(); + constexpr std::size_t dmaN = domain_size(); constexpr std::size_t doutN = domain_size(); constexpr std::size_t dinN = domain_size(); - constexpr std::size_t mpuN = domain_size(); + constexpr std::size_t spiN = domain_size(); // ... struct ConfigBundle { + std::array mpu_cfgs; std::array gpio_cfgs; std::array tim_cfgs; + std::array dma_cfgs; std::array dout_cfgs; std::array din_cfgs; - std::array mpu_cfgs; + std::array spi_cfgs; // ... }; return ConfigBundle{ + .mpu_cfgs = MPUDomain::template build( + ctx.template span()), .gpio_cfgs = GPIODomain::template build(ctx.template span()), .tim_cfgs = TimerDomain::template build(ctx.template span()), + .dma_cfgs = DMA_Domain::template build( + ctx.template span()), .dout_cfgs = DigitalOutputDomain::template build( ctx.template span()), .din_cfgs = DigitalInputDomain::template build( ctx.template span()), - .mpu_cfgs = MPUDomain::template build( - ctx.template span()) + .spi_cfgs = SPIDomain::template build( + ctx.template span()) // ... }; } @@ -135,20 +143,26 @@ template struct Board { static constexpr auto cfg = build(); static void init() { + constexpr std::size_t mpuN = domain_size(); constexpr std::size_t gpioN = domain_size(); constexpr std::size_t timN = domain_size(); + constexpr std::size_t dmaN = domain_size(); constexpr std::size_t doutN = domain_size(); constexpr std::size_t dinN = domain_size(); - constexpr std::size_t mpuN = domain_size(); + constexpr std::size_t spiN = domain_size(); // ... + MPUDomain::Init::init(); GPIODomain::Init::init(cfg.gpio_cfgs); TimerDomain::Init::init(cfg.tim_cfgs); + DMA_Domain::Init::init(cfg.dma_cfgs); DigitalOutputDomain::Init::init(cfg.dout_cfgs, GPIODomain::Init::instances); DigitalInputDomain::Init::init(cfg.din_cfgs, GPIODomain::Init::instances); - MPUDomain::Init::init(); + SPIDomain::Init::init(cfg.spi_cfgs, + GPIODomain::Init::instances, + DMA_Domain::Init::instances); // ... } diff --git a/Inc/stm32h7xx_hal_conf_template.h b/Inc/stm32h7xx_hal_conf_template.h index 4f41c7d25..74fdc0c32 100644 --- a/Inc/stm32h7xx_hal_conf_template.h +++ b/Inc/stm32h7xx_hal_conf_template.h @@ -233,7 +233,7 @@ * @brief Uncomment the line below to expanse the "assert_param" macro in the * HAL drivers code */ -/* #define USE_FULL_ASSERT 1U */ +#define USE_FULL_ASSERT 1 /* Includes ------------------------------------------------------------------*/ diff --git a/Src/HALAL/HALAL.cpp b/Src/HALAL/HALAL.cpp index f35056527..f10963eb3 100644 --- a/Src/HALAL/HALAL.cpp +++ b/Src/HALAL/HALAL.cpp @@ -33,7 +33,7 @@ static void common_start(UART::Peripheral &printf_peripheral) { #endif #ifdef HAL_DMA_MODULE_ENABLED - DMA::start(); + // DMA::start(); #endif #ifdef HAL_MDMA_MODULE_ENABLED diff --git a/Src/HALAL/Models/DMA/DMA.cpp b/Src/HALAL/Models/DMA/DMA.cpp.tmp similarity index 82% rename from Src/HALAL/Models/DMA/DMA.cpp rename to Src/HALAL/Models/DMA/DMA.cpp.tmp index e9982734d..bfc875a9c 100644 --- a/Src/HALAL/Models/DMA/DMA.cpp +++ b/Src/HALAL/Models/DMA/DMA.cpp.tmp @@ -5,6 +5,11 @@ * Author: aleja */ + +# Para que este codigo conviva con la nueva dma hay que forzarlo un pelin. Yo (Jorge no pm), creo que la DMA nueva puede funcionar para todos los perifericos. En caso +# de que no sea asi, cambiare esto para que funcione (sera solo un momentito) + + #include "HALAL/Models/DMA/DMA.hpp" #include "ErrorHandler/ErrorHandler.hpp" @@ -38,4 +43,4 @@ void DMA::start() { HAL_NVIC_SetPriority( (IRQn_Type)dma_stream, 0, 0); HAL_NVIC_EnableIRQ( (IRQn_Type)dma_stream); } -} +} \ No newline at end of file diff --git a/Src/HALAL/Models/DMA/DMA2.cpp b/Src/HALAL/Models/DMA/DMA2.cpp new file mode 100644 index 000000000..27e1c9ac4 --- /dev/null +++ b/Src/HALAL/Models/DMA/DMA2.cpp @@ -0,0 +1,66 @@ +#include "HALAL/Models/DMA/DMA2.hpp" + + +extern "C" void DMA1_Stream0_IRQHandler(void) { + HAL_DMA_IRQHandler(dma_irq_table[0]); +} + +extern "C" void DMA1_Stream1_IRQHandler(void) { + HAL_DMA_IRQHandler(dma_irq_table[1]); +} + +extern "C" void DMA1_Stream2_IRQHandler(void) { + HAL_DMA_IRQHandler(dma_irq_table[2]); +} + +extern "C" void DMA1_Stream3_IRQHandler(void) { + HAL_DMA_IRQHandler(dma_irq_table[3]); +} + +extern "C" void DMA1_Stream4_IRQHandler(void) { + HAL_DMA_IRQHandler(dma_irq_table[4]); +} + +extern "C" void DMA1_Stream5_IRQHandler(void) { + HAL_DMA_IRQHandler(dma_irq_table[5]); +} + +extern "C" void DMA1_Stream6_IRQHandler(void) { + HAL_DMA_IRQHandler(dma_irq_table[6]); +} + +extern "C" void DMA1_Stream7_IRQHandler(void) { + HAL_DMA_IRQHandler(dma_irq_table[7]); +} + +extern "C" void DMA2_Stream0_IRQHandler(void) { + HAL_DMA_IRQHandler(dma_irq_table[8]); +} + +extern "C" void DMA2_Stream1_IRQHandler(void) { + HAL_DMA_IRQHandler(dma_irq_table[9]); +} + +extern "C" void DMA2_Stream2_IRQHandler(void) { + HAL_DMA_IRQHandler(dma_irq_table[10]); +} + +extern "C" void DMA2_Stream3_IRQHandler(void) { + HAL_DMA_IRQHandler(dma_irq_table[11]); +} + +extern "C" void DMA2_Stream4_IRQHandler(void) { + HAL_DMA_IRQHandler(dma_irq_table[12]); +} + +extern "C" void DMA2_Stream5_IRQHandler(void) { + HAL_DMA_IRQHandler(dma_irq_table[13]); +} + +extern "C" void DMA2_Stream6_IRQHandler(void) { + HAL_DMA_IRQHandler(dma_irq_table[14]); +} + +extern "C" void DMA2_Stream7_IRQHandler(void) { + HAL_DMA_IRQHandler(dma_irq_table[15]); +} diff --git a/Src/HALAL/Models/SPI/SPI2.cpp b/Src/HALAL/Models/SPI/SPI2.cpp new file mode 100644 index 000000000..f83ea553c --- /dev/null +++ b/Src/HALAL/Models/SPI/SPI2.cpp @@ -0,0 +1,139 @@ +#include "HALAL/Models/SPI/SPI2.hpp" +uint32_t ST_LIB::SPIDomain::calculate_prescaler(uint32_t src_freq, uint32_t max_baud) { + uint32_t prescaler = 2; // Smallest prescaler available + + while ((src_freq / prescaler) > max_baud) { + prescaler *= 2; // Prescaler doubles each step (it must be a power of 2) + + if (prescaler > 256) { + ErrorHandler("Cannot achieve desired baudrate, speed is too low"); + } + } + + return get_prescaler_flag(prescaler); +} + +extern "C" { + +/** + * ========================================= + * IRQ Handlers + * ========================================= + */ + +void SPI1_IRQHandler(void) { + auto inst = ST_LIB::SPIDomain::spi_instances[0]; + if (inst == nullptr) { + ErrorHandler("SPI1 IRQ Handler called but instance is null"); + return; + } + HAL_SPI_IRQHandler(&inst->hspi); +} +void SPI2_IRQHandler(void) { + auto inst = ST_LIB::SPIDomain::spi_instances[1]; + if (inst == nullptr) { + ErrorHandler("SPI2 IRQ Handler called but instance is null"); + return; + } + HAL_SPI_IRQHandler(&inst->hspi); +} +void SPI3_IRQHandler(void) { + auto inst = ST_LIB::SPIDomain::spi_instances[2]; + if (inst == nullptr) { + ErrorHandler("SPI3 IRQ Handler called but instance is null"); + return; + } + HAL_SPI_IRQHandler(&inst->hspi); +} +void SPI4_IRQHandler(void) { + auto inst = ST_LIB::SPIDomain::spi_instances[3]; + if (inst == nullptr) { + ErrorHandler("SPI4 IRQ Handler called but instance is null"); + return; + } + HAL_SPI_IRQHandler(&inst->hspi); +} +void SPI5_IRQHandler(void) { + auto inst = ST_LIB::SPIDomain::spi_instances[4]; + if (inst == nullptr) { + ErrorHandler("SPI5 IRQ Handler called but instance is null"); + return; + } + HAL_SPI_IRQHandler(&inst->hspi); +} +void SPI6_IRQHandler(void) { + auto inst = ST_LIB::SPIDomain::spi_instances[5]; + if (inst == nullptr) { + ErrorHandler("SPI6 IRQ Handler called but instance is null"); + return; + } + HAL_SPI_IRQHandler(&inst->hspi); +} + + +/** + * ========================================= + * HAL Callbacks + * ========================================= + */ + +void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) { + auto& spi_instances = ST_LIB::SPIDomain::spi_instances; + + ST_LIB::SPIDomain::Instance* inst = nullptr; + if (spi_instances[0] != nullptr && hspi == &spi_instances[0]->hspi) { + inst = spi_instances[0]; + } else if (spi_instances[1] != nullptr && hspi == &spi_instances[1]->hspi) { + inst = spi_instances[1]; + } else if (spi_instances[2] != nullptr && hspi == &spi_instances[2]->hspi) { + inst = spi_instances[2]; + } else if (spi_instances[3] != nullptr && hspi == &spi_instances[3]->hspi) { + inst = spi_instances[3]; + } else if (spi_instances[4] != nullptr && hspi == &spi_instances[4]->hspi) { + inst = spi_instances[4]; + } else if (spi_instances[5] != nullptr && hspi == &spi_instances[5]->hspi) { + inst = spi_instances[5]; + } else { + ErrorHandler("SPI IRQ Callback called but instance is null"); + return; + } + + if (inst->operation_flag != nullptr) { + *(inst->operation_flag) = true; + } +} + +void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) { + HAL_SPI_TxCpltCallback(hspi); // Same logic +} + +void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) { + HAL_SPI_TxCpltCallback(hspi); // Same logic +} + +void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) { + auto& spi_instances = ST_LIB::SPIDomain::spi_instances; + + uint32_t error_code = hspi->ErrorCode; + uint32_t inst_idx = 0; + if (spi_instances[0] != nullptr && hspi == &spi_instances[0]->hspi) { + inst_idx = 0; + } else if (spi_instances[1] != nullptr && hspi == &spi_instances[1]->hspi) { + inst_idx = 1; + } else if (spi_instances[2] != nullptr && hspi == &spi_instances[2]->hspi) { + inst_idx = 2; + } else if (spi_instances[3] != nullptr && hspi == &spi_instances[3]->hspi) { + inst_idx = 3; + } else if (spi_instances[4] != nullptr && hspi == &spi_instances[4]->hspi) { + inst_idx = 4; + } else if (spi_instances[5] != nullptr && hspi == &spi_instances[5]->hspi) { + inst_idx = 5; + } else { + ErrorHandler("SPI IRQ Callback called but instance is null"); + return; + } + + ErrorHandler("SPI%i failed with error number %u", inst_idx + 1, error_code); +} + +} \ No newline at end of file diff --git a/Src/HALAL/Services/ADC/ADC.cpp b/Src/HALAL/Services/ADC/ADC.cpp index d63e3b920..4ec12705a 100644 --- a/Src/HALAL/Services/ADC/ADC.cpp +++ b/Src/HALAL/Services/ADC/ADC.cpp @@ -16,8 +16,8 @@ uint8_t ADC::id_counter = 0; unordered_map ADC::active_instances = {}; -ADC::InitData::InitData(ADC_TypeDef* adc, uint32_t resolution, uint32_t external_trigger, vector& channels, DMA::Stream dma_stream, string name) : - adc(adc), resolution(resolution), external_trigger(external_trigger), channels(channels), dma_stream(dma_stream), name(name) {} +ADC::InitData::InitData(ADC_TypeDef* adc, uint32_t resolution, uint32_t external_trigger, vector& channels, string name) : + adc(adc), resolution(resolution), external_trigger(external_trigger), channels(channels), name(name) {} ADC::Peripheral::Peripheral(ADC_HandleTypeDef* handle, LowPowerTimer& timer, InitData& init_data) : handle(handle), timer(timer), init_data(init_data) { @@ -42,7 +42,7 @@ uint8_t ADC::inscribe(Pin pin) { InitData& init_data = active_instances[id_counter].peripheral->init_data; - DMA::inscribe_stream(init_data.dma_stream); + active_instances[id_counter].rank = init_data.channels.size(); init_data.channels.push_back(active_instances[id_counter].channel); return id_counter++; @@ -68,7 +68,7 @@ void ADC::turn_on(uint8_t id){ uint32_t buffer_length = peripheral->init_data.channels.size(); if (HAL_ADC_Start_DMA(peripheral->handle, (uint32_t*) peripheral->dma_data_buffer, buffer_length) != HAL_OK) { - ErrorHandler("DMA - %d - of ADC - %d - did not start correctly", peripheral->init_data.dma_stream, id); + ErrorHandler("DMA - %d - of ADC - %d - did not start correctly", id); return; } diff --git a/Src/HALAL/Services/Communication/I2C/I2C.cpp b/Src/HALAL/Services/Communication/I2C/I2C.cpp index 61655d304..967b9eb07 100644 --- a/Src/HALAL/Services/Communication/I2C/I2C.cpp +++ b/Src/HALAL/Services/Communication/I2C/I2C.cpp @@ -23,8 +23,7 @@ uint8_t I2C::inscribe(I2C::Peripheral &i2c, uint8_t address) { Pin::inscribe(i2c_instance->SCL, ALTERNATIVE); Pin::inscribe(i2c_instance->SDA, ALTERNATIVE); - DMA::inscribe_stream(i2c_instance->RX_DMA); - DMA::inscribe_stream(i2c_instance->TX_DMA); + //DMA::inscribe_stream(i2c_instance->hi2c); uint8_t id = I2C::id_counter++; diff --git a/Src/HALAL/Services/Communication/SPI/SPI.cpp b/Src/HALAL/Services/Communication/SPI/SPI.cpp index 9b498b12b..007f1f0e2 100644 --- a/Src/HALAL/Services/Communication/SPI/SPI.cpp +++ b/Src/HALAL/Services/Communication/SPI/SPI.cpp @@ -56,8 +56,7 @@ uint8_t SPI::inscribe(SPI::Peripheral& spi) { uint8_t id = SPI::id_counter++; if (spi_instance->use_DMA) { - DMA::inscribe_stream(spi_instance->hdma_rx); - DMA::inscribe_stream(spi_instance->hdma_tx); + //DMA::inscribe_stream(spi_instance->hspi); } SPI::registered_spi[id] = spi_instance; SPI::registered_spi_by_handler[spi_instance->hspi] = spi_instance; @@ -433,130 +432,130 @@ void SPI::init(SPI::Instance* spi) { spi->initialized = true; } -void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef* hspi) { - if (!SPI::registered_spi_by_handler.contains(hspi)) { - ErrorHandler("Used SPI protocol without the HALAL SPI interface"); - return; - } - - SPI::Instance* spi = SPI::registered_spi_by_handler[hspi]; - switch (spi->state) { - case SPI::IDLE: - // Does nothing as there is no Order handling on a direct send - break; - case SPI::STARTING_ORDER: { - SPIBaseOrder* Order = - SPIBaseOrder::SPIOrdersByID[*(spi->SPIOrderID)]; - if (spi->mode == - SPI_MODE_MASTER) { // checks if the Order is ready on slave - if (*(spi->available_end) == *(spi->SPIOrderID)) { - spi->state = SPI::PROCESSING_ORDER; - Order->master_prepare_buffer(spi->tx_buffer); - SPI::turn_off_chip_select(spi); - - SPI::spi_communicate_order_data( - spi, spi->tx_buffer, spi->rx_buffer, - Order->payload_size - PAYLOAD_OVERHEAD); - } else { - spi->try_count++; - switch (*(spi->available_end)) { - case NO_ORDER_ID: { - spi->last_end_check = Time::get_global_tick(); - SPI::turn_on_chip_select(spi); - } break; - default: - case ERROR_ORDER_ID: { - spi->last_end_check = Time::get_global_tick(); - spi->error_count++; - SPI::turn_on_chip_select(spi); - } break; - } - } - } else { - ErrorHandler("Used master transmit Order on a slave spi"); - } - break; - } - case SPI::WAITING_ORDER: { - SPIBaseOrder* Order = - SPIBaseOrder::SPIOrdersByID[*(spi->SPIOrderID)]; - if (Order == 0x0) { - SPI::spi_recover(spi, hspi); - return; - } else if (spi->mode == - SPI_MODE_SLAVE) { // prepares the Order on the slave - Order->slave_prepare_buffer(spi->tx_buffer); - SPI::spi_communicate_order_data( - spi, spi->tx_buffer, spi->rx_buffer, Order->payload_size); - SPI::mark_slave_ready(spi); - spi->state = SPI::PROCESSING_ORDER; - } else { - ErrorHandler("Used slave process Orders on a master spi"); - } - break; - } - case SPI::PROCESSING_ORDER: { - SPIBaseOrder* Order = - SPIBaseOrder::SPIOrdersByID[*(spi->SPIOrderID)]; - - if (spi->mode == SPI_MODE_MASTER) { // ends communication - if (*(uint16_t*)&spi - ->rx_buffer[Order->CRC_index - PAYLOAD_OVERHEAD] != - *spi->SPIOrderID) { - spi->state = SPI::STARTING_ORDER; - SPI::master_check_available_end(spi); - return; - } - spi->Order_count++; - SPI::turn_on_chip_select(spi); - Order->master_process_callback(spi->rx_buffer); - spi->state = SPI::IDLE; - } else { // prepares the next received Order - if (*(uint16_t*)&spi->rx_buffer[Order->CRC_index] != - *spi->SPIOrderID) { - SPI::spi_recover(spi, hspi); - return; - } - spi->Order_count++; - SPI::mark_slave_waiting(spi); - *(spi->SPIOrderID) = NO_ORDER_ID; - *(spi->available_end) = NO_ORDER_ID; - Order->slave_process_callback(spi->rx_buffer); - SPI::slave_check_packet_ID(spi); - spi->state = SPI::WAITING_ORDER; - } - break; - } - case SPI::ERROR_RECOVERY: { - if (spi->mode == SPI_MODE_MASTER) { - // TODO - } else { - SPI::mark_slave_waiting(spi); - spi->state = - SPI::WAITING_ORDER; // prepares the next received Order - *(spi->SPIOrderID) = NO_ORDER_ID; - *(spi->available_end) = NO_ORDER_ID; - SPI::slave_check_packet_ID(spi); - } - break; - } - default: - ErrorHandler("Unknown spi state: %d", spi->state); - break; - } -} - -void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef* hspi) {} - -void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef* hspi) {} - -void HAL_SPI_ErrorCallback(SPI_HandleTypeDef* hspi) { - if ((hspi->ErrorCode & HAL_SPI_ERROR_UDR) != 0) { - SPI::spi_recover(SPI::registered_spi_by_handler[hspi], hspi); - } else { - ErrorHandler("SPI error number %u", hspi->ErrorCode); - } -} +// void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef* hspi) { +// if (!SPI::registered_spi_by_handler.contains(hspi)) { +// ErrorHandler("Used SPI protocol without the HALAL SPI interface"); +// return; +// } + +// SPI::Instance* spi = SPI::registered_spi_by_handler[hspi]; +// switch (spi->state) { +// case SPI::IDLE: +// // Does nothing as there is no Order handling on a direct send +// break; +// case SPI::STARTING_ORDER: { +// SPIBaseOrder* Order = +// SPIBaseOrder::SPIOrdersByID[*(spi->SPIOrderID)]; +// if (spi->mode == +// SPI_MODE_MASTER) { // checks if the Order is ready on slave +// if (*(spi->available_end) == *(spi->SPIOrderID)) { +// spi->state = SPI::PROCESSING_ORDER; +// Order->master_prepare_buffer(spi->tx_buffer); +// SPI::turn_off_chip_select(spi); + +// SPI::spi_communicate_order_data( +// spi, spi->tx_buffer, spi->rx_buffer, +// Order->payload_size - PAYLOAD_OVERHEAD); +// } else { +// spi->try_count++; +// switch (*(spi->available_end)) { +// case NO_ORDER_ID: { +// spi->last_end_check = Time::get_global_tick(); +// SPI::turn_on_chip_select(spi); +// } break; +// default: +// case ERROR_ORDER_ID: { +// spi->last_end_check = Time::get_global_tick(); +// spi->error_count++; +// SPI::turn_on_chip_select(spi); +// } break; +// } +// } +// } else { +// ErrorHandler("Used master transmit Order on a slave spi"); +// } +// break; +// } +// case SPI::WAITING_ORDER: { +// SPIBaseOrder* Order = +// SPIBaseOrder::SPIOrdersByID[*(spi->SPIOrderID)]; +// if (Order == 0x0) { +// SPI::spi_recover(spi, hspi); +// return; +// } else if (spi->mode == +// SPI_MODE_SLAVE) { // prepares the Order on the slave +// Order->slave_prepare_buffer(spi->tx_buffer); +// SPI::spi_communicate_order_data( +// spi, spi->tx_buffer, spi->rx_buffer, Order->payload_size); +// SPI::mark_slave_ready(spi); +// spi->state = SPI::PROCESSING_ORDER; +// } else { +// ErrorHandler("Used slave process Orders on a master spi"); +// } +// break; +// } +// case SPI::PROCESSING_ORDER: { +// SPIBaseOrder* Order = +// SPIBaseOrder::SPIOrdersByID[*(spi->SPIOrderID)]; + +// if (spi->mode == SPI_MODE_MASTER) { // ends communication +// if (*(uint16_t*)&spi +// ->rx_buffer[Order->CRC_index - PAYLOAD_OVERHEAD] != +// *spi->SPIOrderID) { +// spi->state = SPI::STARTING_ORDER; +// SPI::master_check_available_end(spi); +// return; +// } +// spi->Order_count++; +// SPI::turn_on_chip_select(spi); +// Order->master_process_callback(spi->rx_buffer); +// spi->state = SPI::IDLE; +// } else { // prepares the next received Order +// if (*(uint16_t*)&spi->rx_buffer[Order->CRC_index] != +// *spi->SPIOrderID) { +// SPI::spi_recover(spi, hspi); +// return; +// } +// spi->Order_count++; +// SPI::mark_slave_waiting(spi); +// *(spi->SPIOrderID) = NO_ORDER_ID; +// *(spi->available_end) = NO_ORDER_ID; +// Order->slave_process_callback(spi->rx_buffer); +// SPI::slave_check_packet_ID(spi); +// spi->state = SPI::WAITING_ORDER; +// } +// break; +// } +// case SPI::ERROR_RECOVERY: { +// if (spi->mode == SPI_MODE_MASTER) { +// // TODO +// } else { +// SPI::mark_slave_waiting(spi); +// spi->state = +// SPI::WAITING_ORDER; // prepares the next received Order +// *(spi->SPIOrderID) = NO_ORDER_ID; +// *(spi->available_end) = NO_ORDER_ID; +// SPI::slave_check_packet_ID(spi); +// } +// break; +// } +// default: +// ErrorHandler("Unknown spi state: %d", spi->state); +// break; +// } +// } + +// // void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef* hspi) {} + +// // void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef* hspi) {} + +// // void HAL_SPI_ErrorCallback(SPI_HandleTypeDef* hspi) { +// // if ((hspi->ErrorCode & HAL_SPI_ERROR_UDR) != 0) { +// // SPI::spi_recover(SPI::registered_spi_by_handler[hspi], hspi); +// // } else { +// // ErrorHandler("SPI error number %u", hspi->ErrorCode); +// // } +// // } void SPI::spi_communicate_order_data(SPI::Instance* spi, uint8_t* value_to_send, uint8_t* value_to_receive, diff --git a/Src/HALAL/Services/FMAC/FMAC.cpp b/Src/HALAL/Services/FMAC/FMAC.cpp index 6b07bb19f..d7885689c 100644 --- a/Src/HALAL/Services/FMAC/FMAC.cpp +++ b/Src/HALAL/Services/FMAC/FMAC.cpp @@ -32,9 +32,7 @@ void MultiplierAccelerator::IIR_software_in_software_out_inscribe(uint16_t input } void MultiplierAccelerator::inscribe(){ - DMA::inscribe_stream(Instance.dma_preload); - DMA::inscribe_stream(Instance.dma_read); - DMA::inscribe_stream(Instance.dma_write); + //DMA::inscribe_stream(Instance.hfmac); } void MultiplierAccelerator::start(){