diff options
Diffstat (limited to 'os/hal')
-rw-r--r-- | os/hal/dox/i2c.dox | 20 | ||||
-rw-r--r-- | os/hal/include/i2c.h | 11 | ||||
-rw-r--r-- | os/hal/platforms/STM32/i2c_lld.c | 154 | ||||
-rw-r--r-- | os/hal/platforms/STM32/i2c_lld.h | 43 |
4 files changed, 115 insertions, 113 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 = { - 1000000, /* 1MHz timer clock.*/ - gpt1cb /* Timer callback.*/ -}; - -/* GPT2 configuration. */ -static const GPTConfig gpt2cfg = { +/* I2C2 GPT configuration. */ +static const GPTConfig i2c2gptcfg = { 1000000, /* 1MHz timer clock.*/ - gpt2cb /* Timer callback.*/ + i2c2gptcb /* 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,12 +704,27 @@ 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) { + /* "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){ + gptStartOneShot(i2cp->timer, I2C_STOP_GPT_TIMEOUT); + i2cp->flags |= I2C_FLG_TIMER_ARMED; + return; + } + else{ + while(i2cp->id_i2c->CR1 & I2C_CR1_STOP) + ; + } + + /* 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 */ @@ -715,18 +734,7 @@ void i2c_lld_master_transmit(I2CDriver *i2cp, uint16_t slave_addr, i2cp->slave_addr1 = ((slave_addr <<1) & 0x00FE); /* LSB = 0 -> write */ } - 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){ - gptStartOneShot(i2cp->timer, I2C_STOP_GPT_TIMEOUT); - i2cp->flags |= I2C_FLG_TIMER_ARMED; - return; - } - else{ - while(i2cp->id_i2c->CR1 & I2C_CR1_STOP) - ; - } - + /* 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; } ; |