#ifndef STM32U5XX_HAL_SPI_HPP #define STM32U5XX_HAL_SPI_HPP #include "global_variable.h" #include "stdint.h" #include "stdlib.h" #include "stm32u575xx.h" #include "stm32u5xx.h" #include "queue.hpp" #include "reg_spi.h" typedef struct { } spi_s; ///< @brief spi instance for driver __UNUSED static inline void rcc_enable_spi(SPI_TypeDef *spi) { if (spi == SPI1) SET_BIT(RCC->APB2ENR, RCC_APB2ENR_SPI1EN); else if (spi == SPI2) SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_SPI2EN); else if (spi == SPI3) SET_BIT(RCC->APB3ENR, RCC_APB3ENR_SPI3EN); } __UNUSED static inline void nvic_enable_spi_irq(SPI_TypeDef *spi) { if (spi == SPI1) NVIC_EnableIRQ(SPI1_IRQn); else if (spi == SPI2) NVIC_EnableIRQ(SPI2_IRQn); else if (spi == SPI3) NVIC_EnableIRQ(SPI3_IRQn); } typedef struct { REG_SPI_MBR master_baud_rate; ///< @brief master baud rate prescaler REG_SPI_CPHA clock_phase; ///< @brief clock phase REG_SPI_CPOL clock_polarity; ///< @brief clock polarity REG_SPI_FIRST_BIT first_bit; ///< @brief first bit select REG_SPI_SS_MANAGEMENT slave_man; ///< @brief slave select management REG_SPI_MASTER mode; ///< @brief spi mode REG_SPI_SSI_STATE slave_select_pin; ///< @brief slave select pin ll_state_e af_control; ///< @brief alternate function control /// @brief alternate function control } spi_init_options_s; ///< @brief spi options for initialization of spi // //const spi_init_options_s spi_default_option = { // .master_baud_rate = SPI_MBR_DIV256, // .clock_phase = SPI_CPHA_FIRST, // .clock_polarity = SPI_CPOL_LOW, // .first_bit = SPI_FIRST_BIT_MSB, // .slave_man = SPI_SS_MANAGER_SOFTWARE, // .slave_select_pin = SPI_SSI_HIGH, // .mode = SPI_MASTER, // .af_control = LL_ENABLE, //}; extern const spi_init_options_s spi_default_option; // the default spi options for initialization extern spi_s *spi1_p; // spi1 instance class Spi { private: SPI_TypeDef *spi; ///< @brief spi instance queue20u8 tx_queue; ///< @brief queue for data to send queue20u8 rx_queue; ///< @brief queue for data to receive public: Spi() = default; void setup() {} /// @brief initialize spi /// @param[in] spi spi to initialize /// @param[in] queue_size size of the tx_queue and rx_queue /// @return status of the operation hal_status_e spi_init(int queue_size, spi_init_options_s options){ // initialize the queue hal_status_e status; // set clock to 100k hz // use hsi16 clock RCC->CCIPR1 |= 2 << RCC_CCIPR1_SPI1SEL_Pos; // 16 Mhz / 160 -> 0.1Mhz = 100kHz options.master_baud_rate = SPI_MBR_DIV256; // clock = 16M/256 < 100Khz // enable clock for spi rcc_enable_spi(spi); nvic_enable_spi_irq(spi); reg_spi_set_af_control(spi, options.af_control); reg_spi_set_slave_select(spi, options.slave_man); reg_spi_set_slave_select_pin(spi, options.slave_select_pin); reg_spi_set_master(spi, options.mode); reg_spi_set_master_baud_rate(spi, options.master_baud_rate); reg_spi_set_data_size(spi, 8); reg_spi_set_clock_phase(spi, options.clock_phase); reg_spi_set_clock_polarity(spi, options.clock_polarity); reg_spi_set_first_bit(spi, options.first_bit); reg_spi_set_peripheral_enable(spi, LL_ENABLE); // todo: get MODF status, if MODF is set, return error return HAL_OK; } /// @brief send data to spi /// @param[in] spi spi to send data /// @param[in] send_ptr pointer to data to send. when this function return, /// the data can be free /// @param[in] size size of data to send /// @return status of the operation hal_status_e spi_send( uint8_t *send_ptr, uint32_t size){ // enable tx and rx intterupt spi->CR1 |= SPI_CR1_CSTART; tx_queue.push_block(send_ptr, size); // spi->spi->CR2 = 1; reg_spi_set_rx_interrupt(spi, LL_ENABLE); reg_spi_set_tx_interrupt(spi, LL_ENABLE); // reg_spi_set_peripheral_enable(spi->spi, LL_ENABLE); // spi->spi->CR1 |= SPI_CR1_CSTART | SPI_CR1_SPE; // return ret; return HAL_OK; } /// @brief read data from spi /// @param[in] spi spi to read data /// @param[out] read_ptr the space to store the data /// @param[in,out] size size of data to read. return the actual size of data. /// @return status of the operation hal_status_e spi_read(uint8_t *read_ptr, uint32_t *size){ return rx_queue.pop_block(read_ptr, *size); } void spi_irq_handler() { uint32_t sr = spi->SR; // handle the error if (sr & SPI_SR_OVR) { // clear the error spi->SR &= ~SPI_SR_OVR; } // handle the rx queue if (sr & SPI_SR_RXP) { if (rx_queue.push(spi->RXDR) != HAL_OK) { // error } } if (sr & SPI_SR_TXP) { uint8_t data; if (tx_queue.pop(&data) == HAL_OK){ *(uint8_t *) &(spi->TXDR) = data; // spi->spi->TXDR = data; } else reg_spi_set_tx_interrupt(spi, LL_DISABLE); } }; }; #endif // STM32U5XX_HAL_SPI_HPP