From eafaa7d6cfafb767ddf58caba640d63f418c5af6 Mon Sep 17 00:00:00 2001 From: barthess Date: Thu, 10 Feb 2011 16:35:28 +0000 Subject: [PATCH] I2C. 10-bit slave addressing done. Not tested at all. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/branches/i2c_dev@2729 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/include/i2c.h | 18 +++++---- os/hal/platforms/STM32/i2c_lld.c | 63 +++++++++++++++++++++++--------- 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; } - // "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 + 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 (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; } }