123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- /**
- ******************************************************************************
- * @file : i2c.c
- * @brief : I2C base functions
- ******************************************************************************
- */
- #include "main.h"
- /* Private macros */
- #define ENABLE_TIM TIM17->CNT=1; TIM17->CR1 |= TIM_CR1_CEN
- #define TIM_CNT TIM17->CNT
- /* Private variables */
- static i2c_status_t st_Read = I2C_Ret_OK;
- /* Private function prototypes */
- static i2c_status_t i2c_check_err(void);
- static inline void i2c_start(void) {
- // Send 'Start' condition, and wait for acknowledge.
- I2C1->CR2 |= (I2C_CR2_START);
- while ((I2C1->CR2 & I2C_CR2_START)) {}
- }
- static inline void i2c_stop(void) {
- // Send 'Stop' condition, and wait for acknowledge.
- I2C1->CR2 |= (I2C_CR2_STOP);
- while ((I2C1->CR2 & I2C_CR2_STOP)) {}
- // Reset the ICR ('Interrupt Clear Register') event flag.
- I2C1->ICR |= (I2C_ICR_STOPCF);
- while ((I2C1->ICR & I2C_ICR_STOPCF)) {}
- }
- static void i2c_write_byte(uint8_t dat);
- static uint8_t i2c_read_byte(void);
- static uint8_t i2c_read_register(uint8_t reg_addr);
- /**
- * @brief Check I2C bus for errors.
- * @retval I2C return code
- */
- static i2c_status_t i2c_check_err(void) {
- i2c_status_t r = I2C_Ret_OK;
- if ((I2C1->ISR & I2C_ISR_NACKF) != 0) {
- /* device not present */
- r = I2C_Ret_NACK;
- } else if ((I2C1->ISR & I2C_ISR_TIMEOUT) != 0) {
- /* timeout error */
- r = I2C_Ret_Tout;
- } else if ((I2C1->ISR & (I2C_ISR_ARLO | I2C_ISR_BERR)) != 0) {
- /* other error */
- r = I2C_Ret_Err;
- }
- if (r != I2C_Ret_OK) {
- /* restart I2C and clear flags */
- I2C1->CR1 &= ~I2C_CR1_PE;
- while ((I2C1->CR1 & I2C_CR1_PE) != 0);
- I2C1->CR1 |= I2C_CR1_PE;
- }
- return r;
- }
- /**
- * @brief Read len bytes from I2C bus to data by reg_addr.
- * @retval I2C return code
- */
- i2c_status_t user_i2c_read(const uint8_t id, const uint8_t reg_addr, uint8_t *data, uint16_t len) {
- /* wait for i2c */
- while ( I2C1->ISR & I2C_ISR_BUSY ) { __NOP(); };
- st_Read = I2C_Ret_OK;
- Flag.I2C_RX_End = 0;
- Flag.I2C_RX_Err = 0;
- Flag.I2C_TX_Err = 0;
- /* prepare i2c for sending reg addr */
- I2C1->CR2 &= ~(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN);
- I2C1->CR2 |= (id | (1 << I2C_CR2_NBYTES_Pos));
- i2c_start();
- /* wait for byte request or any error */
- while ((I2C1->ISR & (I2C_ISR_TIMEOUT | I2C_ISR_ARLO | I2C_ISR_BERR | I2C_ISR_NACKF | I2C_ISR_TXE)) == 0) {
- __NOP();
- }
- if ((I2C1->ISR & I2C_ISR_TXE) != 0) {
- /* device ok, send reg addr */
- I2C1->TXDR = reg_addr;
- } else {
- st_Read = i2c_check_err();
- Flag.I2C_TX_Err = 1;
- Flag.I2C_RX_End = 1;
- return st_Read;
- }
- /* wait for i2c or any error */
- while (((I2C1->ISR & I2C_ISR_BUSY) != 0) && ((I2C1->ISR & (I2C_ISR_ARLO | I2C_ISR_BERR | I2C_ISR_NACKF)) == 0)) { __NOP(); };
- st_Read = i2c_check_err();
- if (st_Read != I2C_Ret_OK) {
- Flag.I2C_TX_Err = 1;
- Flag.I2C_RX_End = 1;
- return st_Read;
- }
- /* prepare i2c for receiving data */
- I2C1->CR2 &= ~(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN);
- I2C1->CR2 |= (id | (len << I2C_CR2_NBYTES_Pos) | I2C_CR2_RD_WRN);
- /* launch receiving */
- i2c_start();
- /* receiving data */
- while (len) {
- while ((I2C1->ISR & (I2C_ISR_NACKF | I2C_ISR_RXNE))==0) { __NOP(); }
- if (I2C1->ISR & I2C_ISR_RXNE) { // Reading data
- *data = I2C1->RXDR;
- data ++;
- len --;
- } else {
- st_Read = i2c_check_err();
- Flag.I2C_RX_Err = 1;
- Flag.I2C_RX_End = 1;
- return st_Read;
- }
- }
- Flag.I2C_RX_End = 1;
- return st_Read;
- }
- /**
- * @brief Write len bytes to I2C bus from data by reg_addr.
- * @retval I2C return code
- */
- i2c_status_t user_i2c_write(const uint8_t id, const uint8_t reg_addr, uint8_t *data, uint16_t len) {
- i2c_status_t r = I2C_Ret_OK;
- while ( I2C1->ISR & I2C_ISR_BUSY );
- Flag.I2C_TX_End = 0;
- Flag.I2C_TX_Err = 0;
- I2C1->CR2 &= ~(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN);
- I2C1->CR2 |= (id | ((len + 1) << I2C_CR2_NBYTES_Pos ));
- i2c_start();
- while ((I2C1->ISR & (I2C_ISR_ARLO | I2C_ISR_BERR | I2C_ISR_NACKF | I2C_ISR_TXE)) == 0) {
- __NOP();
- }
- if ((I2C1->ISR & I2C_ISR_TXE) != 0) {
- I2C1->TXDR = reg_addr;
- } else {
- r = i2c_check_err();
- Flag.I2C_TX_Err = 1;
- Flag.I2C_TX_End = 1;
- return r;
- }
- while (len) {
- while ((I2C1->ISR & (I2C_ISR_NACKF | I2C_ISR_TXE)) == 0) { __NOP(); }
- if ((I2C1->ISR & I2C_ISR_TXE) != 0) {
- I2C1->TXDR = *data;
- data ++;
- len --;
- } else {
- r = i2c_check_err();
- Flag.I2C_TX_Err = 1;
- Flag.I2C_TX_End = 1;
- return r;
- }
- }
- Flag.I2C_TX_End = 1;
- return r;
- }
- static void i2c_write_byte(uint8_t dat) {
- I2C1->TXDR = (I2C1->TXDR & 0xFFFFFF00) | dat;
- // Wait for one of these ISR bits:
- // 'TXIS' ("ready for next byte")
- // 'TC' ("transfer complete")
- while (!(I2C1->ISR & (I2C_ISR_TXIS | I2C_ISR_TC))) {}
- // (Also of interest: 'TXE' ("TXDR register is empty") and
- // 'TCR' ("transfer complete, and 'RELOAD' is set."))
- }
- static uint8_t i2c_read_byte(void) {
- // Wait for a byte of data to be available, then read it.
- while (!(I2C1->ISR & I2C_ISR_RXNE)) {}
- return (I2C1->RXDR & 0xFF);
- }
- static uint8_t i2c_read_register(uint8_t reg_addr) {
- // Set '1 byte to send.'
- I2C1->CR2 &= ~(I2C_CR2_NBYTES);
- I2C1->CR2 |= (0x01 << I2C_CR2_NBYTES_Pos);
- // Start the I2C write transmission.
- i2c_start();
- // Send the register address.
- i2c_write_byte(reg_addr);
- // Stop the I2C write transmission.
- i2c_stop();
- // Set '1 byte to receive.'
- I2C1->CR2 &= ~(I2C_CR2_NBYTES);
- I2C1->CR2 |= (0x01 << I2C_CR2_NBYTES_Pos);
- // Set 'read' I2C direction.
- I2C1->CR2 |= (I2C_CR2_RD_WRN);
- // Start the I2C read transmission.
- i2c_start();
- // Read the transmitted data.
- uint8_t read_result = i2c_read_byte();
- // Stop the I2C read transmission.
- i2c_stop();
- // Set 'write' I2C direction again.
- I2C1->CR2 &= ~(I2C_CR2_RD_WRN);
- // Return the read value.
- return read_result;
- }
|