I2C. STOP waitings was replaced by GPT callback functions. Need much of testing.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/branches/i2c_dev@3166 35acf78f-673a-0410-8e92-d51de3d6d3f4
master
barthess 2011-07-19 20:45:57 +00:00
parent e02d3607dc
commit b569145b24
4 changed files with 188 additions and 54 deletions

View File

@ -82,7 +82,8 @@ typedef enum {
I2C_UNINIT = 0, /**< @brief Not initialized. */
I2C_STOP = 1, /**< @brief Stopped. */
I2C_READY = 2, /**< @brief Ready. */
I2C_ACTIVE = 3, /**< @brief In communication. */
I2C_ACTIVE_TRANSMIT = 3,/**< @brief Transmit in progress. */
I2C_ACTIVE_RECEIVE = 4, /**< @brief Receive in progress. */
/* Slave part. Not realized. */
I2C_SACTIVE = 10,

View File

@ -23,6 +23,11 @@
* Otherwise there is a risk of setting a second STOP, START or PEC request.
*/
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define I2C_STOP_GPT_TIMEOUT 50 /* waiting timer value */
#define I2C_START_GPT_TIMEOUT 50 /* waiting timer value */
/*===========================================================================*/
/* Driver exported variables. */
@ -48,27 +53,83 @@ static volatile uint16_t dbgSR1 = 0;
static volatile uint16_t dbgSR2 = 0;
static volatile uint16_t dbgCR1 = 0;
static volatile uint16_t dbgCR2 = 0;
static uint32_t polling_time_worst = 0;
static uint32_t polling_time_begin = 0;
static uint32_t polling_time_delta = 0;
#endif /* CH_DBG_ENABLE_ASSERTS */
/* defines for convenience purpose */
#define txBuffp (i2cp->txbuff_p)
#define rxBuffp (i2cp->rxbuff_p)
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
#if STM32_I2C_USE_POLLING_WAIT
#else
VirtualTimer i2c_waiting_vt;
/*
* GPT1 callback.
*/
static void gpt1cb(GPTDriver *gptp) {
(void)gptp;
I2CDriver *i2cp = &I2CD1;
chSysLockFromIsr();
i2cp->flags &= ~I2C_FLG_TIMER_ARMED;
switch(i2cp->id_state){
case I2C_ACTIVE_TRANSMIT:
i2c_lld_master_transmit(i2cp, i2cp->slave_addr, i2cp->txbuf, i2cp->txbytes, i2cp->rxbuf, i2cp->rxbytes);
break;
case I2C_ACTIVE_RECEIVE:
i2c_lld_master_receive(i2cp, i2cp->slave_addr, i2cp->rxbuf, i2cp->rxbytes);
break;
default:
break;
}
chSysUnlockFromIsr();
}
/*
* GPT2 callback.
*/
static void gpt2cb(GPTDriver *gptp) {
(void)gptp;
I2CDriver *i2cp = &I2CD2;
chSysLockFromIsr();
i2cp->flags &= ~I2C_FLG_TIMER_ARMED;
switch(i2cp->id_state){
case I2C_ACTIVE_TRANSMIT:
i2c_lld_master_transmit(i2cp, i2cp->slave_addr, i2cp->txbuf, i2cp->txbytes, i2cp->rxbuf, i2cp->rxbytes);
break;
case I2C_ACTIVE_RECEIVE:
i2c_lld_master_receive(i2cp, i2cp->slave_addr, i2cp->rxbuf, i2cp->rxbytes);
break;
default:
break;
}
chSysUnlockFromIsr();
}
/* GPT1 configuration. */
static const GPTConfig gpt1cfg = {
1000000, /* 1MHz timer clock.*/
gpt1cb /* Timer callback.*/
};
/* GPT2 configuration. */
static const GPTConfig gpt2cfg = {
1000000, /* 1MHz timer clock.*/
gpt2cb /* Timer callback.*/
};
#endif /* STM32_I2C_USE_POLLING_WAIT */
/* defines for convenience purpose */
#define txBuffp (i2cp->txbuff_p)
#define rxBuffp (i2cp->rxbuff_p)
/**
* @brief Function for I2C debugging purpose.
* @note Internal use only.
@ -409,14 +470,32 @@ void i2c_lld_init(void) {
RCC->APB1RSTR = 0;
i2cObjectInit(&I2CD1);
I2CD1.id_i2c = I2C1;
#endif
#if !(STM32_I2C_I2C1_USE_POLLING_WAIT)
I2CD1.timer = &GPTD1;//TODO: remove hardcode
I2CD1.timer_cfg = &gpt1cfg;//TODO: remove hardcode
#else
I2CD1.timer = NULL;
I2CD1.timer_cfg = NULL;
#endif /* !(STM32_I2C_I2C1_USE_POLLING_WAIT) */
#endif /* STM32_I2C_USE_I2C */
#if STM32_I2C_USE_I2C2
RCC->APB1RSTR = RCC_APB1RSTR_I2C2RST; /* reset I2C 2 */
RCC->APB1RSTR = 0;
i2cObjectInit(&I2CD2);
I2CD2.id_i2c = I2C2;
#endif
#if !(STM32_I2C_I2C2_USE_POLLING_WAIT)
I2CD2.timer = &GPTD2;//TODO: remove hardcode
I2CD2.timer_cfg = &gpt2cfg;//TODO: remove hardcode
#else
I2CD2.timer = NULL;
I2CD2.timer_cfg = NULL;
#endif /* !(STM32_I2C_I2C2_USE_POLLING_WAIT) */
#endif /* STM32_I2C_USE_I2C2 */
}
/**
@ -425,6 +504,9 @@ void i2c_lld_init(void) {
* @param[in] i2cp pointer to the @p I2CDriver object
*/
void i2c_lld_start(I2CDriver *i2cp) {
if (i2cp->timer != NULL || i2cp->timer_cfg != NULL)
gptStart(i2cp->timer, i2cp->timer_cfg);
if (i2cp->id_state == I2C_STOP) { /* If in stopped state then enables the I2C clock.*/
#if STM32_I2C_USE_I2C1
if (&I2CD1 == i2cp) {
@ -633,22 +715,22 @@ void i2c_lld_master_transmit(I2CDriver *i2cp, uint16_t slave_addr,
i2cp->slave_addr1 = ((slave_addr <<1) & 0x00FE); /* LSB = 0 -> write */
}
i2cp->flags = 0;
i2cp->errors = 0;
#if CH_DBG_ENABLE_ASSERTS
polling_time_begin = PWMD4.tim->CNT;
#endif
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)
;
#if CH_DBG_ENABLE_ASSERTS
polling_time_delta = PWMD4.tim->CNT - polling_time_begin;
if (polling_time_delta > polling_time_worst)
polling_time_worst = polling_time_delta;
#endif
}
i2cp->flags = 0;
i2cp->errors = 0;
i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
i2cp->id_i2c->CR1 |= I2C_CR1_START; /* send start bit */
i2cp->id_i2c->CR1 |= I2C_CR1_START;
i2cp->id_i2c->CR2 |= (I2C_CR2_ITERREN|I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN); /* enable ERR, EVT & BUF ITs */
}
@ -675,6 +757,7 @@ void i2c_lld_master_receive(I2CDriver *i2cp, uint16_t 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 */
@ -684,19 +767,22 @@ void i2c_lld_master_receive(I2CDriver *i2cp, uint16_t slave_addr,
i2cp->slave_addr1 = ((slave_addr <<1) | 0x01); /* LSB = 1 -> receive */
}
i2cp->flags = I2C_FLG_MASTER_RECEIVER;
i2cp->errors = 0;
#if CH_DBG_ENABLE_ASSERTS
polling_time_begin = PWMD4.tim->CNT;
#endif
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){
gptStartOneShot(i2cp->timer, I2C_STOP_GPT_TIMEOUT);
i2cp->flags |= I2C_FLG_TIMER_ARMED;
return;
}
else{
while(i2cp->id_i2c->CR1 & I2C_CR1_STOP)
;
#if CH_DBG_ENABLE_ASSERTS
polling_time_delta = PWMD4.tim->CNT - polling_time_begin;
if (polling_time_delta > polling_time_worst)
polling_time_worst = polling_time_delta;
#endif
}
i2cp->flags |= I2C_FLG_MASTER_RECEIVER;
i2cp->errors = 0;
i2cp->id_i2c->CR1 |= I2C_CR1_ACK; /* acknowledge returned */
i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
@ -728,11 +814,6 @@ void i2c_lld_master_transceive(I2CDriver *i2cp){
"i2c_lld_master_transceive(), #1",
"");
i2cp->flags = I2C_FLG_MASTER_RECEIVER;
i2cp->errors = 0;
i2cp->id_i2c->CR1 |= I2C_CR1_ACK; /* acknowledge returned */
i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
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 */
@ -742,6 +823,14 @@ void i2c_lld_master_transceive(I2CDriver *i2cp){
i2cp->slave_addr1 |= 0x01;
}
i2cp->flags |= I2C_FLG_MASTER_RECEIVER;
i2cp->errors = 0;
i2cp->id_i2c->CR1 |= I2C_CR1_ACK; /* acknowledge returned */
i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
if(i2cp->rxbytes == 1) { /* Only one byte to be received */
i2cp->flags |= I2C_FLG_1BTR;
}
@ -750,6 +839,9 @@ 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;

View File

@ -20,16 +20,45 @@
/*===========================================================================*/
/**
* @brief Waiting method switch.
* @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.
*/
#if !defined(STM32_I2C_USE_POLLING_WAIT) || defined(__DOXYGEN__)
#define STM32_I2C_USE_POLLING_WAIT TRUE
#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) || \
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) || \
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.
@ -89,6 +118,7 @@
#define I2C_FLG_3BTR 0x04 /* Last three received bytes to be processed */
#define I2C_FLG_MASTER_RECEIVER 0x10
#define I2C_FLG_HEADER_SENT 0x80
#define I2C_FLG_TIMER_ARMED 0x40 /* Used to check locks on the bus */
#define EV6_SUBEV_MASK (I2C_FLG_1BTR|I2C_FLG_2BTR|I2C_FLG_MASTER_RECEIVER)
#define EV7_SUBEV_MASK (I2C_FLG_2BTR|I2C_FLG_3BTR|I2C_FLG_MASTER_RECEIVER)
@ -197,6 +227,17 @@ struct I2CDriver{
* @brief Pointer to the I2Cx registers block.
*/
I2C_TypeDef *id_i2c;
/**
* @brief Timer for waiting STOP condition on the bus.
* @details Workaround for STM32 buggy I2C cell.
*/
GPTDriver *timer;
/**
* @brief Config for workaround timer.
*/
const GPTConfig *timer_cfg;
} ;

View File

@ -176,7 +176,7 @@ void i2cMasterTransmit(I2CDriver *i2cp,
chDbgAssert(i2cp->id_state == I2C_READY,
"i2cMasterTransmit(), #1", "not ready");
i2cp->id_state = I2C_ACTIVE;
i2cp->id_state = I2C_ACTIVE_TRANSMIT;
i2c_lld_master_transmit(i2cp, slave_addr, txbuf, txbytes, rxbuf, rxbytes);
_i2c_wait_s(i2cp);
}
@ -214,7 +214,7 @@ void i2cMasterReceive(I2CDriver *i2cp,
chDbgAssert(i2cp->id_state == I2C_READY,
"i2cMasterReceive(), #1", "not ready");
i2cp->id_state = I2C_ACTIVE;
i2cp->id_state = I2C_ACTIVE_RECEIVE;
i2c_lld_master_receive(i2cp, slave_addr, rxbuf, rxbytes);
_i2c_wait_s(i2cp);
}