Explorar el Código

Try to fix I2C driver.

Vladimir N. Shilov hace 1 año
padre
commit
939dbe3e23
Se han modificado 2 ficheros con 134 adiciones y 51 borrados
  1. 131 48
      lib/i2c.c
  2. 3 3
      lib/i2c.h

+ 131 - 48
lib/i2c.c

@@ -15,7 +15,7 @@ extern __IO uint8_t I2C_timeout;
 #define wait_event(event, timeout) I2C_timeout = timeout;\
                                    while(event && I2C_timeout);\
                                    if(!I2C_timeout) return I2C_TIMEOUT;
-
+#define set_I2C_timeout_ms(time)  I2C_timeout = time
 
 /**
  * @brief Инициализация I2C интерфейса
@@ -34,8 +34,12 @@ void i2c_master_init(void) {
   //Отключаем I2C
   I2C->CR1 &= (uint8_t)(~I2C_CR1_PE);
 
-  //Выбираем стандартный режим
+  //Выбираем режим
+#ifdef I2C_FAST
+  I2C->CCRH = I2C_CCRH_FS; // | I2C_CCRH_DUTY;
+#else
   I2C->CCRH = 0;
+#endif
 
   //CCR = Fmaster/2*Fiic = 16MHz/2*100kHz = 80
   ccr = (uint16_t)(F_MASTER_HZ / (2 * F_I2C_HZ));
@@ -45,7 +49,7 @@ void i2c_master_init(void) {
   //= InputClockFrequencyMHz+1
   I2C->TRISER = (uint8_t)(F_MASTER_MHZ + 1);
   I2C->CCRL = (uint8_t)ccr;
-  I2C->CCRH = (uint8_t)((uint8_t)(ccr >> 8) & I2C_CCRH_CCR);
+  I2C->CCRH |= (uint8_t)((uint8_t)(ccr >> 8) & I2C_CCRH_CCR);
 
   //Включаем I2C
   I2C->CR1 |= I2C_CR1_PE;
@@ -55,40 +59,43 @@ void i2c_master_init(void) {
 }
 
 /**
- * @brief Запись регистра slave-устройства
+ * @brief Send data to slave device.
  */
-t_i2c_status i2c_wr_reg(const uint8_t address, const uint8_t data) {
+t_i2c_status i2c_wr_data(const uint8_t address, const uint8_t num_bytes_to_wr, uint8_t * data) {
+  uint8_t adr = address << 1;
+  uint8_t length = num_bytes_to_wr;
 
   //Ждем освобождения шины I2C
   wait_event((I2C->SR3 & I2C_SR3_BUSY), 10);
-
+    
   //Генерация СТАРТ-посылки
   I2C->CR2 |= I2C_CR2_START;
   //Ждем установки бита SB
   wait_event(!(I2C->SR1 & I2C_SR1_SB), 1);
-
-
+  
   //Записываем в регистр данных адрес ведомого устройства
-  I2C->DR = address & 0xFE;
+  I2C->DR = adr;
   //Ждем подтверждения передачи адреса
   wait_event(!(I2C->SR1 & I2C_SR1_ADDR), 1);
   //Очистка бита ADDR чтением регистра SR3
   I2C->SR3;
-
-
-  //Ждем освобождения регистра данных
-  wait_event(!(I2C->SR1 & I2C_SR1_TXE), 1);
-  //Отправляем адрес регистра
-  I2C->DR = data;
-
+  
+  //Отправка данных
+  while (length--) {
+    //Ждем освобождения регистра данных
+    wait_event(!(I2C->SR1 & I2C_SR1_TXE), 1);
+    //Отправляем адрес регистра
+    I2C->DR = *data++;
+  }
+  
   //Ловим момент, когда DR освободился и данные попали в сдвиговый регистр
   wait_event(!((I2C->SR1 & I2C_SR1_TXE) && (I2C->SR1 & I2C_SR1_BTF)), 1);
-
+  
   //Посылаем СТОП-посылку
   I2C->CR2 |= I2C_CR2_STOP;
   //Ждем выполнения условия СТОП
   wait_event((I2C->CR2 & I2C_CR2_STOP), 1);
-
+  
   return I2C_SUCCESS;
 }
 
@@ -96,47 +103,123 @@ t_i2c_status i2c_wr_reg(const uint8_t address, const uint8_t data) {
  * @brief Чтение регистра slave-устройства
  * @note Start -> Slave Addr -> Reg. addr -> Restart -> Slave Addr <- data ... -> Stop
  */
-t_i2c_status i2c_rd_reg(const uint8_t address, uint8_t * data) {
+t_i2c_status i2c_rd_data(const uint8_t address, const uint8_t num_bytes_to_rd, uint8_t * data) {
+  uint8_t addr = (address << 1) | 1;
+  uint8_t length = num_bytes_to_rd;
 
   //Ждем освобождения шины I2C
   wait_event((I2C->SR3 & I2C_SR3_BUSY), 10);
-
+    
   //Разрешаем подтверждение в конце посылки
   I2C->CR2 |= I2C_CR2_ACK;
-
+  
   //Генерация СТАРТ-посылки
   I2C->CR2 |= I2C_CR2_START;
   //Ждем установки бита SB
   wait_event(!(I2C->SR1 & I2C_SR1_SB), 1);
-
+  
   //Записываем в регистр данных адрес ведомого устройства и переходим
   //в режим чтения (установкой младшего бита в 1)
-  I2C->DR = address | 0x01;
-  //Бит который разрешает NACK на следующем принятом байте
-  //I2C->CR2 |= I2C_CR2_POS;
-  //Ждем подтверждения передачи адреса
-  wait_event(!(I2C->SR1 & I2C_SR1_ADDR), 1);
-  //Очистка бита ADDR чтением регистра SR3
-  I2C->SR3;
-  // wait for BTF
-  wait_event(!(I2C->SR1 & I2C_SR1_BTF), 1);
-  //Запрещаем подтверждение в конце посылки
-  I2C->CR2 &= (uint8_t)(~I2C_CR2_ACK);
-  //Заплатка из Errata
-  disableInterrupts();
-  // Read 1st byte
-  data[0] = I2C->DR;
-  //Устанавлием бит STOP
-  I2C->CR2 |= I2C_CR2_STOP;
-  // Read 2nd byte
-  data[1] = I2C->DR;
-  //Заплатка из Errata
-  enableInterrupts();
-  // Wait for RXNE
-  wait_event(!(I2C->SR1 & I2C_SR1_RXNE), 1);
-  // Read 3rd Data byte
-  data[2] = I2C->DR;
-
+  I2C->DR = addr;
+  
+  //Дальше алгоритм зависит от количества принимаемых байт
+  //N=1
+  if(length == 1){
+    //Запрещаем подтверждение в конце посылки
+    I2C->CR2 &= ~I2C_CR2_ACK;
+    //Ждем подтверждения передачи адреса
+    wait_event(!(I2C->SR1 & I2C_SR1_ADDR), 1);
+    
+    //Заплатка из Errata
+    __disable_interrupt();
+    //Очистка бита ADDR чтением регистра SR3
+    I2C->SR3;
+    
+    //Устанавлием бит STOP
+    I2C->CR2 |= I2C_CR2_STOP;
+    //Заплатка из Errata
+    __enable_interrupt();
+    
+    //Ждем прихода данных в RD
+    wait_event(!(I2C->SR1 & I2C_SR1_RXNE), 1);
+    
+    //Читаем принятый байт
+    *data = I2C->DR;
+  } 
+  //N=2
+  else if (length == 2) {
+    //Бит который разрешает NACK на следующем принятом байте
+    I2C->CR2 |= I2C_CR2_POS;
+    //Ждем подтверждения передачи адреса
+    wait_event(!(I2C->SR1 & I2C_SR1_ADDR), 1);
+    //Заплатка из Errata
+    __disable_interrupt();
+    //Очистка бита ADDR чтением регистра SR3
+    I2C->SR3;
+    //Запрещаем подтверждение в конце посылки
+    I2C->CR2 &= ~I2C_CR2_ACK;
+    //Заплатка из Errata
+    __enable_interrupt();
+    //Ждем момента, когда первый байт окажется в DR,
+    //а второй в сдвиговом регистре
+    wait_event(!(I2C->SR1 & I2C_SR1_BTF), 1);
+    
+    //Заплатка из Errata
+    __disable_interrupt();
+    //Устанавлием бит STOP
+    I2C->CR2 |= I2C_CR2_STOP;
+    //Читаем принятые байты
+    *data++ = I2C->DR;
+    //Заплатка из Errata
+    __enable_interrupt();
+    *data = I2C->DR;
+  } 
+  //N>2
+  else if (length > 2) {
+    //Ждем подтверждения передачи адреса
+    wait_event(!(I2C->SR1 & I2C_SR1_ADDR), 1);
+    
+    //Заплатка из Errata
+    __disable_interrupt();
+    
+    //Очистка бита ADDR чтением регистра SR3
+    I2C->SR3;
+    
+    //Заплатка из Errata
+    __enable_interrupt();
+    
+    while (length-- > 3 && I2C_timeout) {
+      //Ожидаем появления данных в DR и сдвиговом регистре
+      wait_event(!(I2C->SR1 & I2C_SR1_BTF), 1);
+      //Читаем принятый байт из DR
+      *data++ = I2C->DR;
+    }
+    //Время таймаута вышло
+    if (!I2C_timeout) return I2C_TIMEOUT;
+    
+    //Осталось принять 3 последних байта
+    //Ждем, когда в DR окажется N-2 байт, а в сдвиговом регистре
+    //окажется N-1 байт
+    wait_event(!(I2C->SR1 & I2C_SR1_BTF), 1);
+    //Запрещаем подтверждение в конце посылки
+    I2C->CR2 &= ~I2C_CR2_ACK;
+    //Заплатка из Errata
+    __disable_interrupt();
+    //Читаем N-2 байт из RD, тем самым позволяя принять в сдвиговый
+    //регистр байт N, но теперь в конце приема отправится посылка NACK
+    *data++ = I2C->DR;
+    //Посылка STOP
+    I2C->CR2 |= I2C_CR2_STOP;
+    //Читаем N-1 байт
+    *data++ = I2C->DR;
+    //Заплатка из Errata
+    __enable_interrupt();
+    //Ждем, когда N-й байт попадет в DR из сдвигового регистра
+    wait_event(!(I2C->SR1 & I2C_SR1_RXNE), 1);
+    //Читаем N байт
+    *data++ = I2C->DR;
+  }
+  
   //Ждем отправки СТОП посылки
   wait_event((I2C->CR2 & I2C_CR2_STOP), 1);
   //Сбрасывает бит POS, если вдруг он был установлен

+ 3 - 3
lib/i2c.h

@@ -23,11 +23,11 @@ typedef enum {
 } t_i2c_status;
 
 // Инициализация I2C интерфейса
-extern void i2c_master_init(void);
+void i2c_master_init(void);
 
 // Wrie 1 byte
-extern t_i2c_status  i2c_wr_reg(uint8_t address, uint8_t data);
+t_i2c_status  i2c_wr_data(uint8_t address, uint8_t num_bytes_to_wr, uint8_t * data);
 
 // Read 3 bytes
-extern t_i2c_status  i2c_rd_reg(uint8_t address, uint8_t * data);
+t_i2c_status  i2c_rd_data(uint8_t address, uint8_t num_bytes_to_rw, uint8_t * data);
 #endif // I2C_H