Browse Source

Modify I2C routines.

Vladimir N. Shilov 2 years ago
parent
commit
9b1383efd1
3 changed files with 101 additions and 69 deletions
  1. 0 1
      inc/i2c.h
  2. 1 9
      src/board.c
  3. 100 59
      src/i2c.c

+ 0 - 1
inc/i2c.h

@@ -15,7 +15,6 @@ typedef enum t_i2c_status {
   I2C_Ret_Err
 } i2c_status_t;
 
-/* Exported variabless */
 /* Exported function prototypes */
 i2c_status_t user_i2c_read(uint8_t id, uint8_t reg_addr, uint8_t *data, uint16_t len);
 i2c_status_t user_i2c_write(uint8_t id, uint8_t reg_addr, uint8_t *data, uint16_t len);

+ 1 - 9
src/board.c

@@ -150,19 +150,11 @@ void GPIO_SPI_HW(void) {
   */
 static void I2C1_Init(void)
 {
-  /* I2C1 DMA Ch2 for I2C1_TX Init */
-  // DMA_CCR_CIRC
-  DMA1_Channel2->CCR = (DMA_CCR_DIR | DMA_CCR_PL_0 | DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_TEIE);
-
-  /* I2C1 interrupt Init */
-  NVIC_SetPriority(I2C1_IRQn, 0);
-  NVIC_EnableIRQ(I2C1_IRQn);
-
   /* By default, I2C clocked from HSI, for SysClk use this: */
   //RCC->CFGR3 |= RCC_CFGR3_I2C1SW;
 
   /** I2C Initialization: I2C_Fast */
-  I2C1->CR1 = (I2C_CR1_TXDMAEN); //  | I2C_CR1_RXIE | I2C_CR1_ERRIE
+  I2C1->CR1 = 0x0;
   I2C1->TIMINGR = 0x0010020A; //0x00701850; // 400kHz / 8MHz / 100/100 ns
   I2C1->CR2 = I2C_CR2_AUTOEND;
   I2C1->CR1 |= I2C_CR1_PE;

+ 100 - 59
src/i2c.c

@@ -15,13 +15,32 @@
 static i2c_status_t st_Read = I2C_Ret_OK;
 
 /* Private function prototypes */
-i2c_status_t i2c_check_err(void);
+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
  */
-i2c_status_t i2c_check_err(void) {
+static i2c_status_t i2c_check_err(void) {
   i2c_status_t r = I2C_Ret_OK;
 
   if ((I2C1->ISR & I2C_ISR_NACKF) != 0) {
@@ -49,7 +68,7 @@ i2c_status_t i2c_check_err(void) {
  * @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, const uint16_t len) {
+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(); };
 
@@ -61,16 +80,11 @@ i2c_status_t user_i2c_read(const uint8_t id, const uint8_t reg_addr, uint8_t *da
 
   /* 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);
-  /* gen START */
-  I2C1->CR2 |= I2C_CR2_START;
+  I2C1->CR2 |= (id | (1 << I2C_CR2_NBYTES_Pos));
+  i2c_start();
 
   /* wait for byte request or any error */
-  //ENABLE_TIM;
   while ((I2C1->ISR & (I2C_ISR_TIMEOUT | I2C_ISR_ARLO | I2C_ISR_BERR | I2C_ISR_NACKF | I2C_ISR_TXE)) == 0) {
-    //if (TIM_CNT == 0) {
-    //  return I2C_Ret_Tout;
-    //}
     __NOP();
   }
 
@@ -79,10 +93,9 @@ i2c_status_t user_i2c_read(const uint8_t id, const uint8_t reg_addr, uint8_t *da
     I2C1->TXDR = reg_addr;
   } else {
     st_Read = i2c_check_err();
-    if (st_Read != I2C_Ret_OK) {
-      Flag.I2C_TX_Err = 1;
-      return st_Read;
-    }
+    Flag.I2C_TX_Err = 1;
+    Flag.I2C_RX_End = 1;
+    return st_Read;
   }
 
   /* wait for i2c or any error */
@@ -90,37 +103,32 @@ i2c_status_t user_i2c_read(const uint8_t id, const uint8_t reg_addr, uint8_t *da
   st_Read = i2c_check_err();
   if (st_Read != I2C_Ret_OK) {
     Flag.I2C_TX_Err = 1;
+    Flag.I2C_RX_End = 1;
     return st_Read;
   }
 
-  int cnt = 0;
-  // Read data while no TC flag set.
-  // Если взлетит NACK-флаг, приём прекращаем.
-  //ENABLE_TIM;
-  while ((((I2C1->ISR & I2C_ISR_TC)==0) && ((I2C1->ISR & I2C_ISR_NACKF)==0)) && (I2C1->ISR & I2C_ISR_BUSY)) {
+  /* 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 ++;
-      cnt ++;
-      if (cnt > len) {
-        st_Read = I2C_Ret_Err;
-        break;
-      }
+      len --;
+    } else {
+      st_Read = i2c_check_err();
+      Flag.I2C_RX_Err = 1;
+      Flag.I2C_RX_End = 1;
+      return st_Read;
     }
-    //if (TIM_CNT == 0) {
-    //  st_Read = I2C_Ret_Tout;
-    //  break;
-    //}
   }
 
-  /* wait for receiving data */
-  //while ((Flag.I2C_RX_End == 0) && (Flag.I2C_RX_Err == 0)) { __NOP(); };
-
-  /* Set STOP */
-  //I2C1->CR2 |= I2C_CR2_STOP;
-  /* Clear flags */
-  //I2C1->ICR = (I2C_ICR_STOPCF | I2C_ICR_NACKCF | I2C_ICR_ARLOCF | I2C_ICR_BERRCF);
-
+  Flag.I2C_RX_End = 1;
   return st_Read;
 }
 
@@ -136,19 +144,11 @@ i2c_status_t user_i2c_write(const uint8_t id, const uint8_t reg_addr, uint8_t *d
   Flag.I2C_TX_End = 0;
   Flag.I2C_TX_Err = 0;
 
-  DMA1_Channel2->CMAR = (uint32_t)data;
-  DMA1_Channel2->CPAR = (uint32_t)&(I2C1->TXDR);
-  DMA1_Channel2->CNDTR = len;
-
-  I2C1->CR2 &= ~( I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN);
-  I2C1->CR2 |= ( id | (len + 1) << I2C_CR2_NBYTES_Pos );
-  I2C1->CR2 |= ( I2C_CR2_START );
+  I2C1->CR2 &= ~(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN);
+  I2C1->CR2 |= (id | ((len + 1) << I2C_CR2_NBYTES_Pos ));
+  i2c_start();
 
-  //ENABLE_TIM;
   while ((I2C1->ISR & (I2C_ISR_ARLO | I2C_ISR_BERR | I2C_ISR_NACKF | I2C_ISR_TXE)) == 0) {
-    //if (TIM_CNT == 0) {
-    //  return I2C_Ret_Tout;
-    //}
     __NOP();
   }
 
@@ -156,28 +156,69 @@ i2c_status_t user_i2c_write(const uint8_t id, const uint8_t reg_addr, uint8_t *d
     I2C1->TXDR = reg_addr;
   } else {
     r = i2c_check_err();
-    if (r != I2C_Ret_OK) {
-      Flag.I2C_TX_Err = 1;
-      return r;
-    }
+    Flag.I2C_TX_Err = 1;
+    Flag.I2C_TX_End = 1;
+    return r;
   }
 
   while (len) {
-    while ((I2C1->ISR & (I2C_ISR_TC | I2C_ISR_BUSY | I2C_ISR_NACKF | I2C_ISR_TXE)) == 0) { __NOP(); }
-    if (I2C1->ISR & I2C_ISR_TXE) {
+  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();
-      if (r != I2C_Ret_OK) {
-        Flag.I2C_TX_Err = 1;
-        return r;
-      }
+      Flag.I2C_TX_Err = 1;
+      Flag.I2C_TX_End = 1;
+      return r;
     }
   }
-//  DMA1_Channel2->CCR |= DMA_CCR_EN;
-//  I2C1->CR1 |= I2C_CR1_TXDMAEN;
 
+  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;
+}