Browse Source

Be more compliant in the I2C protocol

- Enter a repeated-start for reading data
- Write in the same session
Yuri D'Elia 3 years ago
parent
commit
c2e8d229a7
3 changed files with 84 additions and 42 deletions
  1. 2 4
      Firmware/pat9125.c
  2. 67 33
      Firmware/twi.c
  3. 15 5
      Firmware/twi.h

+ 2 - 4
Firmware/pat9125.c

@@ -263,8 +263,7 @@ uint8_t pat9125_rd_reg(uint8_t addr)
 	if (!swi2c_readByte_A8(PAT9125_I2C_ADDR, addr, &data)) //NO ACK error
         goto error;
 #elif defined(PAT9125_I2C)
-	if (twi_rw8(PAT9125_I2C_ADDR,TW_WRITE,&addr) ||
-        twi_rw8(PAT9125_I2C_ADDR,TW_READ,&data))
+	if (twi_r8(PAT9125_I2C_ADDR,addr,&data))
         goto error;
 #endif
 	return data;
@@ -286,8 +285,7 @@ void pat9125_wr_reg(uint8_t addr, uint8_t data)
 	if (!swi2c_writeByte_A8(PAT9125_I2C_ADDR, addr, &data)) //NO ACK error
         goto error;
 #elif defined(PAT9125_I2C)
-	if (twi_rw8(PAT9125_I2C_ADDR,TW_WRITE,&addr) ||
-        twi_rw8(PAT9125_I2C_ADDR,TW_READ,&data))
+	if (twi_w8(PAT9125_I2C_ADDR,addr,data))
         goto error;
 #endif
     return;

+ 67 - 33
Firmware/twi.c

@@ -48,55 +48,89 @@ void twi_disable(void)
   digitalWrite(SCL, 0);
 }
 
-static void twi_wait()
+
+static void twi_stop()
 {
-    while(!(TWCR & _BV(TWINT)));
+  TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWSTO);
 }
 
-uint8_t twi_rw8(uint8_t address, uint8_t mode, uint8_t* data)
+
+static uint8_t twi_wait(uint8_t status)
+{
+  while(!(TWCR & _BV(TWINT)));
+  if(TW_STATUS != status)
+  {
+      twi_stop();
+      return 1;
+  }
+  return 0;
+}
+
+
+static uint8_t twi_start(uint8_t address, uint8_t reg)
 {
   // send start condition
   TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWSTA);
-  twi_wait();
-  if(TW_STATUS != TW_START)
+  if(twi_wait(TW_START))
       return 1;
 
   // send address
-  TWDR = mode;
-  TWDR |= (address << 1);
+  TWDR = TW_WRITE | (address << 1);
   TWCR = _BV(TWEN) | _BV(TWINT);
-  twi_wait();
+  if(twi_wait(TW_MT_SLA_ACK))
+      return 2;
 
-  if(mode == TW_WRITE)
-  {
-      if(TW_STATUS != TW_MT_SLA_ACK)
-          return 2;
-
-      // send data
-      TWDR = *data;
-      TWCR = _BV(TWEN) | _BV(TWINT);
-      twi_wait();
-      if(TW_STATUS != TW_MT_DATA_ACK)
-          return 3;
-  }
-  else
-  {
-      if(TW_STATUS != TW_MR_SLA_ACK)
-          return 2;
+  // send register
+  TWDR = reg;
+  TWCR = _BV(TWEN) | _BV(TWINT);
+  if(twi_wait(TW_MT_DATA_ACK))
+      return 3;
 
-      // receive data
-      TWCR = _BV(TWEN) | _BV(TWINT);
-      twi_wait();
+  return 0;
+}
 
-      // accept ACK or NACK (since only 1 byte is read)
-      if(!(TW_STATUS & TW_MR_DATA_ACK))
-          return 3;
 
-      *data = TWDR;
-  }
+uint8_t twi_r8(uint8_t address, uint8_t reg, uint8_t* data)
+{
+  if(twi_start(address, reg))
+      return 1;
+
+  // repeat start
+  TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWSTA);
+  if(twi_wait(TW_REP_START))
+      return 2;
+
+  // start receiving
+  TWDR = TW_READ | (address << 1);
+  TWCR = _BV(TWEN) | _BV(TWINT);
+  if(twi_wait(TW_MR_SLA_ACK))
+      return 3;
+
+  // receive data
+  TWCR = _BV(TWEN) | _BV(TWINT);
+  if(twi_wait(TW_MR_DATA_NACK))
+      return 4;
+
+  *data = TWDR;
 
   // send stop
-  TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWSTO);
+  twi_stop();
+  return 0;
+}
+
 
+uint8_t twi_w8(uint8_t address, uint8_t reg, uint8_t data)
+{
+  if(twi_start(address, reg))
+      return 1;
+
+  // send data
+  TWDR = data;
+  TWCR = _BV(TWEN) | _BV(TWINT);
+  if(twi_wait(TW_MT_DATA_ACK))
+      return 2;
+
+  // send stop
+  twi_stop();
   return 0;
 }

+ 15 - 5
Firmware/twi.h

@@ -43,11 +43,21 @@ void twi_init(void);
 void twi_disable(void);
 
 /*
- * Function twi_rw8
- * Desc     read/write a single byte from a device
+ * Function twi_r8
+ * Desc     read a single byte from a device
  * Input    address: 7bit i2c device address
- *          mode: TW_READ or TW_WRITE
- *          data: pointer to byte
+ *          reg: register address
+ *          data: pointer to byte for result
  * Output   0 on success
  */
-uint8_t twi_rw8(uint8_t address, uint8_t mode, uint8_t* data);
+uint8_t twi_r8(uint8_t address, uint8_t reg, uint8_t* data);
+
+/*
+ * Function twi_w8
+ * Desc     write a single byte from a device
+ * Input    address: 7bit i2c device address
+ *          reg: register address
+ *          data: byte to write
+ * Output   0 on success
+ */
+uint8_t twi_w8(uint8_t address, uint8_t reg, uint8_t data);