255 lines
9.3 KiB
C
Executable File
255 lines
9.3 KiB
C
Executable File
/**
|
|
* @addtogroup stm32u5xx_ll_driver
|
|
* @{
|
|
* @addtogroup stm32u5xx_ll_spi
|
|
* @{
|
|
*/
|
|
|
|
/// @file ll_spi.h
|
|
/// @breif spi driver
|
|
/// @version 0.1
|
|
/// @author Guangzong Chen <chen-gz@outlook.com>
|
|
/// @date 2023-03-14
|
|
/// @copyright Copyright (c) 2022 zongpitt All Rights Reserved.
|
|
|
|
#ifndef REG_SPI_H
|
|
#define REG_SPI_H
|
|
|
|
#include "global_variable.h"
|
|
#include "stm32u575xx.h"
|
|
#include <stm32u5xx.h>
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////SPI CR1 register//////////////////////////////////
|
|
|
|
/// @brief set spi peripheral enable
|
|
/// @param[in] spi: spi instance
|
|
/// @param[in] state: enable or disable
|
|
/// @note bit 0
|
|
static inline void reg_spi_set_peripheral_enable(SPI_TypeDef *spi, ll_state_e state) {
|
|
MODIFY_REG(spi->CR1, SPI_CR1_SPE, state << SPI_CR1_SPE_Pos);
|
|
}
|
|
|
|
|
|
typedef enum {
|
|
SPI_SSI_LOW = 0, ///< @brief spi slave select pin is low
|
|
SPI_SSI_HIGH = 1, ///< @brief spi slave select pin is high
|
|
} REG_SPI_SSI_STATE; ///< @brief spi slave select pin state
|
|
|
|
/// @brief spi set slave select pin
|
|
/// @param[in] spi: spi instance
|
|
/// @param[in] state: slave select pin state
|
|
/// @note bit 12
|
|
/// @note This bit has an effect only when the SSM bit is set. The value of this bit is forced onto the peripheral SS
|
|
/// input internally and the I/O value of the SS pin is ignored.
|
|
static inline void reg_spi_set_slave_select_pin(SPI_TypeDef *spi, REG_SPI_SSI_STATE state) {
|
|
MODIFY_REG(spi->CR1, SPI_CR1_SSI, state << SPI_CR1_SSI_Pos);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////SPI CR2 register//////////////////////////////////
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////SPI CFG1 register////////////////////////////////
|
|
|
|
/// @brief spi master clock divider
|
|
typedef enum {
|
|
SPI_MBR_DIV2 = 0, ///< @brief spi master clock/2
|
|
SPI_MBR_DIV4 = 1, ///< @brief spi master clock/4
|
|
SPI_MBR_DIV8 = 2, ///< @brief spi master clock/8
|
|
SPI_MBR_DIV16 = 3, ///< @brief spi master clock/16
|
|
SPI_MBR_DIV32 = 4, ///< @brief spi master clock/32
|
|
SPI_MBR_DIV64 = 5, ///< @brief spi master clock/64
|
|
SPI_MBR_DIV128 = 6, ///< @brief spi master clock/128
|
|
SPI_MBR_DIV256 = 7, ///< @brief spi master clock/256
|
|
} REG_SPI_MBR;
|
|
|
|
/// @brief spi set master baud rate prescaler
|
|
/// @param[in] spi: spi instance
|
|
/// @param[in] mbr: spi master baud rate prescalar
|
|
static inline void reg_spi_set_master_baud_rate(SPI_TypeDef *spi, REG_SPI_MBR mbr) {
|
|
MODIFY_REG(spi->CFG1, SPI_CFG1_MBR, mbr << SPI_CFG1_MBR_Pos);
|
|
}
|
|
|
|
/// @brief spi set data size
|
|
/// @param[in] spi: spi instance
|
|
/// @param[in] size: spi data size (3-16)
|
|
static inline void reg_spi_set_data_size(SPI_TypeDef *spi, uint8_t size) {
|
|
MODIFY_REG(spi->CFG1, SPI_CFG1_DSIZE, (size - 1) << SPI_CFG1_DSIZE_Pos);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////SPI CFG2 register////////////////////////////////
|
|
|
|
typedef enum {
|
|
SPI_SLAVE = 0, ///< @brief spi slave
|
|
SPI_MASTER = 1, ///< @brief spi master
|
|
} REG_SPI_MASTER;
|
|
|
|
/// @brief spi set master
|
|
/// @param[in] spi: spi instance
|
|
/// @param[in] state: spi master or slave.
|
|
static inline void reg_spi_set_master(SPI_TypeDef *spi, REG_SPI_MASTER state) {
|
|
// todo: I don't know why it need set twice. Then the register will be set correctly.
|
|
MODIFY_REG(spi->CFG2, SPI_CFG2_MASTER, state << SPI_CFG2_MASTER_Pos);
|
|
MODIFY_REG(spi->CFG2, SPI_CFG2_MASTER, state << SPI_CFG2_MASTER_Pos);
|
|
}
|
|
|
|
typedef enum {
|
|
SPI_CPOL_LOW = 0, ///< @brief spi clock idle state is low
|
|
SPI_CPOL_HIGH = 1, ///< @brief spi clock idle state is high
|
|
} REG_SPI_CPOL;
|
|
|
|
/// @brief spi set clock polarity
|
|
/// @param[in] spi: spi instance
|
|
/// @param[in] polarity: spi clock idle state (low or high)
|
|
static inline void reg_spi_set_clock_polarity(SPI_TypeDef *spi, REG_SPI_CPOL polarity) {
|
|
MODIFY_REG(spi->CFG2, SPI_CFG2_CPOL, polarity << SPI_CFG2_CPOL_Pos);
|
|
}
|
|
|
|
typedef enum {
|
|
SPI_CPHA_FIRST = 0, ///< @brief spi clock phase is first edge
|
|
SPI_CPHA_SECOND = 1, ///< @brief spi clock phase is second edge
|
|
} REG_SPI_CPHA;
|
|
|
|
/// @brief spi set clock phase
|
|
/// @param[in] spi: spi instance
|
|
/// @param[in] phase: spi clock phase (first or second edge)
|
|
static inline void reg_spi_set_clock_phase(SPI_TypeDef *spi, REG_SPI_CPHA phase) {
|
|
MODIFY_REG(spi->CFG2, SPI_CFG2_CPHA, phase << SPI_CFG2_CPHA_Pos);
|
|
}
|
|
|
|
typedef enum {
|
|
SPI_FIRST_BIT_MSB = 0, ///< @brief spi first bit is MSB
|
|
SPI_FIRST_BIT_LSB = 1, ///< @brief spi first bit is LSB
|
|
} REG_SPI_FIRST_BIT;
|
|
|
|
/// @brief spi set first bit
|
|
static inline void reg_spi_set_first_bit(SPI_TypeDef *spi, REG_SPI_FIRST_BIT first_bit) {
|
|
MODIFY_REG(spi->CFG2, SPI_CFG2_LSBFRST, first_bit << SPI_CFG2_LSBFRST_Pos);
|
|
}
|
|
|
|
|
|
/// @brief spi slave select pin management
|
|
typedef enum {
|
|
SPI_SS_MANAGER_SOFTWARE = 1, ///< @brief software slave select management
|
|
SPI_SS_MANAGER_HARDWARE = 0, ///< @brief hardware slave select management
|
|
} REG_SPI_SS_MANAGEMENT;
|
|
|
|
/// @brief spi set slave select
|
|
/// @see doc/rm0456 68.4.7 Slave select(SS) pin management. Page 2898
|
|
static inline void reg_spi_set_slave_select(SPI_TypeDef *spi, REG_SPI_SS_MANAGEMENT ssm) {
|
|
MODIFY_REG(spi->CFG2, SPI_CFG2_SSM, ssm << SPI_CFG2_SSM_Pos);
|
|
}
|
|
|
|
/// @brief alternate function GPIO contorol
|
|
/// @param[in] spi: spi instance
|
|
/// @param[in] state: enable or disable
|
|
/// @note bit 31
|
|
/// @note This bit taken into account when SPE=0 only (SPI disabled).
|
|
/// 0: The peripheral takes no control of GPIOs while it is disabled
|
|
/// 1: The peripheral keeps always control of all associated GPIOs
|
|
/// When SPI must be disabled temporary for a specific configuration reason
|
|
/// (for example CRC reset, CPHA or HDDIR change) setting this bit prevents any glitches on the associated
|
|
/// outputs configured at alternate function mode by keeping them forced at state corresponding the current SPI configuration
|
|
static inline void reg_spi_set_af_control(SPI_TypeDef *spi, ll_state_e state) {
|
|
MODIFY_REG(spi->CFG2, SPI_CFG2_AFCNTR, state << SPI_CFG2_AFCNTR_Pos);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////SPI IER register/////////////////////////////////
|
|
|
|
/// @brief set spi receive interrupt
|
|
/// @param[in] spi: spi instance
|
|
/// @param[in] state: enable or disable
|
|
/// @note bit 0: RXPIE: Rx buffer not empty interrupt enable
|
|
/// @note Interrupt Event: RxFIFO not empty
|
|
static inline void reg_spi_set_rx_interrupt(SPI_TypeDef *spi, ll_state_e state) {
|
|
MODIFY_REG(spi->IER, SPI_IER_RXPIE, state << SPI_IER_RXPIE_Pos);
|
|
}
|
|
|
|
/// @brief set spi transmit interrupt
|
|
/// @param[in] spi: spi instance
|
|
/// @param[in] state: enable or disable
|
|
/// @note bit 1: TXPIE: Tx buffer empty interrupt enable
|
|
/// @note Interrupt Event: TxFIFO ready to be loaded (space available for one data packet - FIFO threshold)
|
|
static inline void reg_spi_set_tx_interrupt(SPI_TypeDef *spi, ll_state_e state) {
|
|
MODIFY_REG(spi->IER, SPI_IER_TXPIE, state << SPI_IER_TXPIE_Pos);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////SPI SR register//////////////////////////////////
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////SPI IFCR register////////////////////////////////
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////SPI AUTOCR register//////////////////////////////
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////SPI TXDR register////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////SPI RXDR register////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////SPI CRCPOLY register/////////////////////////////
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////SPI TXCRC register///////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////SPI RXCRC register///////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////SPI UDRDR register///////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// @brief spi clock mode
|
|
typedef enum {
|
|
SPI_CLOCK_MODE_0 = 0, ///< @brief spi clock idle state is low and clock phase is first edge
|
|
SPI_CLOCK_MODE_1 = 1, ///< @brief spi clock idle state is low and clock
|
|
///< phase is second edge
|
|
SPI_CLOCK_MODE_2 = 2, ///< @brief spi clock idle state is high and clock
|
|
///< phase is first edge
|
|
SPI_CLOCK_MODE_3 = 3, ///< @brief spi clock idle state is high and clock
|
|
///< phase is second edge
|
|
} REG_SPI_CLOCK_MODE;
|
|
|
|
/// @brief spi set mode
|
|
/// @param[in] spi: spi instance
|
|
/// @param[in] mode: spi mode (0, 1, 2, 3)
|
|
/// @return void
|
|
static inline void reg_spi_set_clock_mode(SPI_TypeDef *spi, REG_SPI_CLOCK_MODE mode) {
|
|
reg_spi_set_clock_polarity(spi, static_cast<REG_SPI_CPOL>(mode & 0x1));
|
|
reg_spi_set_clock_phase(spi, static_cast<REG_SPI_CPHA>((mode >> 1) & 0x1));
|
|
}
|
|
|
|
|
|
#endif
|
|
/**
|
|
* @}
|
|
* @}
|
|
*/ |