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-d51de3d6d3f4master
parent
e02d3607dc
commit
b569145b24
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
} ;
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue