155 lines
5.3 KiB
C++
Executable File
155 lines
5.3 KiB
C++
Executable File
#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
|