I2C. Driver looks working, but sometimes hangs up. I don't know, my big project cause troubles in it, or driver cause troubles in my project.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/branches/i2c_dev@3116 35acf78f-673a-0410-8e92-d51de3d6d3f4
master
barthess 2011-07-03 18:02:55 +00:00
parent af0e40079d
commit ccb28114da
9 changed files with 179 additions and 71 deletions

View File

@ -218,6 +218,31 @@ struct I2CSlaveConfig{
_i2c_wakeup_isr(i2cp); \
}
/**
* @brief Error ISR code.
* @details This code handles the portable part of the ISR code:
* - Error callback invocation.
* - Waiting thread wakeup, if any.
* - Driver state transitions.
*
* @note This macro is meant to be used in the low level drivers
* implementation only.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define _i2c_isr_err_code(i2cp, i2cscfg) { \
(i2cp)->id_state = I2C_COMPLETE; \
if(((i2cp)->id_slave_config)->id_err_callback) { \
((i2cp)->id_slave_config)->id_err_callback(i2cp, i2cscfg); \
if((i2cp)->id_state == I2C_COMPLETE) \
(i2cp)->id_state = I2C_READY; \
} \
else \
(i2cp)->id_state = I2C_READY; \
_i2c_wakeup_isr(i2cp); \
}
/*===========================================================================*/
/* External declarations. */

View File

@ -94,20 +94,20 @@ static void i2c_serve_event_interrupt(I2CDriver *i2cp) {
}
break;
case I2C_EV8_2_MASTER_BYTE_TRANSMITTED:
/* Disable ITEVT In order to not have again a BTF IT */
dp->CR2 &= (uint16_t)~I2C_CR2_ITEVTEN;
/* if nothing to read then generate stop */
if (i2cp->rxbytes == 0){
dp->CR1 |= I2C_CR1_STOP;
/* Disable ITEVT In order to not have again a BTF IT */
dp->CR2 &= (uint16_t)~I2C_CR2_ITEVTEN;
/* Portable I2C ISR code defined in the high level driver,
* note, it is a macro.*/
_i2c_isr_code(i2cp, i2cp->id_slave_config);
}
else{
/* Disable ITEVT In order to not have again a BTF IT */
dp->CR2 &= (uint16_t)~I2C_CR2_ITEVTEN;
/* send restart and begin reading operations */
i2c_lld_master_receive(i2cp, i2cp->slave_addr, i2cp->rxbuf, i2cp->rxbytes);
chSysLockFromIsr();
i2c_lld_master_transceive(i2cp);
chSysUnlockFromIsr();
}
break;
@ -242,10 +242,10 @@ static void i2c_serve_error_interrupt(I2CDriver *i2cp) {
if(flags != I2CD_NO_ERROR) {
/* send communication end signal */
_i2c_isr_code(i2cp, i2cp->id_slave_config);
chSysLockFromIsr();
i2cAddFlagsI(i2cp, flags);
chSysUnlockFromIsr();
_i2c_isr_err_code(i2cp, i2cp->id_slave_config);
}
}
@ -539,10 +539,6 @@ void i2c_lld_master_transmit(I2CDriver *i2cp, uint16_t slave_addr,
i2cp->txbuf = txbuf;
i2cp->rxbuf = rxbuf;
/* enable ERR, EVT & BUF ITs */
i2cp->id_i2c->CR2 |= (I2C_CR2_ITERREN|I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN);
i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
if(slave_addr & 0x8000){/* 10-bit mode used */
/* add the two msb of 10-bit address to the header */
i2cp->slave_addr1 = ((slave_addr >>7) & 0x0006);
@ -568,9 +564,18 @@ void i2c_lld_master_transmit(I2CDriver *i2cp, uint16_t slave_addr,
// while((i2cp->id_i2c->CR1 & I2C_CR1_START) && timeout--)
// ;
//#endif /* I2C_USE_WAIT */
uint32_t timeout = 0xfffff;
uint32_t timeout = I2C_START_TIMEOUT;
while((i2cp->id_i2c->CR1 & I2C_CR1_START) && timeout--)
;
/* is timeout overflows? */
chDbgAssert(timeout < I2C_START_TIMEOUT,
"i2c_lld_master_transmit(), #1", "time is out");
/* enable ERR, EVT & BUF ITs */
i2cp->id_i2c->CR2 |= (I2C_CR2_ITERREN|I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN);
i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
}
@ -593,11 +598,6 @@ void i2c_lld_master_receive(I2CDriver *i2cp, uint16_t slave_addr,
i2cp->rxbytes = rxbytes;
i2cp->rxbuf = rxbuf;
/* enable ERR, EVT & BUF ITs */
i2cp->id_i2c->CR2 |= (I2C_CR2_ITERREN|I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN);
i2cp->id_i2c->CR1 |= I2C_CR1_ACK; /* acknowledge returned */
i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
if(slave_addr & 0x8000){/* 10-bit mode used */
/* add the two msb of 10-bit address to the header */
i2cp->slave_addr1 = ((slave_addr >>7) & 0x0006);
@ -633,9 +633,62 @@ void i2c_lld_master_receive(I2CDriver *i2cp, uint16_t slave_addr,
// while((i2cp->id_i2c->CR1 & I2C_CR1_START) && timeout--)
// ;
//#endif /* I2C_USE_WAIT */
uint32_t timeout = 0xfffff;
uint32_t timeout = I2C_START_TIMEOUT;
while((i2cp->id_i2c->CR1 & I2C_CR1_START) && timeout--)
;
/* is timeout overflows? */
chDbgAssert(timeout < I2C_START_TIMEOUT,
"i2c_lld_master_receive(), #1", "time is out");
/* enable ERR, EVT & BUF ITs */
i2cp->id_i2c->CR2 |= (I2C_CR2_ITERREN|I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN);
i2cp->id_i2c->CR1 |= I2C_CR1_ACK; /* acknowledge returned */
i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
}
void i2c_lld_master_transceive(I2CDriver *i2cp){
i2cp->flags = I2C_FLG_MASTER_RECEIVER;
i2cp->errors = 0;
i2cp->slave_addr1 |= 0x01;
/* Only one byte to be received */
if(i2cp->rxbytes == 1) {
i2cp->flags |= I2C_FLG_1BTR;
}
/* Only two bytes to be received */
else if(i2cp->rxbytes == 2) {
i2cp->flags |= I2C_FLG_2BTR;
i2cp->id_i2c->CR1 |= I2C_CR1_POS; /* Acknowledge Position */
}
i2cp->id_i2c->CR1 |= I2C_CR1_START; /* send start bit */
//#if !I2C_USE_WAIT
// /* Wait until the START condition is generated on the bus:
// * the START bit is cleared by hardware */
// uint32_t timeout = 0xfffff;
// while((i2cp->id_i2c->CR1 & I2C_CR1_START) && timeout--)
// ;
//#endif /* I2C_USE_WAIT */
uint32_t timeout = I2C_START_TIMEOUT;
while((i2cp->id_i2c->CR1 & I2C_CR1_START) && timeout--)
;
/* is timeout overflows? */
chDbgAssert(timeout < I2C_START_TIMEOUT,
"i2c_lld_master_receive(), #1", "time is out");
/* enable ERR, EVT & BUF ITs */
i2cp->id_i2c->CR2 |= (I2C_CR2_ITERREN|I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN);
i2cp->id_i2c->CR1 |= I2C_CR1_ACK; /* acknowledge returned */
i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
}

View File

@ -13,6 +13,7 @@
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define I2C_START_TIMEOUT 0xFFFF
/*===========================================================================*/
/* Driver pre-compile time settings. */
@ -233,6 +234,7 @@ void i2c_lld_master_transmit(I2CDriver *i2cp, uint16_t slave_addr,
uint8_t *txbuf, size_t txbytes, uint8_t *rxbuf, size_t rxbytes);
void i2c_lld_master_receive(I2CDriver *i2cp, uint16_t slave_addr,
uint8_t *rxbuf, size_t rxbytes);
void i2c_lld_master_transceive(I2CDriver *i2cp);
#ifdef __cplusplus
}

View File

@ -165,15 +165,18 @@ void i2cMasterTransmit(I2CDriver *i2cp,
/* init slave config field in driver */
i2cp->id_slave_config = i2cscfg;
//#if I2C_USE_WAIT
// i2c_lld_wait_bus_free(i2cp);
// if(i2c_lld_bus_is_busy(i2cp)) {
//#ifdef PRINTTRACE
// print("I2C Bus busy!\n");
//#endif
// return;
// };
//#endif
#if I2C_USE_WAIT
i2c_lld_wait_bus_free(i2cp);
if(i2c_lld_bus_is_busy(i2cp)) {
#ifdef PRINTTRACE
print("I2C Bus busy!\n");
return;
#else
/* the time is out */
chDbgAssert(FALSE, "i2cMasterTransmit(), #1", "time is out");
#endif
};
#endif
chSysLock();
chDbgAssert(i2cp->id_state == I2C_READY,
@ -211,15 +214,18 @@ void i2cMasterReceive(I2CDriver *i2cp,
/* init slave config field in driver */
i2cp->id_slave_config = i2cscfg;
//#if I2C_USE_WAIT
// i2c_lld_wait_bus_free(i2cp);
// if(i2c_lld_bus_is_busy(i2cp)) {
//#ifdef PRINTTRACE
// print("I2C Bus busy!\n");
//#endif
// return;
// };
//#endif
#if I2C_USE_WAIT
i2c_lld_wait_bus_free(i2cp);
if(i2c_lld_bus_is_busy(i2cp)) {
#ifdef PRINTTRACE
print("I2C Bus busy!\n");
return;
#else
/* the time is out */
chDbgAssert(FALSE, "i2cMasterReceive(), #1", "time is out");
#endif
};
#endif
chSysLock();
chDbgAssert(i2cp->id_state == I2C_READY,

View File

@ -173,6 +173,14 @@
/* I2C driver related settings. */
/*===========================================================================*/
/**
* @brief Enables synchronous APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(I2C_USE_WAIT) || defined(__DOXYGEN__)
#define I2C_USE_WAIT TRUE
#endif
/**
* @brief Enables the mutual exclusion APIs on the I2C bus.
*/

View File

@ -54,9 +54,9 @@ static msg_t I2CAccelThread(void *arg) {
i2cscfg = (I2CSlaveConfig *)msg;
/* collect measured data */
acceleration_x = i2cscfg->rxbuf[0] + (i2cscfg->rxbuf[1] << 8);
acceleration_y = i2cscfg->rxbuf[2] + (i2cscfg->rxbuf[3] << 8);
acceleration_z = i2cscfg->rxbuf[4] + (i2cscfg->rxbuf[5] << 8);
acceleration_x = accel_rx_data[0] + (accel_rx_data[1] << 8);
acceleration_y = accel_rx_data[2] + (accel_rx_data[3] << 8);
acceleration_z = accel_rx_data[4] + (accel_rx_data[5] << 8);
}
return 0;
}
@ -77,8 +77,6 @@ static void i2c_lis3_cb(I2CDriver *i2cp, const I2CSlaveConfig *i2cscfg){
static const I2CSlaveConfig lis3 = {
i2c_lis3_cb,
i2c_lis3_error_cb,
accel_rx_data,
accel_tx_data,
};
@ -106,13 +104,13 @@ int init_lis3(void){
#define RXBYTES 0 /* set to 0 because we need only transmit */
/* configure accelerometer */
lis3.txbuf[0] = ACCEL_CTRL_REG1 | AUTO_INCREMENT_BIT; /* register address */
lis3.txbuf[1] = 0b11100111;
lis3.txbuf[2] = 0b01000001;
lis3.txbuf[3] = 0b00000000;
accel_tx_data[0] = ACCEL_CTRL_REG1 | AUTO_INCREMENT_BIT; /* register address */
accel_tx_data[1] = 0b11100111;
accel_tx_data[2] = 0b01000001;
accel_tx_data[3] = 0b00000000;
/* sending */
i2cMasterTransmit(&I2CD1, &lis3, lis3_addr, TXBYTES, RXBYTES);
i2cMasterTransmit(&I2CD1, &lis3, lis3_addr, accel_tx_data, TXBYTES, accel_rx_data, RXBYTES);
chThdSleepMilliseconds(1);
#undef RXBYTES
@ -127,9 +125,9 @@ int init_lis3(void){
void request_acceleration_data(void){
#define RXBYTES 6
#define TXBYTES 1
lis3.txbuf[0] = ACCEL_OUT_DATA | AUTO_INCREMENT_BIT; // register address
accel_tx_data[0] = ACCEL_OUT_DATA | AUTO_INCREMENT_BIT; // register address
i2cAcquireBus(&I2CD1);
i2cMasterTransmit(&I2CD1, &lis3, lis3_addr, TXBYTES, RXBYTES);
i2cMasterTransmit(&I2CD1, &lis3, lis3_addr, accel_tx_data, TXBYTES, accel_rx_data, RXBYTES);
i2cReleaseBus(&I2CD1);
#undef RXBYTES
#undef TXBYTES

View File

@ -29,6 +29,23 @@
/*
* Red LEDs blinker thread, times are in milliseconds.
*/
static WORKING_AREA(BlinkWA, 128);
static msg_t Blink(void *arg) {
(void)arg;
while (TRUE) {
palClearPad(IOPORT3, GPIOC_LED);
chThdSleepMilliseconds(500);
palSetPad(IOPORT3, GPIOC_LED);
chThdSleepMilliseconds(500);
}
return 0;
}
/* Temperature polling thread */
static WORKING_AREA(PollTmp75ThreadWA, 128);
static msg_t PollTmp75Thread(void *arg) {
@ -110,6 +127,8 @@ int main(void) {
PollAccelThread,
NULL);
/* Creates the blinker thread. */
chThdCreateStatic(BlinkWA, sizeof(BlinkWA), LOWPRIO, Blink, NULL);
/* main loop that do nothing */
while (TRUE) {

View File

@ -29,11 +29,12 @@ static void i2c_max1236_error_cb(I2CDriver *i2cp, const I2CSlaveConfig *i2cscfg)
/* This callback raise up when transfer finished */
static void i2c_max1236_cb(I2CDriver *i2cp, const I2CSlaveConfig *i2cscfg){
(void)*i2cp;
(void)*i2cscfg;
/* get ADC data */
ch1 = ((i2cscfg->rxbuf[0] & 0xF) << 8) + i2cscfg->rxbuf[1];
ch2 = ((i2cscfg->rxbuf[2] & 0xF) << 8) + i2cscfg->rxbuf[3];
ch3 = ((i2cscfg->rxbuf[4] & 0xF) << 8) + i2cscfg->rxbuf[5];
ch4 = ((i2cscfg->rxbuf[6] & 0xF) << 8) + i2cscfg->rxbuf[7];
ch1 = ((max1236_rx_data[0] & 0xF) << 8) + max1236_rx_data[1];
ch2 = ((max1236_rx_data[2] & 0xF) << 8) + max1236_rx_data[3];
ch3 = ((max1236_rx_data[4] & 0xF) << 8) + max1236_rx_data[5];
ch4 = ((max1236_rx_data[6] & 0xF) << 8) + max1236_rx_data[7];
}
@ -42,8 +43,6 @@ static void i2c_max1236_cb(I2CDriver *i2cp, const I2CSlaveConfig *i2cscfg){
static const I2CSlaveConfig max1236 = {
i2c_max1236_cb,
i2c_max1236_error_cb,
max1236_rx_data,
max1236_tx_data,
};
#define max1236_addr 0b0110100
@ -56,13 +55,13 @@ void init_max1236(void){
/* this data we must send via IC to setup ADC */
#define RXBYTES 0
#define TXBYTES 2
max1236.txbuf[0] = 0b10000011; /* config register content. Consult datasheet */
max1236.txbuf[1] = 0b00000111; /* config register content. Consult datasheet */
max1236_tx_data[0] = 0b10000011; /* config register content. Consult datasheet */
max1236_tx_data[1] = 0b00000111; /* config register content. Consult datasheet */
/* transmit out 2 bytes */
i2cAcquireBus(&I2CD2);
i2cMasterTransmit(&I2CD2, &max1236, max1236_addr, TXBYTES, RXBYTES);
i2cMasterTransmit(&I2CD2, &max1236, max1236_addr, max1236_tx_data, TXBYTES, max1236_rx_data, RXBYTES);
while(I2CD2.id_state != I2C_READY){
chThdSleepMilliseconds(1);
}
@ -78,7 +77,7 @@ void read_max1236(void){
#define RXBYTES 8
i2cAcquireBus(&I2CD2);
i2cMasterReceive(&I2CD2, &max1236, max1236_addr, RXBYTES);
i2cMasterReceive(&I2CD2, &max1236, max1236_addr, max1236_rx_data, RXBYTES);
i2cReleaseBus(&I2CD2);
#undef RXBYTES
#undef TXBYTES

View File

@ -14,7 +14,6 @@
/* input buffer */
static i2cblock_t tmp75_rx_data[TMP75_RX_DEPTH];
static i2cblock_t tmp75_tx_data[TMP75_TX_DEPTH];
/* temperature value */
static int16_t temperature = 0;
@ -29,16 +28,15 @@ static void i2c_tmp75_error_cb(I2CDriver *i2cp, const I2CSlaveConfig *i2cscfg){
/* This callback raise up when transfer finished */
static void i2c_tmp75_cb(I2CDriver *i2cp, const I2CSlaveConfig *i2cscfg){
(void)*i2cp;
(void)*i2cscfg;
/* store temperature value */
temperature = (i2cscfg->rxbuf[0] << 8) + i2cscfg->rxbuf[1];
temperature = (tmp75_rx_data[0] << 8) + tmp75_rx_data[1];
}
/* Fill TMP75 config. */
static const I2CSlaveConfig tmp75 = {
i2c_tmp75_cb,
i2c_tmp75_error_cb,
tmp75_rx_data,
tmp75_tx_data,
};
#define tmp75_addr 0b1001000
@ -49,7 +47,7 @@ void request_temperature(void){
#define RXBYTES 2 /* we need to read 2 bytes */
i2cAcquireBus(&I2CD2);
i2cMasterReceive(&I2CD2, &tmp75, tmp75_addr, RXBYTES);
i2cMasterReceive(&I2CD2, &tmp75, tmp75_addr, tmp75_rx_data, RXBYTES);
i2cReleaseBus(&I2CD2);
}