diff --git a/os/hal/include/i2c.h b/os/hal/include/i2c.h index e93f2249c..66019ccbf 100644 --- a/os/hal/include/i2c.h +++ b/os/hal/include/i2c.h @@ -61,12 +61,10 @@ typedef enum { I2C_UNINIT = 0, /**< Not initialized. */ I2C_STOP = 1, /**< Stopped. */ I2C_READY = 2, /**< Ready. */ - I2C_MACTIVE = 3, /**< START condition sent. */ - I2C_MTXREADY = 4, /**< address sent when tx-flag set. */ - I2C_MTRANSMIT = 5, /**< Master transmitting. */ - - I2C_MRECEIVE = 6, /**< Master receiving. */ + I2C_MTRANSMIT = 4, /**< Master transmitting. */ + I2C_MRECEIVE = 5, /**< Master receiving. */ + I2C_MWAIT_TF = 6, /**< Master wait Transmission Finished */ I2C_MERROR = 7 /**< Error condition. */ } i2cstate_t; @@ -123,14 +121,14 @@ extern "C" { void i2cObjectInit(I2CDriver *i2cp); void i2cStart(I2CDriver *i2cp, I2CConfig *config); void i2cStop(I2CDriver *i2cp); - void i2cMasterTransmit(I2CDriver *i2cp, I2CSlaveConfig *i2cscfg, bool_t restart); + void i2cMasterTransmit(I2CDriver *i2cp, I2CSlaveConfig *i2cscfg); void i2cMasterReceive(I2CDriver *i2cp, I2CSlaveConfig *i2cscfg); - void i2cMasterStartI(I2CDriver *i2cp,uint16_t header,i2ccallback_t callback); - void i2cMasterStopI(I2CDriver *i2cp, i2ccallback_t callback); - void i2cMasterRestartI(I2CDriver *i2cp, i2ccallback_t callback); - void i2cMasterTransmitI(I2CDriver *i2cp, size_t n, const uint8_t *txbuf, i2ccallback_t callback); - void i2cMasterReceiveI(I2CDriver *i2cp, size_t n, uint8_t *rxbuf, i2ccallback_t callback); + void i2cMasterStartI(I2CDriver *i2cp,uint16_t header); + void i2cMasterStopI(I2CDriver *i2cp); + void i2cMasterRestartI(I2CDriver *i2cp); + void i2cMasterTransmitI(I2CDriver *i2cp, size_t n, const uint8_t *txbuf); + void i2cMasterReceiveI(I2CDriver *i2cp, size_t n, uint8_t *rxbuf); #if I2C_USE_MUTUAL_EXCLUSION void i2cAcquireBus(I2CDriver *i2cp); void i2cReleaseBus(I2CDriver *i2cp); diff --git a/os/hal/platforms/STM32/i2c_lld.c b/os/hal/platforms/STM32/i2c_lld.c index a6e03d010..5efa5c082 100644 --- a/os/hal/platforms/STM32/i2c_lld.c +++ b/os/hal/platforms/STM32/i2c_lld.c @@ -61,9 +61,10 @@ static i2cflags_t translate_errors(uint16_t sr) { - +/* This function handle all regular interrupt conditions + * + */ static void i2c_serve_event_interrupt(I2CDriver *i2cp) { - // TODO: enable interrupts in config registers if ((i2cp->id_state == I2C_READY) && (i2cp->id_i2c->SR1 & I2C_SR1_SB)){// start bit sent i2cp->id_state = I2C_MACTIVE; @@ -71,24 +72,104 @@ static void i2c_serve_event_interrupt(I2CDriver *i2cp) { i2cp->id_slave_config->rw_bit; // write slave address in DR } - // now wait interrupt with ADDR flag + // now "wait" interrupt with ADDR flag // TODO: 10 bit address handling here + // TODO: setup here transmission via DMA like in ADC if ((i2cp->id_state == I2C_MACTIVE) && (i2cp->id_i2c->SR1 & I2C_SR1_ADDR)){// address successfully sent if(i2cp->id_slave_config->rw_bit == I2C_WRITE){ - i2cp->id_state = I2C_MTRANSMIT; - // TODO: setup here transmission via DMA like in ADC + i2c_lld_txbyte(i2cp); // send first byte + i2cp->id_state = I2C_MTRANSMIT; // change state } else { - i2cp->id_state = I2C_MRECEIVE; - // TODO: setup here transmission via DMA like in ADC + i2c_lld_rxbyte(i2cp); // read first byte + i2cp->id_state = I2C_MRECEIVE; // change stat } } + + // transmitting bytes one by one + if ((i2cp->id_state == I2C_MTRANSMIT) && (i2cp->id_i2c->SR1 & I2C_SR1_TXE)){ + if (i2c_lld_txbyte(i2cp)) + i2cp->id_state = I2C_MWAIT_TF; // last byte written + } + + //receiving bytes one by one + if ((i2cp->id_state == I2C_MRECEIVE) && (i2cp->id_i2c->SR1 & I2C_SR1_RXNE)){ + if (i2c_lld_txbyte(i2cp)) + i2cp->id_state = I2C_MWAIT_TF; // last byte read + } + + // "wait" BTF bit in status register + if ((i2cp->id_state == I2C_MWAIT_TF) && (i2cp->id_i2c->SR1 & I2C_SR1_BTF)){ + if (i2cp->id_slave_config->restart){ // restart need + i2cp->id_state = I2C_MACTIVE; + //i2cp->id_i2c->CR1 |= I2C_CR1_START; // send restart + i2cp->id_slave_config->id_restart_callback(i2cp, i2cp->id_slave_config); // callback call + } + else { + i2cp->id_state = I2C_READY; + i2cp->id_i2c->CR1 |= I2C_CR1_STOP; // stop communication + i2cp->id_slave_config->id_stop_callback(i2cp, i2cp->id_slave_config); // callback call + } + } +} + +/* helper function, not API + * write bytes in DR register + * return TRUE if last byte written + */ +bool_t i2c_lld_txbyte(I2CDriver *i2cp) { + // temporal variables + #define txbuf i2cp->id_slave_config->txbuf + #define txbufhead i2cp->id_slave_config->txbufhead + #define txdepth i2cp->id_slave_config->txdepth + + if (txbufhead < txdepth){ + i2cp->id_i2c->DR = txbuf[txbufhead]; + txbufhead++; + return(FALSE); + } + + txbufhead = 0; + #undef txbuf + #undef txbufhead + #undef txdepth + + return(TRUE); // last byte written +} + + +/* helper function, not API + * read bytes from DR register + * return TRUE if last byte read + */ +bool_t i2c_lld_rxbyte(I2CDriver *i2cp) { + // temporal variables + #define rxbuf i2cp->id_slave_config->rxbuf + #define rxbufhead i2cp->id_slave_config->rxbufhead + #define rxdepth i2cp->id_slave_config->rxdepth + + if (rxbufhead < rxdepth){ + rxbuf[rxbufhead] = i2cp->id_i2c->DR; + rxbufhead++; + return(FALSE); + } + + rxbufhead = 0; + #undef rxbuf + #undef rxbufhead + #undef rxdepth + + return(TRUE); // last byte read } static void i2c_serve_error_interrupt(I2CDriver *i2cp) { - + // TODO:remove this stub + //simply trap for errors + while TRUE{ + translate_errors(i2cp->id_i2c->SR1); + } } #if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__) @@ -186,9 +267,9 @@ void i2c_lld_start(I2CDriver *i2cp) { i2cp->id_i2c->CR1 = i2cp->id_config->i2cc_cr1; i2cp->id_i2c->CR2 = i2cp->id_config->i2cc_cr2 | - //I2C_CR2_ITERREN | - //I2C_CR2_ITEVTEN | - //I2C_CR2_ITBUFEN | + I2C_CR2_ITERREN | + I2C_CR2_ITEVTEN | + I2C_CR2_ITBUFEN | 36; //TODO: replace this by macro calculation /* TODO: * 1. macro timing calculator @@ -230,10 +311,32 @@ void i2c_lld_stop(I2CDriver *i2cp) { -void i2c_lld_master_transmitI(I2CDriver *i2cp, I2CSlaveConfig *i2cscfg, bool_t restart){ - ; +void i2c_lld_master_transmitI(I2CDriver *i2cp, I2CSlaveConfig *i2cscfg){ + //TODO: check txbytes <= sizeof(i2cscfg->txbuf) here, or in hylevel API + + i2cp->id_slave_config = i2cscfg; + i2cp->id_slave_config->rw_bit = I2C_WRITE; + + + // generate start condition. Later transmission goes asynchronously + i2cp->id_i2c->CR1 |= I2C_CR1_START; } +void i2c_lld_master_receiveI(I2CDriver *i2cp, I2CSlaveConfig *i2cscfg){ + //TODO: check txbytes <= sizeof(i2cscfg->txbuf) here, or in hylevel API + + i2cp->id_slave_config = i2cscfg; + i2cp->id_slave_config->rw_bit = I2C_READ; + + // reset restart flag + i2cp->id_slave_config->restart = FALSE; + + // generate (re)start condition. Later connection goes asynchronously + i2cp->id_i2c->CR1 |= I2C_CR1_START; + // TODO: need to clear ACK bit somewhere +} + + /** * @brief Transmits data ever the I2C bus as master. @@ -251,9 +354,6 @@ void i2c_lld_master_transmit(I2CDriver *i2cp, I2CSlaveConfig *i2cscfg, bool_t re i2cp->id_slave_config = i2cscfg; i2cp->id_slave_config->rw_bit = I2C_WRITE; - //TODO: setup DMA channel here - // - // i2cp->id_i2c->CR1 |= I2C_CR1_START; // generate start condition while (!(i2cp->id_i2c->SR1 & I2C_SR1_SB)){ diff --git a/os/hal/platforms/STM32/i2c_lld.h b/os/hal/platforms/STM32/i2c_lld.h index 72b190eba..1b684a167 100644 --- a/os/hal/platforms/STM32/i2c_lld.h +++ b/os/hal/platforms/STM32/i2c_lld.h @@ -77,13 +77,25 @@ /* Driver data structures and types. */ /*===========================================================================*/ +/** + * @brief Type of a structure representing an I2C driver. + */ +typedef struct I2CDriver I2CDriver; + +/** + * @brief Type of a structure representing an I2C driver. + */ +typedef struct I2CSlaveConfig I2CSlaveConfig; + + /** * @brief I2C notification callback type. * * @param[in] i2cp FIXME: pointer to the @p I2CDriver object triggering the * callback */ -typedef void (*i2ccallback_t)(void); +typedef void (*i2ccallback_t)(I2CDriver *i2cp, I2CSlaveConfig *i2cscfg); +//typedef void (*i2ccallback_t)(void); /** * @brief I2C error notification callback type. @@ -93,6 +105,7 @@ typedef void (*i2ccallback_t)(void); */ typedef void (*i2cerrorcallback_t)(void); + /** * @brief Driver configuration structure. */ @@ -123,27 +136,31 @@ typedef uint8_t i2cblock_t; * @brief Structure representing an I2C slave configuration. * @details Each slave has its own data buffers, adress, and error flags. */ -typedef struct { +struct I2CSlaveConfig{ + /** + * @brief Callback pointer. + * @note Transfer finished callback. Invoke when all data transferred, or + * by DMA buffer events + * @p NULL then the callback is disabled. + */ + i2ccallback_t id_stop_callback; + i2ccallback_t id_restart_callback; /** * @brief Callback pointer. * @note TODO: I don't know, when this callback is inwoked * @p NULL then the callback is disabled. */ - i2ccallback_t id_callback; - /** - * @brief Callback pointer. - * @note TODO: I don't know, when this callback is inwoked - * @p NULL then the callback is disabled. - */ - i2cerrorcallback_t id_errcallback; + i2cerrorcallback_t id_err_callback; - i2cblock_t *rxbuf; // pointer to buffer - size_t rxdepth;// depth of buffer - size_t rxbytes;// count of bytes to sent in one sending + i2cblock_t *rxbuf; // pointer to buffer + size_t rxdepth; // depth of buffer + size_t rxbytes; // count of bytes to sent in one sending + size_t rxbufhead; // head pointer to current data byte i2cblock_t *txbuf; size_t txdepth; size_t txbytes; + size_t txbufhead; uint8_t slave_addr1; // 7-bit address of the slave uint8_t slave_addr2; // used in 10-bit address mode @@ -154,14 +171,14 @@ typedef struct { bool_t restart; // send restart or stop event after complete data tx/rx -}I2CSlaveConfig; +}; /** * @brief Structure representing an I2C driver. */ -typedef struct { +struct I2CDriver{ /** * @brief Driver state. */ @@ -195,7 +212,10 @@ typedef struct { */ I2C_TypeDef *id_i2c; -} I2CDriver; +} ; + + + /*===========================================================================*/ @@ -224,9 +244,14 @@ void i2c_lld_start(I2CDriver *i2cp); void i2c_lld_stop(I2CDriver *i2cp); void i2c_lld_master_start(I2CDriver *i2cp, uint16_t header); void i2c_lld_master_stop(I2CDriver *i2cp); + void i2c_lld_master_transmit(I2CDriver *i2cp, I2CSlaveConfig *i2cscfg, bool_t restart); -void i2c_lld_master_transmitI(I2CDriver *i2cp, I2CSlaveConfig *i2cscfg, bool_t restart); +bool_t i2c_lld_txbyte(I2CDriver *i2cp); // helper function +void i2c_lld_master_transmitI(I2CDriver *i2cp, I2CSlaveConfig *i2cscfg); + void i2c_lld_master_receive(I2CDriver *i2cp, I2CSlaveConfig *i2cscfg); +void i2c_lld_master_receiveI(I2CDriver *i2cp, I2CSlaveConfig *i2cscfg); +bool_t i2c_lld_rxbyte(I2CDriver *i2cp); //static i2cflags_t translate_errors(uint16_t sr); #ifdef __cplusplus diff --git a/os/hal/src/i2c.c b/os/hal/src/i2c.c index e621c652d..5a0471e0f 100644 --- a/os/hal/src/i2c.c +++ b/os/hal/src/i2c.c @@ -126,7 +126,7 @@ void i2cStop(I2CDriver *i2cp) { * @param[in] txbuf the pointer to the transmit buffer * */ -void i2cMasterTransmit(I2CDriver *i2cp, I2CSlaveConfig *i2cscfg, bool_t restart) { +void i2cMasterTransmit(I2CDriver *i2cp, I2CSlaveConfig *i2cscfg) { chDbgCheck((i2cp != NULL) && (i2cscfg != NULL), "i2cMasterTransmit"); @@ -134,7 +134,7 @@ void i2cMasterTransmit(I2CDriver *i2cp, I2CSlaveConfig *i2cscfg, bool_t restart) "i2cMasterTransmit(), #1", "not active"); - i2c_lld_master_transmit(i2cp, i2cscfg, restart); + i2c_lld_master_transmitI(i2cp, i2cscfg); } @@ -156,7 +156,7 @@ void i2cMasterReceive(I2CDriver *i2cp, I2CSlaveConfig *i2cscfg) { "i2cMasterReceive(), #1", "not active"); - i2c_lld_master_receive(i2cp, i2cscfg); + i2c_lld_master_receiveI(i2cp, i2cscfg); }