#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 ////////////////////////////////////////////