401 lines
16 KiB
C
Executable File
401 lines
16 KiB
C
Executable File
#include "delay.h"
|
||
#include "global_variable.h"
|
||
#include "stm32u5xx.h"
|
||
|
||
/// chapter 65
|
||
|
||
/////////////////////////// I2C CR1 //////////////////////////////////////////
|
||
|
||
/// @brief set i2c peripheral enable or disable
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[0] (rw) Peripheralenable 0: Peripheral disable 1: Peripheral enable
|
||
/// When PE = 0, the I2C SCL and SDA lines are released.
|
||
/// Internal state machines and status bits are put back to their reset value.
|
||
/// When cleared, PE must be kept low for at least three APB clock cycles.
|
||
static inline void reg_i2c_set_peripheral_enable(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR1, I2C_CR1_PE, state << I2C_CR1_PE_Pos);
|
||
delay_us(3, true); // wait for 3 APB clock cycles
|
||
}
|
||
|
||
/// @brief check if i2c is enabled
|
||
/// @param[in] i2c: i2c instance
|
||
/// @return true if enabled, false if disabled
|
||
/// @note bit[0]
|
||
static bool reg_i2c_is_enabled(I2C_TypeDef *i2c) {
|
||
return READ_BIT(i2c->CR1, I2C_CR1_PE) == I2C_CR1_PE;
|
||
}
|
||
|
||
/// @brief set i2c error interrupt
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[1]
|
||
/// @note A transmit interrupt status (TXIS) is generated when the I2C_TXDR register becomes empty.
|
||
/// An interrupt is generated if the TXIE bit is set in the I2C_CR1 register.
|
||
/// The TXIS bit is cleared when the I2C_TXDR register is written with the next data byte to
|
||
/// be transmitted.
|
||
static inline void reg_i2c_set_tx_interrupt(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR1, I2C_CR1_TXIE, state << I2C_CR1_TXIE_Pos);
|
||
}
|
||
|
||
/// @brief set i2c rx interrupt
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[2]
|
||
/// @todo verify following note
|
||
/// @note A receive interrupt status (RXNE) is generated when the I2C_RXDR register is full.
|
||
static inline void reg_i2c_set_rx_interrupt(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR1, I2C_CR1_RXIE, state << I2C_CR1_RXIE_Pos);
|
||
}
|
||
|
||
/// @brief set i2c address match interrupt (slave mode only)
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[3]
|
||
/// @todo verify following note
|
||
/// @note An address match interrupt status (ADDR) is generated when the address sent by the master
|
||
/// matches the own address of the slave.
|
||
static inline void reg_i2c_set_address_match_interrupt(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR1, I2C_CR1_ADDRIE, state << I2C_CR1_ADDRIE_Pos);
|
||
}
|
||
|
||
/// @brief set i2c nack interrupt
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[4]
|
||
/// @todo verify following note
|
||
/// @note A NACK interrupt status (NACKF) is generated when the master receives a NACK in response
|
||
/// to a transmitted byte.
|
||
static inline void reg_i2c_set_nack_interrupt(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR1, I2C_CR1_NACKIE, state << I2C_CR1_NACKIE_Pos);
|
||
}
|
||
|
||
/// @brief set i2c stop detection interrupt
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[5]
|
||
/// @todo verify following note
|
||
/// @note A stop detection interrupt status (STOPF) is generated when a STOP condition is detected
|
||
/// on the bus.
|
||
static inline void reg_i2c_set_stop_detection_interrupt(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR1, I2C_CR1_STOPIE, state << I2C_CR1_STOPIE_Pos);
|
||
}
|
||
|
||
/// @brief set i2c transfer complete interrupt
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[6]
|
||
/// @todo verify following note
|
||
/// @note A transfer complete interrupt status (TC) is generated when the data byte transfer is
|
||
/// complete.
|
||
static inline void reg_i2c_set_transfer_complete_interrupt(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR1, I2C_CR1_TCIE, state << I2C_CR1_TCIE_Pos);
|
||
}
|
||
|
||
/// @brief set i2c error interrupt
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[7]
|
||
/// @note Any of these errors generate an interrupt:
|
||
/// Arbitration Loss (ARLO)
|
||
/// Bus Error detection (BERR)
|
||
/// Overrun/Underrun (OVR)
|
||
/// Timeout detection (TIMEOUT)
|
||
/// PEC error detection (PECERR)
|
||
/// Alert pin event detection (ALERT)
|
||
static inline void reg_i2c_set_error_interrupt(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR1, I2C_CR1_ERRIE, state << I2C_CR1_ERRIE_Pos);
|
||
}
|
||
|
||
/// @brief set i2c set digital filter
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] filter: filter value
|
||
/// @note bit[11:8] (4 bits)
|
||
/// @note These bits are used to configure the digital noise filter on SDA and SCL input.
|
||
/// The digital filter, filters spikes with a length of up to DNF[3:0] * t_{I2CCLK}
|
||
/// 0000: Digital filter disabled
|
||
/// 0001: Digital filter enabled and filtering capability up to 1 t_{I2CCLK}
|
||
/// @note If the analog filter is also enabled, the digital filter is added to the analog filter.
|
||
/// This filter can only be programmed when the I2C is disabled (PE = 0).
|
||
static inline void reg_i2c_set_digit_filter(I2C_TypeDef *i2c, uint8_t filter) {
|
||
MODIFY_REG(i2c->CR1, I2C_CR1_DNF, filter << I2C_CR1_DNF_Pos);
|
||
}
|
||
|
||
/// @brief set i2c analog filter
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[12]
|
||
/// @note: 0 = analog filter enabled
|
||
/// 1 = analog filter disabled
|
||
/// @note This bit can only be programmed when the I2C is disabled (PE = 0).
|
||
static inline void reg_i2c_set_analog_filter(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR1, I2C_CR1_ANFOFF, (state ^ 1) << I2C_CR1_ANFOFF_Pos);
|
||
}
|
||
|
||
/// @brief set i2c tx dma request enable
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[14]
|
||
static inline void reg_i2c_set_tx_dma_en(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR1, I2C_CR1_TXDMAEN, state << I2C_CR1_TXDMAEN_Pos);
|
||
}
|
||
|
||
/// @brief set i2c rx dma request enable
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[15]
|
||
static inline void reg_i2c_set_rx_dma_en(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR1, I2C_CR1_RXDMAEN, state << I2C_CR1_RXDMAEN_Pos);
|
||
}
|
||
|
||
/// @brief set i2c slave byte control
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[16]
|
||
/// @todo add document for slave byte control (what is it?)
|
||
static inline void reg_i2c_set_slave_byte_control(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR1, I2C_CR1_SBC, state << I2C_CR1_SBC_Pos);
|
||
}
|
||
|
||
/// @brief set i2c clock no stretching
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[17]
|
||
/// @note 0 = Clock stretching enabled
|
||
/// 1 = Clock stretching disabled
|
||
/// @note This bit is used to disable clock stretching in slave mode.
|
||
/// It must be kept cleared in master mode.
|
||
static inline void reg_i2c_set_clock_stretching(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR1, I2C_CR1_NOSTRETCH, (state ^ 1) << I2C_CR1_NOSTRETCH_Pos);
|
||
}
|
||
|
||
/// @brief set wake up from stop mode
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[18]
|
||
/// @note If the wake-up from Stop mode feature is not supported,
|
||
/// this bit is reserved and forced by hardware to ‘0’. Refer to Section 65.3.
|
||
/// @note WUPEN can be set only when DNF = ‘0000’
|
||
static inline void reg_i2c_set_wake_up_from_stop_mode(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR1, I2C_CR1_WUPEN, state << I2C_CR1_WUPEN_Pos);
|
||
}
|
||
|
||
/// @brief set i2c general call
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[19]
|
||
/// @note 0: General call disabled. Address 0b00000000 is NACKed.
|
||
/// @note 1: General call enabled. Address 0b00000000 is ACKed.
|
||
static inline void reg_i2c_set_general_call(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR1, I2C_CR1_GCEN, state << I2C_CR1_GCEN_Pos);
|
||
}
|
||
|
||
/// @todo add document for bit 20 to 31
|
||
|
||
/////////////////////////// I2C CR2 //////////////////////////////////////////
|
||
|
||
/// @brief set i2c slave address
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] address: slave address
|
||
/// @note bit[9:0]
|
||
/// @note In 7-bit addressing mode (ADD10 = 0):
|
||
/// SADD[7:1] must be written with the 7-bit slave address to be sent.
|
||
/// The bits SADD[9], SADD[8] and SADD[0] are don't care.
|
||
/// In 10-bit addressing mode (ADD10 = 1):
|
||
/// SADD[9:0] must be written with the 10-bit slave address to be sent.
|
||
/// @note Changing these bits when the START bit is set is not allowed.
|
||
static inline void reg_i2c_set_slave_address(I2C_TypeDef *i2c, uint16_t address) {
|
||
MODIFY_REG(i2c->CR2, I2C_CR2_SADD, address << I2C_CR2_SADD_Pos);
|
||
}
|
||
|
||
typedef enum {
|
||
LL_I2C_WRITE = 0, ///< write
|
||
LL_I2C_READ = 1, ///< read
|
||
} LL_I2C_RW; /// @brief i2c read or write
|
||
|
||
/// @brief set i2c read or write
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] rw: read or write @see LL_I2C_RW
|
||
/// @note bit[10]
|
||
/// @note changing this bit when the START bit is set is not allowed.
|
||
static inline void reg_i2c_set_rd_wrn(I2C_TypeDef *i2c, LL_I2C_RW rw) {
|
||
MODIFY_REG(i2c->CR2, I2C_CR2_RD_WRN, rw << I2C_CR2_RD_WRN_Pos);
|
||
}
|
||
|
||
typedef enum {
|
||
LL_I2C_7BIT = 0, ///< 7-bit
|
||
LL_I2C_10BIT = 1, ///< 10-bit
|
||
} LL_I2C_ADD10; /// @brief i2c address mode
|
||
|
||
/// @brief set i2c address mode
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] mode: 7-bit or 10-bit
|
||
/// @note bit[11]
|
||
/// @note changing this bit when the START bit is set is not allowed.
|
||
static inline void reg_i2c_set_add10(I2C_TypeDef *i2c, LL_I2C_ADD10 mode) {
|
||
MODIFY_REG(i2c->CR2, I2C_CR2_ADD10, mode << I2C_CR2_ADD10_Pos);
|
||
}
|
||
|
||
/// @todo add document for bit 12
|
||
|
||
/// @brief send i2c start
|
||
/// @param[in] i2c: i2c instance
|
||
/// @note bit[13]
|
||
/// @note This bit is set by software, and cleared by hardware after the Start followed by the
|
||
/// address sequence is sent, by an arbitration loss, by an address matched in slave mode,
|
||
/// by a timeout error detection, or when PE = 0.
|
||
/// 0: No Start generation. 1: Restart/Start generation:
|
||
/// If the I2C is already in master mode with AUTOEND = 0, setting this bit generates a
|
||
/// Repeated start condition when RELOAD = 0, after the end of the NBYTES transfer. Otherwise
|
||
/// setting this bit generates a START condition once the bus is free.
|
||
/// @note Writing ‘0’ to this bit has no effect.
|
||
/// The START bit can be set even if the bus is BUSY or I2C is in slave mode.
|
||
/// This bit has no effect when RELOAD is set.
|
||
static inline void reg_i2c_send_start(I2C_TypeDef *i2c) { SET_BIT(i2c->CR2, I2C_CR2_START); }
|
||
|
||
/// @brief send i2c stop (master mode)
|
||
/// @param[in] i2c: i2c instance
|
||
/// @note bit[14]
|
||
/// @ntoe The bit is set by software, cleared by hardware when a STOP condition is detected, or when
|
||
/// PE = 0.
|
||
/// @note writing ‘0’ to this bit has no effect.
|
||
static inline void reg_i2c_send_stop(I2C_TypeDef *i2c) { SET_BIT(i2c->CR2, I2C_CR2_STOP); }
|
||
|
||
typedef enum {
|
||
LL_I2C_ACK = 0, ///< ACK
|
||
LL_I2C_NACK = 1, ///< NACK
|
||
} LL_I2C_NACK_MODE; /// @brief i2c NACK or ACK
|
||
|
||
/// @brief NACK generation (slave mode)
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] mode: NACK or ACK
|
||
/// @note bit[15]
|
||
/// @note The bit is set by software, cleared by hardware when the NACK is sent, or when a STOP
|
||
/// condition or an Address matched is received, or when PE = 0.
|
||
/// 0: an ACK is sent after current received byte.
|
||
/// 1: a NACK is sent after current received byte.
|
||
/// @note Writing ‘0’ to this bit has no effect.
|
||
/// This bit is used in slave mode only: in master receiver mode, NACK is automatically generated
|
||
/// after last byte preceding STOP or RESTART condition, whatever the NACK bit value. When an
|
||
/// overrun occurs in slave receiver NOSTRETCH mode, a NACK is automatically generated whatever
|
||
/// the NACK bit value. When hardware PEC checking is enabled (PECBYTE = 1), the PEC acknowledge
|
||
/// value does not depend on the NACK value.
|
||
static inline void reg_i2c_set_nack(I2C_TypeDef *i2c, LL_I2C_NACK_MODE mode) {
|
||
MODIFY_REG(i2c->CR2, I2C_CR2_NACK, mode << I2C_CR2_NACK_Pos);
|
||
}
|
||
|
||
/// @brief set i2c number of bytes
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] nbytes: number of bytes
|
||
/// @note bit[23:16]
|
||
/// @warning change nbyte when sending is not allowed (after send start)
|
||
/// @note Changing this bit when the START bit is set is not allowed.
|
||
/// @note The number of bytes to be transmitted/received is programmed there.
|
||
/// This field is don’t care in slave mode with SBC = 0.
|
||
static inline void reg_i2c_set_nbytes(I2C_TypeDef *i2c, uint8_t nbytes) {
|
||
MODIFY_REG(i2c->CR2, I2C_CR2_NBYTES, nbytes << I2C_CR2_NBYTES_Pos);
|
||
}
|
||
|
||
/// @brief nbytes reload mode
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[24]
|
||
/// @todo add document
|
||
static inline void reg_i2c_set_reload(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR2, I2C_CR2_RELOAD, state << I2C_CR2_RELOAD_Pos);
|
||
}
|
||
|
||
/// @brief set i2c autoend
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[25]
|
||
/// @todo add document
|
||
static inline void reg_i2c_set_autoend(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR2, I2C_CR2_AUTOEND, (state ^ 1) << I2C_CR2_AUTOEND_Pos);
|
||
}
|
||
|
||
/// @brief set i2c pec byte
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[26]
|
||
/// @todo add document
|
||
static inline void reg_i2c_set_pec_byte(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->CR2, I2C_CR2_PECBYTE, state << I2C_CR2_PECBYTE_Pos);
|
||
}
|
||
|
||
/////////////////////////// I2C OAR1 //////////////////////////////////////////
|
||
|
||
/// @brief set own address1
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] address: own address
|
||
/// @note bit[9:0]
|
||
static inline void reg_i2c_set_own_address1(I2C_TypeDef *i2c, uint16_t address) {
|
||
MODIFY_REG(i2c->OAR1, I2C_OAR1_OA1, address << I2C_OAR1_OA1_Pos);
|
||
}
|
||
|
||
/// @brief set own address mode
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] mode: 7-bit or 10-bit
|
||
/// @note bit[10]
|
||
static inline void reg_i2c_set_own_address_mode(I2C_TypeDef *i2c, LL_I2C_ADD10 mode) {
|
||
MODIFY_REG(i2c->OAR1, I2C_OAR1_OA1MODE, mode << I2C_OAR1_OA1MODE_Pos);
|
||
}
|
||
|
||
/// @brief set i2c own address enable
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] state: enable or disable
|
||
/// @note bit[15]
|
||
static inline void reg_i2c_set_own_address1_en(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->OAR1, I2C_OAR1_OA1EN, state << I2C_OAR1_OA1EN_Pos);
|
||
}
|
||
|
||
/////////////////////////// I2C OAR2 //////////////////////////////////////////
|
||
|
||
/// @brief set i2c own address2
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] address: own address
|
||
/// @note bit[9:0]
|
||
static inline void reg_i2c_set_own_address2(I2C_TypeDef *i2c, uint16_t address) {
|
||
MODIFY_REG(i2c->OAR2, I2C_OAR2_OA2, address << I2C_OAR2_OA2_Pos);
|
||
}
|
||
|
||
/// @brief set i2c own address2 mode
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] mode: 7-bit or 10-bit
|
||
/// @note bit[10]
|
||
static inline void reg_i2c_set_own_address2_mode(I2C_TypeDef *i2c, LL_I2C_ADD10 mode) {
|
||
MODIFY_REG(i2c->OAR2, I2C_OAR2_OA2, mode << I2C_OAR2_OA2_Pos);
|
||
}
|
||
|
||
/// @brief set i2c own address2 enable
|
||
/// @param[in] i2c: i2c instance
|
||
/// @param[in] address: own address
|
||
/// @note bit[15]
|
||
static inline void reg_i2c_set_own_address2_en(I2C_TypeDef *i2c, ll_state_e state) {
|
||
MODIFY_REG(i2c->OAR2, I2C_OAR2_OA2EN, state << I2C_OAR2_OA2EN_Pos);
|
||
}
|
||
|
||
/////////////////////////// I2C TIMINGR ///////////////////////////////////////////
|
||
/// todo: update timming set up using understandable names
|
||
static inline void reg_i2c_set_timing(I2C_TypeDef *i2c, uint32_t timing) {
|
||
WRITE_REG(i2c->TIMINGR, timing);
|
||
}
|
||
|
||
/////////////////////////// I2C TIMEOUTR //////////////////////////////////////////
|
||
|
||
/////////////////////////// I2C ISR ///////////////////////////////////////////////
|
||
|
||
/////////////////////////// I2C ICR ///////////////////////////////////////////////
|
||
|
||
/////////////////////////// I2C RXDR //////////////////////////////////////////////
|
||
static inline uint8_t reg_i2c_read_data(I2C_TypeDef *i2c) {
|
||
return READ_REG(i2c->RXDR);
|
||
}
|
||
|
||
/////////////////////////// I2C TXDR //////////////////////////////////////////////
|
||
static inline void reg_i2c_write_data(I2C_TypeDef *i2c, uint8_t data) {
|
||
WRITE_REG(i2c->TXDR, data);
|
||
}
|
||
|
||
/////////////////////////// I2C AUTOCR ////////////////////////////////////////////
|