From 302d06cc6652cd44f961c35c7194ff3145f55406 Mon Sep 17 00:00:00 2001 From: barthess Date: Wed, 20 Jul 2011 08:35:05 +0000 Subject: [PATCH] I2C. All polling waitins code replaced by "waiting" GPT interrups. Documentation fixes. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/branches/i2c_dev@3167 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/dox/i2c.dox | 20 ++-- os/hal/include/i2c.h | 11 ++- os/hal/platforms/STM32/i2c_lld.c | 160 +++++++++++++++++-------------- os/hal/platforms/STM32/i2c_lld.h | 43 +++------ 4 files changed, 118 insertions(+), 116 deletions(-) diff --git a/os/hal/dox/i2c.dox b/os/hal/dox/i2c.dox index cd5e3f698..8e6f78649 100644 --- a/os/hal/dox/i2c.dox +++ b/os/hal/dox/i2c.dox @@ -22,7 +22,12 @@ * @defgroup I2C I2C Driver * @brief Generic I2C Driver. * @details This module implements a generic I2C (Inter-Integrated Circuit) - * driver. + * driver. On STM32 platform you can choose method of waiting START + * and STOP bits: polling wait or wait using GPT. GPT method use + * one timer per I2C interface, on the other hand -- polling is + * block function that starts transfer. + * @note If you decide to use polling wait -- do NOT start transmit or + * receive from callback because it run in ISR context. * @pre In order to use the I2C driver the @p HAL_USE_I2C option * must be enabled in @p halconf.h. * @@ -34,20 +39,23 @@ * @dot digraph example { rankdir="LR"; - node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", + node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="false", width="0.9", height="0.9"]; edge [fontname=Helvetica, fontsize=8]; uninit [label="I2C_UNINIT", style="bold"]; stop [label="I2C_STOP\nLow Power"]; ready [label="I2C_READY\nClock Enabled"]; - active [label="I2C_ACTIVE\nBus Active"]; + active_tx [label="I2C_ACTIVE_TRANSMIT\nBus TX Active"]; + active_rx [label="I2C_ACTIVE_RECEIVE\nBus RX Active"]; uninit -> stop [label="i2cInit()"]; - stop -> stop [label="i2cStop()"]; + stop -> stop [label="i2cStop()"]; stop -> ready [label="i2cStart()"]; - ready -> active [label="i2cMasterTransmit()\ni2cMasterReceive()"]; - active -> ready [label="_i2c_isr_code()"]; + ready -> active_tx [label="i2cMasterTransmit()"]; + ready -> active_rx [label="i2cMasterReceive()"]; + active_tx -> ready [label="_i2c_isr_code()"]; + active_rx -> ready [label="_i2c_isr_code()"]; ready -> stop [label="i2cStop()"]; } * @enddot diff --git a/os/hal/include/i2c.h b/os/hal/include/i2c.h index 16d6f77b6..73f633353 100644 --- a/os/hal/include/i2c.h +++ b/os/hal/include/i2c.h @@ -79,11 +79,12 @@ */ typedef enum { /* master part */ - I2C_UNINIT = 0, /**< @brief Not initialized. */ - I2C_STOP = 1, /**< @brief Stopped. */ - I2C_READY = 2, /**< @brief Ready. */ - I2C_ACTIVE_TRANSMIT = 3,/**< @brief Transmit in progress. */ - I2C_ACTIVE_RECEIVE = 4, /**< @brief Receive in progress. */ + I2C_UNINIT = 0, /**< @brief Not initialized. */ + I2C_STOP = 1, /**< @brief Stopped. */ + I2C_READY = 2, /**< @brief Ready. */ + I2C_ACTIVE_TRANSMIT = 3, /**< @brief Transmit in progress. */ + I2C_ACTIVE_RECEIVE = 4, /**< @brief Receive in progress. */ + I2C_ACTIVE_TRANSCEIVE = 5, /**< @brief Receive after transmit in progress. */ /* Slave part. Not realized. */ I2C_SACTIVE = 10, diff --git a/os/hal/platforms/STM32/i2c_lld.c b/os/hal/platforms/STM32/i2c_lld.c index 84c395fb5..20db34fff 100644 --- a/os/hal/platforms/STM32/i2c_lld.c +++ b/os/hal/platforms/STM32/i2c_lld.c @@ -63,12 +63,10 @@ static volatile uint16_t dbgCR2 = 0; /* Driver local functions. */ /*===========================================================================*/ -#if STM32_I2C_USE_POLLING_WAIT +#if STM32_I2C_I2C1_USE_POLLING_WAIT #else -/* - * GPT1 callback. - */ -static void gpt1cb(GPTDriver *gptp) { +/* I2C1 GPT callback. */ +static void i2c1gptcb(GPTDriver *gptp) { (void)gptp; I2CDriver *i2cp = &I2CD1; @@ -84,18 +82,26 @@ static void gpt1cb(GPTDriver *gptp) { i2c_lld_master_receive(i2cp, i2cp->slave_addr, i2cp->rxbuf, i2cp->rxbytes); break; + case I2C_ACTIVE_TRANSCEIVE: + i2c_lld_master_transceive(i2cp); + break; + default: break; } chSysUnlockFromIsr(); } +/* I2C1 GPT configuration. */ +static const GPTConfig i2c1gptcfg = { + 1000000, /* 1MHz timer clock.*/ + i2c1gptcb /* Timer callback.*/ +}; +#endif /* STM32_I2C_I2C1_USE_POLLING_WAIT */ - - -/* - * GPT2 callback. - */ -static void gpt2cb(GPTDriver *gptp) { +#if STM32_I2C_I2C2_USE_POLLING_WAIT +#else +/* I2C2 GPT callback. */ +static void i2c2gptcb(GPTDriver *gptp) { (void)gptp; I2CDriver *i2cp = &I2CD2; @@ -111,24 +117,21 @@ static void gpt2cb(GPTDriver *gptp) { i2c_lld_master_receive(i2cp, i2cp->slave_addr, i2cp->rxbuf, i2cp->rxbytes); break; + case I2C_ACTIVE_TRANSCEIVE: + i2c_lld_master_transceive(i2cp); + break; + default: break; } chSysUnlockFromIsr(); } - -/* GPT1 configuration. */ -static const GPTConfig gpt1cfg = { +/* I2C2 GPT configuration. */ +static const GPTConfig i2c2gptcfg = { 1000000, /* 1MHz timer clock.*/ - gpt1cb /* Timer callback.*/ + i2c2gptcb /* Timer callback.*/ }; - -/* GPT2 configuration. */ -static const GPTConfig gpt2cfg = { - 1000000, /* 1MHz timer clock.*/ - gpt2cb /* Timer callback.*/ -}; -#endif /* STM32_I2C_USE_POLLING_WAIT */ +#endif /* STM32_I2C_I2C2_USE_POLLING_WAIT */ /** * @brief Function for I2C debugging purpose. @@ -322,6 +325,7 @@ static void i2c_serve_event_interrupt(I2CDriver *i2cp) { _i2c_isr_code(i2cp, i2cp->id_slave_config); /* Portable I2C ISR code defined in the high level driver. */ } else{ /* start reading operation */ + i2cp->id_i2c->CR1 |= I2C_CR1_START; /* send start bit */ i2c_lld_master_transceive(i2cp); } break; @@ -471,12 +475,12 @@ void i2c_lld_init(void) { i2cObjectInit(&I2CD1); I2CD1.id_i2c = I2C1; -#if !(STM32_I2C_I2C1_USE_POLLING_WAIT) - I2CD1.timer = &GPTD1;//TODO: remove hardcode - I2CD1.timer_cfg = &gpt1cfg;//TODO: remove hardcode -#else +#if STM32_I2C_I2C1_USE_POLLING_WAIT I2CD1.timer = NULL; I2CD1.timer_cfg = NULL; +#else + I2CD1.timer = &(STM32_I2C_I2C1_USE_GPT_TIM); + I2CD1.timer_cfg = &i2c1gptcfg; #endif /* !(STM32_I2C_I2C1_USE_POLLING_WAIT) */ #endif /* STM32_I2C_USE_I2C */ @@ -487,12 +491,12 @@ void i2c_lld_init(void) { i2cObjectInit(&I2CD2); I2CD2.id_i2c = I2C2; -#if !(STM32_I2C_I2C2_USE_POLLING_WAIT) - I2CD2.timer = &GPTD2;//TODO: remove hardcode - I2CD2.timer_cfg = &gpt2cfg;//TODO: remove hardcode -#else +#if STM32_I2C_I2C2_USE_POLLING_WAIT I2CD2.timer = NULL; I2CD2.timer_cfg = NULL; +#else + I2CD2.timer = &(STM32_I2C_I2C2_USE_GPT_TIM); + I2CD2.timer_cfg = &i2c2gptcfg; #endif /* !(STM32_I2C_I2C2_USE_POLLING_WAIT) */ #endif /* STM32_I2C_USE_I2C2 */ @@ -700,21 +704,7 @@ void i2c_lld_stop(I2CDriver *i2cp) { void i2c_lld_master_transmit(I2CDriver *i2cp, uint16_t slave_addr, uint8_t *txbuf, size_t txbytes, uint8_t *rxbuf, size_t rxbytes) { - i2cp->slave_addr = slave_addr; - i2cp->txbytes = txbytes; - i2cp->rxbytes = rxbytes; - i2cp->txbuf = txbuf; - i2cp->rxbuf = rxbuf; - - if(slave_addr & 0x8000){ /* 10-bit mode used */ - i2cp->slave_addr1 = ((slave_addr >>7) & 0x0006); /* add the two msb of 10-bit address to the header */ - i2cp->slave_addr1 |= 0xF0; /* add the header bits with LSB = 0 -> write */ - i2cp->slave_addr2 = slave_addr & 0x00FF; /* the remaining 8 bit of 10-bit address */ - } - else{ - i2cp->slave_addr1 = ((slave_addr <<1) & 0x00FE); /* LSB = 0 -> write */ - } - + /* "waiting" for STOP bit routine*/ chDbgAssert(!(i2cp->flags & I2C_FLG_TIMER_ARMED), "i2c_lld_master_transmit(), #1", "time to STOP is out"); if ((i2cp->id_i2c->CR1 & I2C_CR1_STOP) && i2cp->timer != NULL && i2cp->timer_cfg != NULL){ @@ -727,6 +717,24 @@ void i2c_lld_master_transmit(I2CDriver *i2cp, uint16_t slave_addr, ; } + /* init driver fields */ + i2cp->slave_addr = slave_addr; + i2cp->txbytes = txbytes; + i2cp->rxbytes = rxbytes; + i2cp->txbuf = txbuf; + i2cp->rxbuf = rxbuf; + + /* init address fields */ + if(slave_addr & 0x8000){ /* 10-bit mode used */ + i2cp->slave_addr1 = ((slave_addr >>7) & 0x0006); /* add the two msb of 10-bit address to the header */ + i2cp->slave_addr1 |= 0xF0; /* add the header bits with LSB = 0 -> write */ + i2cp->slave_addr2 = slave_addr & 0x00FF; /* the remaining 8 bit of 10-bit address */ + } + else{ + i2cp->slave_addr1 = ((slave_addr <<1) & 0x00FE); /* LSB = 0 -> write */ + } + + /* setting flags and register bits */ i2cp->flags = 0; i2cp->errors = 0; i2cp->id_i2c->CR1 &= ~I2C_CR1_POS; @@ -753,21 +761,7 @@ void i2c_lld_master_receive(I2CDriver *i2cp, uint16_t slave_addr, "i2c_lld_master_receive(), #1", "some interrupt sources not clear"); - i2cp->slave_addr = slave_addr; - i2cp->rxbytes = rxbytes; - i2cp->rxbuf = rxbuf; - - - if(slave_addr & 0x8000){ /* 10-bit mode used */ - i2cp->slave_addr1 = ((slave_addr >>7) & 0x0006); /* add the two msb of 10-bit address to the header */ - i2cp->slave_addr1 |= 0xF0; /* add the header bits (the LSB -> 1 will be add to second */ - i2cp->slave_addr2 = slave_addr & 0x00FF; /* the remaining 8 bit of 10-bit address */ - } - else{ - i2cp->slave_addr1 = ((slave_addr <<1) | 0x01); /* LSB = 1 -> receive */ - } - - + /* "waiting" for STOP bit routine*/ chDbgAssert(!(i2cp->flags & I2C_FLG_TIMER_ARMED), "i2c_lld_master_receive(), #1", "time to STOP is out"); if ((i2cp->id_i2c->CR1 & I2C_CR1_STOP) && i2cp->timer != NULL && i2cp->timer_cfg != NULL){ @@ -780,7 +774,22 @@ void i2c_lld_master_receive(I2CDriver *i2cp, uint16_t slave_addr, ; } + /* init driver fields */ + i2cp->slave_addr = slave_addr; + i2cp->rxbytes = rxbytes; + i2cp->rxbuf = rxbuf; + /* init address fields */ + if(slave_addr & 0x8000){ /* 10-bit mode used */ + i2cp->slave_addr1 = ((slave_addr >>7) & 0x0006); /* add the two msb of 10-bit address to the header */ + i2cp->slave_addr1 |= 0xF0; /* add the header bits (the LSB -> 1 will be add to second */ + i2cp->slave_addr2 = slave_addr & 0x00FF; /* the remaining 8 bit of 10-bit address */ + } + else{ + i2cp->slave_addr1 = ((slave_addr <<1) | 0x01); /* LSB = 1 -> receive */ + } + + /* setting flags and register bits */ i2cp->flags |= I2C_FLG_MASTER_RECEIVER; i2cp->errors = 0; @@ -814,6 +823,22 @@ void i2c_lld_master_transceive(I2CDriver *i2cp){ "i2c_lld_master_transceive(), #1", ""); + i2cp->id_state = I2C_ACTIVE_TRANSCEIVE; + + /* "waiting" for START bit routine*/ + chDbgAssert(!(i2cp->flags & I2C_FLG_TIMER_ARMED), + "i2c_lld_master_transceive(), #1", "time to START is out"); + if ((i2cp->id_i2c->CR1 & I2C_CR1_START) && i2cp->timer != NULL && i2cp->timer_cfg != NULL){ + gptStartOneShot(i2cp->timer, I2C_START_GPT_TIMEOUT); + i2cp->flags |= I2C_FLG_TIMER_ARMED; + return; + } + else{ + while(i2cp->id_i2c->CR1 & I2C_CR1_START) + ; + } + + /* init address fields */ if(i2cp->slave_addr & 0x8000){ /* 10-bit mode used */ i2cp->slave_addr1 = ((i2cp->slave_addr >>7) & 0x0006);/* add the two msb of 10-bit address to the header */ i2cp->slave_addr1 |= 0xF0; /* add the header bits (the LSB -> 1 will be add to second */ @@ -823,9 +848,7 @@ void i2c_lld_master_transceive(I2CDriver *i2cp){ i2cp->slave_addr1 |= 0x01; } - - - + /* setting flags and register bits */ i2cp->flags |= I2C_FLG_MASTER_RECEIVER; i2cp->errors = 0; i2cp->id_i2c->CR1 |= I2C_CR1_ACK; /* acknowledge returned */ @@ -839,17 +862,6 @@ void i2c_lld_master_transceive(I2CDriver *i2cp){ i2cp->id_i2c->CR1 |= I2C_CR1_POS; /* Acknowledge Position */ } - -//TODO: use timer here also!! - - i2cp->id_i2c->CR1 |= I2C_CR1_START; /* send start bit */ - - uint32_t timeout = I2C_START_TIMEOUT; - while((i2cp->id_i2c->CR1 & I2C_CR1_START) && timeout--) - ; - chDbgAssert(timeout <= I2C_START_TIMEOUT, - "i2c_lld_master_receive(), #1", "time is out"); - i2cp->id_i2c->CR2 |= (I2C_CR2_ITERREN|I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN); /* enable ERR, EVT & BUF ITs */ } diff --git a/os/hal/platforms/STM32/i2c_lld.h b/os/hal/platforms/STM32/i2c_lld.h index b5f75e77f..44ecdf70e 100644 --- a/os/hal/platforms/STM32/i2c_lld.h +++ b/os/hal/platforms/STM32/i2c_lld.h @@ -20,45 +20,25 @@ /*===========================================================================*/ /** - * @brief TODO!!!!!!!! - * @details If set to @p TRUE than waiting of STOP generation will use - * while() loop polling. Otherwise -- virtual timer will be used. - * @note The default is @p TRUE. - * @note Virtual timer resolution is 1/@p CH_FREQUENCY seconds. + * @brief I2C1 driver synchronization choice between GPT and polling. + * @note The default is polling wait. */ -#if !defined(STM32_I2C_I2C1_USE_GPT_TIM1) || \ - !defined(STM32_I2C_I2C1_USE_GPT_TIM2) || \ - !defined(STM32_I2C_I2C1_USE_GPT_TIM3) || \ - !defined(STM32_I2C_I2C1_USE_GPT_TIM4) || \ - !defined(STM32_I2C_I2C1_USE_GPT_TIM5) || \ - !defined(STM32_I2C_I2C1_USE_GPT_TIM8) || \ - !defined(STM32_I2C_I2C1_USE_VIRTUAL_TIMER) || \ - !defined(STM32_I2C_I2C1_USE_POLLING_WAIT) || \ +#if !defined(STM32_I2C_I2C1_USE_GPT_TIM) || \ + !defined(STM32_I2C_I2C1_USE_POLLING_WAIT) || \ defined(__DOXYGEN__) #define STM32_I2C_I2C1_USE_POLLING_WAIT TRUE #endif - - -#if !defined(STM32_I2C_I2C2_USE_GPT_TIM1) || \ - !defined(STM32_I2C_I2C2_USE_GPT_TIM2) || \ - !defined(STM32_I2C_I2C2_USE_GPT_TIM3) || \ - !defined(STM32_I2C_I2C2_USE_GPT_TIM4) || \ - !defined(STM32_I2C_I2C2_USE_GPT_TIM5) || \ - !defined(STM32_I2C_I2C2_USE_GPT_TIM8) || \ - !defined(STM32_I2C_I2C2_USE_VIRTUAL_TIMER) || \ - !defined(STM32_I2C_I2C2_USE_POLLING_WAIT) || \ +/** + * @brief I2C2 driver synchronization choice between GPT and polling. + * @note The default is polling wait. + */ +#if !defined(STM32_I2C_I2C2_USE_GPT_TIM) || \ + !defined(STM32_I2C_I2C2_USE_POLLING_WAIT) || \ defined(__DOXYGEN__) #define STM32_I2C_I2C2_USE_POLLING_WAIT TRUE #endif - - - - - - - /** * @brief I2C1 driver enable switch. * @details If set to @p TRUE the support for I2C1 is included. @@ -127,6 +107,7 @@ #define I2C_EV6_3_MASTER_REC_1BTR_MODE_SELECTED (I2C_FLG_1BTR|I2C_FLG_MASTER_RECEIVER) #define I2C_EV7_2_MASTER_REC_3BYTES_TO_PROCESS (I2C_FLG_3BTR|I2C_FLG_MASTER_RECEIVER) #define I2C_EV7_3_MASTER_REC_2BYTES_TO_PROCESS (I2C_FLG_2BTR|I2C_FLG_MASTER_RECEIVER) + /*===========================================================================*/ /* Driver data structures and types. */ /*===========================================================================*/ @@ -237,7 +218,7 @@ struct I2CDriver{ /** * @brief Config for workaround timer. */ - const GPTConfig *timer_cfg; + const GPTConfig *timer_cfg; } ;