aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--os/hal/include/i2c.h18
-rw-r--r--os/hal/platforms/STM32/i2c_lld.c63
2 files changed, 55 insertions, 26 deletions
diff --git a/os/hal/include/i2c.h b/os/hal/include/i2c.h
index 5a85ed5f7..5f4b2cc6f 100644
--- a/os/hal/include/i2c.h
+++ b/os/hal/include/i2c.h
@@ -71,14 +71,16 @@
* @brief Driver state machine possible states.
*/
typedef enum {
- I2C_UNINIT = 0, /**< Not initialized. */
- I2C_STOP = 1, /**< Stopped. */
- I2C_READY = 2, /**< Ready. */
- I2C_MACTIVE = 3, /**< START condition sent. */
- I2C_MTRANSMIT = 4, /**< Master transmitting. */
- I2C_MRECEIVE = 5, /**< Master receiving. */
- I2C_MWAIT_TF = 6, /**< Master wait Transmission Finished */
- I2C_MERROR = 7 /**< Error condition. */
+ I2C_UNINIT = 0, /**< Not initialized. */
+ I2C_STOP = 1, /**< Stopped. */
+ I2C_READY = 2, /**< Ready. Start condition generated. */
+ I2C_MACTIVE = 3, /**< I2C configured and waiting start cond. */
+ I2C_10BIT_HANDSHAKE = 4, /**< 10-bit address sending */
+ I2C_MWAIT_ADDR_ACK = 5, /**< Waiting ACK on address sending. */
+ I2C_MTRANSMIT = 6, /**< Master transmitting. */
+ I2C_MRECEIVE = 7, /**< Master receiving. */
+ I2C_MWAIT_TF = 8, /**< Master wait Transmission Finished */
+ I2C_MERROR = 9 /**< Error condition. */
} i2cstate_t;
#include "i2c_lld.h"
diff --git a/os/hal/platforms/STM32/i2c_lld.c b/os/hal/platforms/STM32/i2c_lld.c
index 68e42972c..aecb1d24d 100644
--- a/os/hal/platforms/STM32/i2c_lld.c
+++ b/os/hal/platforms/STM32/i2c_lld.c
@@ -110,32 +110,59 @@ static void i2c_serve_event_interrupt(I2CDriver *i2cp) {
int n = 0;
int m = 0;
+ /* In 10-bit addressing mode,
+ – To enter Transmitter mode, a master sends the header (11110xx0) and then the
+ slave address, (where xx denotes the two most significant bits of the address).
+ – To enter Receiver mode, a master sends the header (11110xx0) and then the
+ slave address. Then it should send a repeated Start condition followed by the
+ header (11110xx1), (where xx denotes the two most significant bits of the
+ address).
+ The TRA bit indicates whether the master is in Receiver or Transmitter mode.*/
+
if ((i2cp->id_state == I2C_READY) && (i2cp->id_i2c->SR1 & I2C_SR1_SB)){// start bit sent
i2cp->id_state = I2C_MACTIVE;
- /*TODO: 10 bit address handling
- In 10-bit addressing mode,
- – To enter Transmitter mode, a master sends the header (11110xx0) and then the
- slave address, (where xx denotes the two most significant bits of the address).
- – To enter Receiver mode, a master sends the header (11110xx0) and then the
- slave address. Then it should send a repeated Start condition followed by the
- header (11110xx1), (where xx denotes the two most significant bits of the
- address).
- The TRA bit indicates whether the master is in Receiver or Transmitter mode.*/
-
- i2cp->id_i2c->DR = (i2cp->id_slave_config->address << 1) |
- i2cp->id_slave_config->rw_bit; // write slave address in DR
+
+ if(!(i2cp->id_slave_config->address & 0x8000)){ // slave address is 7-bit
+ i2cp->id_i2c->DR = ((i2cp->id_slave_config->address & 0x7F) << 1) |
+ i2cp->id_slave_config->rw_bit;
+ i2cp->id_state = I2C_MWAIT_ADDR_ACK;
+ return;
+ }
+ else{ // slave address is 10-bit
+ i2cp->id_state = I2C_10BIT_HANDSHAKE;
+ // send MSB with header. LSB = 0.
+ i2cp->id_i2c->DR = ((i2cp->id_slave_config->address >> 7) & 0x6) | 0xF0;
+ return;
+ }
+ }
+
+ // "wait" interrupt with ADD10 flag
+ if ((i2cp->id_state == I2C_10BIT_HANDSHAKE) && (i2cp->id_i2c->SR1 & I2C_SR1_ADD10)){
+ i2cp->id_i2c->DR = i2cp->id_slave_config->address & 0x00FF; // send remaining bits of address
+ if (!(i2cp->id_slave_config->rw_bit))
+ // in transmit mode there is nothing to do with 10-bit handshaking
+ i2cp->id_state = I2C_MWAIT_ADDR_ACK;
return;
}
- if ((i2cp->id_state == I2C_MACTIVE) && (i2cp->id_i2c->SR1 & I2C_SR1_ADD10)){// header sent
+ // "wait" interrupt with ADDR
+ if ((i2cp->id_state == I2C_10BIT_HANDSHAKE) && (i2cp->id_i2c->SR1 & I2C_SR1_ADDR)){// address ACKed
+ i2cp->id_i2c->CR1 |= I2C_CR1_START;
+ return;
+ }
+ if ((i2cp->id_state == I2C_10BIT_HANDSHAKE) && (i2cp->id_i2c->SR1 & I2C_SR1_SB)){// restart generated
+ // send MSB with header. LSB = 1
+ i2cp->id_i2c->DR = ((i2cp->id_slave_config->address >> 7) & 0x6) | 0xF1;
+ i2cp->id_state = I2C_MWAIT_ADDR_ACK;
+ return;
}
- // "wait" interrupt with ADDR flag
- if ((i2cp->id_state == I2C_MACTIVE) && (i2cp->id_i2c->SR1 & I2C_SR1_ADDR)){// address successfully sent
- if(i2cp->id_i2c->SR2 & I2C_SR2_TRA){
- i2c_lld_txbyte(i2cp); // send first byte
+ // "wait" interrupt with ADDR (ADD10 in 10-bit receiver mode) flag
+ if ((i2cp->id_state == I2C_MWAIT_ADDR_ACK) && (i2cp->id_i2c->SR1 & I2C_SR1_ADDR & I2C_SR1_ADD10)){// address ACKed
+ if(i2cp->id_i2c->SR2 & I2C_SR2_TRA){// I2C is transmitting data
i2cp->id_state = I2C_MTRANSMIT; // change state
+ i2c_lld_txbyte(i2cp); // send first byte
return;
}
else {
@@ -145,7 +172,7 @@ static void i2c_serve_event_interrupt(I2CDriver *i2cp) {
*/
if (i2cp->id_slave_config->rxbytes > 1)
i2cp->id_i2c->CR1 |= I2C_CR1_ACK; // set ACK bit
- i2cp->id_state = I2C_MRECEIVE; // change status
+ i2cp->id_state = I2C_MRECEIVE; // change state
return;
}
}