I2C. API changes mostly done.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3692 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
barthess 2011-12-30 20:45:56 +00:00
parent 08feb80580
commit 2234fd3e31
9 changed files with 225 additions and 55 deletions

View File

@ -110,10 +110,10 @@ extern "C" {
void i2cObjectInit(I2CDriver *i2cp); void i2cObjectInit(I2CDriver *i2cp);
void i2cStart(I2CDriver *i2cp, const I2CConfig *config); void i2cStart(I2CDriver *i2cp, const I2CConfig *config);
void i2cStop(I2CDriver *i2cp); void i2cStop(I2CDriver *i2cp);
i2cflags_t i2cGetErrors(I2CDriver *i2cp); inline i2cflags_t i2cGetErrors(I2CDriver *i2cp);
msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp, msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp,
i2caddr_t addr, i2caddr_t addr,
const uint8_t *txbuf, size_t txbytes, uint8_t *txbuf, size_t txbytes,
uint8_t *rxbuf, size_t rxbytes, uint8_t *rxbuf, size_t rxbytes,
systime_t timeout); systime_t timeout);
msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp, msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp,

View File

@ -131,7 +131,8 @@ static volatile uint16_t dbgCR2 = 0;
/** /**
* @brief Return the last event value from I2C status registers. * @brief Return the last event value from I2C status registers.
* @details Important but implicit function is clearing interrupts flags. * @details Important but implicit destination of this function is
* clearing interrupts flags.
* @note Internal use only. * @note Internal use only.
* *
* @param[in] i2cp pointer to the @p I2CDriver object * @param[in] i2cp pointer to the @p I2CDriver object
@ -156,6 +157,8 @@ static uint32_t i2c_get_event(I2CDriver *i2cp){
* @brief I2C interrupts handler. * @brief I2C interrupts handler.
* *
* @param[in] i2cp pointer to the @p I2CDriver object * @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/ */
static void i2c_serve_event_interrupt(I2CDriver *i2cp) { static void i2c_serve_event_interrupt(I2CDriver *i2cp) {
I2C_TypeDef *dp = i2cp->id_i2c; I2C_TypeDef *dp = i2cp->id_i2c;
@ -179,13 +182,12 @@ static void i2c_serve_event_interrupt(I2CDriver *i2cp) {
/* catch BTF event after the end of transmission */ /* catch BTF event after the end of transmission */
if (i2cp->rxbytes > 1){ if (i2cp->rxbytes > 1){
/* start "read after write" operation */ /* start "read after write" operation */
i2c_lld_master_receive(i2cp, (i2cp->slave_addr >> 1), i2c_lld_master_transceive(i2cp);
i2cp->rxbuf, i2cp->rxbytes);
return; return;
} }
else else
i2cp->id_i2c->CR1 |= I2C_CR1_STOP; i2cp->id_i2c->CR1 |= I2C_CR1_STOP;
_i2c_isr_code(i2cp, i2cp->id_slave_config); i2c_lld_isr_code(i2cp);
break; break;
default: default:
@ -203,7 +205,7 @@ static void i2c_lld_serve_rx_end_irq(I2CDriver *i2cp){
dmaStreamDisable(i2cp->dmarx); dmaStreamDisable(i2cp->dmarx);
i2cp->id_i2c->CR1 |= I2C_CR1_STOP; i2cp->id_i2c->CR1 |= I2C_CR1_STOP;
_i2c_isr_code(i2cp, i2cp->id_slave_config); i2c_lld_isr_code(i2cp);
} }
@ -268,7 +270,7 @@ static void i2c_serve_error_interrupt(I2CDriver *i2cp) {
if(errors != I2CD_NO_ERROR) { /* send communication end signal */ if(errors != I2CD_NO_ERROR) { /* send communication end signal */
i2cp->errors |= errors; i2cp->errors |= errors;
_i2c_isr_err_code(i2cp, i2cp->id_slave_config); i2c_lld_isr_err_code(i2cp);
} }
#undef reg #undef reg
} }
@ -359,6 +361,7 @@ void i2c_lld_init(void) {
#endif /* STM32_I2C_USE_I2C3 */ #endif /* STM32_I2C_USE_I2C3 */
} }
/** /**
* @brief Configures and activates the I2C peripheral. * @brief Configures and activates the I2C peripheral.
* *
@ -495,11 +498,22 @@ void i2c_lld_reset(I2CDriver *i2cp){
* @param[in] slave_addr slave device address * @param[in] slave_addr slave device address
* @param[in] rxbuf pointer to the receive buffer * @param[in] rxbuf pointer to the receive buffer
* @param[in] rxbytes number of bytes to be received * @param[in] rxbytes number of bytes to be received
*
* @return The operation status.
* @retval RDY_OK if the function succeeded.
* @retval RDY_RESET if one or more I2C errors occurred, the errors can
* be retrieved using @p i2cGetErrors().
* @retval RDY_TIMEOUT if a timeout occurred before operation end.
*/ */
void i2c_lld_master_receive(I2CDriver *i2cp, uint8_t slave_addr, msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp,
uint8_t *rxbuf, size_t rxbytes){ uint8_t slave_addr,
uint8_t *rxbuf,
size_t rxbytes,
systime_t timeout){
uint32_t mode = 0; msg_t rdymsg;
chSysUnlock(); /* release lock from high level call */
chDbgCheck((rxbytes > 1), "i2c_lld_master_receive"); chDbgCheck((rxbytes > 1), "i2c_lld_master_receive");
@ -509,11 +523,12 @@ void i2c_lld_master_receive(I2CDriver *i2cp, uint8_t slave_addr,
i2cp->rxbuf = rxbuf; i2cp->rxbuf = rxbuf;
i2cp->errors = 0; i2cp->errors = 0;
mode = STM32_DMA_CR_DIR_P2M;
/* TODO: DMA error handling */ /* TODO: DMA error handling */
dmaStreamSetMemory0(i2cp->dmarx, rxbuf); dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes); dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
dmaStreamSetMode(i2cp->dmarx, ((i2cp->dmamode) | mode)); dmaStreamSetMode(i2cp->dmarx, ((i2cp->dmamode) | STM32_DMA_CR_DIR_P2M));
i2c_lld_wait_bus_free(i2cp);
/* wait stop bit from previous transaction*/ /* wait stop bit from previous transaction*/
while(i2cp->id_i2c->CR1 & I2C_CR1_STOP) while(i2cp->id_i2c->CR1 & I2C_CR1_STOP)
@ -521,6 +536,10 @@ void i2c_lld_master_receive(I2CDriver *i2cp, uint8_t slave_addr,
i2cp->id_i2c->CR2 |= I2C_CR2_ITERREN | I2C_CR2_ITEVTEN; i2cp->id_i2c->CR2 |= I2C_CR2_ITERREN | I2C_CR2_ITEVTEN;
i2cp->id_i2c->CR1 |= I2C_CR1_START | I2C_CR1_ACK; i2cp->id_i2c->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
i2c_lld_wait_s(i2cp, timeout, rdymsg);
return rdymsg;
} }
@ -536,12 +555,21 @@ void i2c_lld_master_receive(I2CDriver *i2cp, uint8_t slave_addr,
* @param[in] txbytes number of bytes to be transmitted * @param[in] txbytes number of bytes to be transmitted
* @param[in] rxbuf pointer to the receive buffer * @param[in] rxbuf pointer to the receive buffer
* @param[in] rxbytes number of bytes to be received * @param[in] rxbytes number of bytes to be received
*
* @return The operation status.
* @retval RDY_OK if the function succeeded.
* @retval RDY_RESET if one or more I2C errors occurred, the errors can
* be retrieved using @p i2cGetErrors().
* @retval RDY_TIMEOUT if a timeout occurred before operation end.
*/ */
void i2c_lld_master_transmit(I2CDriver *i2cp, uint8_t slave_addr, msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, uint8_t slave_addr,
uint8_t *txbuf, size_t txbytes, uint8_t *txbuf, size_t txbytes,
uint8_t *rxbuf, size_t rxbytes){ uint8_t *rxbuf, size_t rxbytes,
systime_t timeout){
uint32_t mode = 0; msg_t rdymsg;
chSysUnlock(); /* release lock from high level call */
chDbgCheck(((rxbytes == 0) || ((rxbytes > 1) && (rxbuf != NULL))), chDbgCheck(((rxbytes == 0) || ((rxbytes > 1) && (rxbuf != NULL))),
"i2cMasterTransmit"); "i2cMasterTransmit");
@ -554,20 +582,50 @@ void i2c_lld_master_transmit(I2CDriver *i2cp, uint8_t slave_addr,
i2cp->rxbuf = rxbuf; i2cp->rxbuf = rxbuf;
i2cp->errors = 0; i2cp->errors = 0;
mode = STM32_DMA_CR_DIR_M2P;
/* TODO: DMA error handling */ /* TODO: DMA error handling */
dmaStreamSetMemory0(i2cp->dmatx, txbuf); dmaStreamSetMemory0(i2cp->dmatx, txbuf);
dmaStreamSetTransactionSize(i2cp->dmatx, txbytes); dmaStreamSetTransactionSize(i2cp->dmatx, txbytes);
dmaStreamSetMode(i2cp->dmatx, ((i2cp->dmamode) | mode)); dmaStreamSetMode(i2cp->dmatx, ((i2cp->dmamode) | STM32_DMA_CR_DIR_M2P));
/* wait stop bit from previouse transaction*/ i2c_lld_wait_bus_free(i2cp);
/* wait stop bit from previous transaction*/
while(i2cp->id_i2c->CR1 & I2C_CR1_STOP) while(i2cp->id_i2c->CR1 & I2C_CR1_STOP)
; ;
i2cp->id_i2c->CR2 |= I2C_CR2_ITERREN | I2C_CR2_ITEVTEN; i2cp->id_i2c->CR2 |= I2C_CR2_ITERREN | I2C_CR2_ITEVTEN;
i2cp->id_i2c->CR1 |= I2C_CR1_START; i2cp->id_i2c->CR1 |= I2C_CR1_START;
i2c_lld_wait_s(i2cp, timeout, rdymsg);
return rdymsg;
} }
/**
* @brief Receive data via the I2C bus after writing.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
inline void i2c_lld_master_transceive(I2CDriver *i2cp){
/* There are no checks in this function because:
- all values checked earlier
- this function calls from ISR */
/* init driver fields */
i2cp->slave_addr |= 0x01; /* LSB = 1 -> receive */
/* TODO: DMA error handling */
dmaStreamSetMemory0(i2cp->dmarx, i2cp->rxbuf);
dmaStreamSetTransactionSize(i2cp->dmarx, i2cp->rxbytes);
dmaStreamSetMode(i2cp->dmarx, ((i2cp->dmamode) | STM32_DMA_CR_DIR_P2M));
i2cp->id_i2c->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
}
/** /**
* @brief Set clock speed. * @brief Set clock speed.
* *

View File

@ -238,6 +238,11 @@
/* Driver data structures and types. */ /* Driver data structures and types. */
/*===========================================================================*/ /*===========================================================================*/
/**
* @brief Type representing I2C address.
*/
typedef uint16_t i2caddr_t;
/** /**
* @brief I2C Driver condition flags type. * @brief I2C Driver condition flags type.
*/ */
@ -307,7 +312,7 @@ struct I2CDriver{
__IO i2cflags_t errors; /*!< @brief Error flags.*/ __IO i2cflags_t errors; /*!< @brief Error flags.*/
uint8_t slave_addr; /*!< @brief Current slave address without R/W bit. */ i2caddr_t slave_addr; /*!< @brief Current slave address without R/W bit. */
/*********** End of the mandatory fields. **********************************/ /*********** End of the mandatory fields. **********************************/
@ -330,6 +335,90 @@ struct I2CDriver{
while(i2cp->id_i2c->SR2 & I2C_SR2_BUSY) \ while(i2cp->id_i2c->SR2 & I2C_SR2_BUSY) \
; \ ; \
} }
/**
* @brief Waits for operation completion.
* @details This function waits for the driver to complete the current
* operation.
* @pre An operation must be running while the function is invoked.
* @note No more than one thread can wait on a I2C driver using
* this function.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_wait_s(i2cp, timeout, rdymsg) { \
chDbgAssert((i2cp)->id_thread == NULL, \
"_i2c_wait(), #1", "already waiting"); \
chSysLock(); /* this lock will be disarmed in high level part */ \
(i2cp)->id_thread = chThdSelf(); \
rdymsg = chSchGoSleepTimeoutS(THD_STATE_SUSPENDED, timeout); \
}
/**
* @brief Wakes up the waiting thread.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_wakeup_isr(i2cp) { \
if ((i2cp)->id_thread != NULL) { \
Thread *tp = (i2cp)->id_thread; \
(i2cp)->id_thread = NULL; \
chSysLockFromIsr(); \
chSchReadyI(tp); \
chSysUnlockFromIsr(); \
} \
}
/**
* @brief Wakes up the waiting thread in case of errors.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_error_wakeup_isr(i2cp) { \
if ((i2cp)->id_thread != NULL) { \
Thread *tp = (i2cp)->id_thread; \
(i2cp)->id_thread = NULL; \
chSysLockFromIsr(); \
chSchReadyI(tp); \
chSysUnlockFromIsr(); \
} \
}
/**
* @brief Common ISR code.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_isr_code(i2cp) { \
i2c_lld_wakeup_isr(i2cp); \
}
/**
* @brief Error ISR code.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_isr_err_code(i2cp) { \
i2c_lld_error_wakeup_isr(i2cp); \
}
/**
* @brief Get errors from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_errors(i2cp) ((i2cp)->errors)
/*===========================================================================*/ /*===========================================================================*/
/* External declarations. */ /* External declarations. */
@ -358,10 +447,16 @@ void i2c_lld_set_clock(I2CDriver *i2cp);
void i2c_lld_set_opmode(I2CDriver *i2cp); void i2c_lld_set_opmode(I2CDriver *i2cp);
void i2c_lld_start(I2CDriver *i2cp); void i2c_lld_start(I2CDriver *i2cp);
void i2c_lld_stop(I2CDriver *i2cp); void i2c_lld_stop(I2CDriver *i2cp);
void i2c_lld_master_transmit(I2CDriver *i2cp, uint8_t slave_addr, msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, uint8_t slave_addr,
uint8_t *txbuf, size_t txbytes, uint8_t *rxbuf, size_t rxbytes); uint8_t *txbuf, size_t txbytes,
void i2c_lld_master_receive(I2CDriver *i2cp, uint8_t slave_addr, uint8_t *rxbuf, size_t rxbytes,
uint8_t *rxbuf, size_t rxbytes); systime_t timeout);
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp,
uint8_t slave_addr,
uint8_t *rxbuf,
size_t rxbytes,
systime_t timeout);
void i2c_lld_master_transceive(I2CDriver *i2cp);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -179,7 +179,7 @@ i2cflags_t i2cGetErrors(I2CDriver *i2cp) {
*/ */
msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp, msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp,
i2caddr_t addr, i2caddr_t addr,
const uint8_t *txbuf, uint8_t *txbuf,
size_t txbytes, size_t txbytes,
uint8_t *rxbuf, uint8_t *rxbuf,
size_t rxbytes, size_t rxbytes,
@ -202,7 +202,10 @@ msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp,
rxbuf, rxbytes, timeout); rxbuf, rxbytes, timeout);
i2cp->id_state = I2C_READY; i2cp->id_state = I2C_READY;
chSysUnlock(); chSysUnlock();
return rdymsg; if (i2cGetErrors(i2cp) != I2CD_NO_ERROR)
return RDY_RESET;
else
return rdymsg;
} }
/** /**
@ -228,7 +231,7 @@ msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp,
* @api * @api
*/ */
msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp, msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp,
i2caddr_t slave_addr, i2caddr_t addr,
uint8_t *rxbuf, uint8_t *rxbuf,
size_t rxbytes, size_t rxbytes,
systime_t timeout){ systime_t timeout){
@ -249,7 +252,10 @@ msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp,
rdymsg = i2c_lld_master_receive_timeout(i2cp, addr, rxbuf, rxbytes, timeout); rdymsg = i2c_lld_master_receive_timeout(i2cp, addr, rxbuf, rxbytes, timeout);
i2cp->id_state = I2C_READY; i2cp->id_state = I2C_READY;
chSysUnlock(); chSysUnlock();
return rdymsg; if (i2cGetErrors(i2cp) != I2CD_NO_ERROR)
return RDY_RESET;
else
return rdymsg;
} }
#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) #if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)

View File

@ -82,9 +82,10 @@ CSRC = $(PORTSRC) \
$(CHIBIOS)/os/various/syscalls.c \ $(CHIBIOS)/os/various/syscalls.c \
main.c \ main.c \
i2c_pns.c \ i2c_pns.c \
lis3.c \
tmp75.c \ tmp75.c \
fake.c fake.c \
#lis3.c

View File

@ -42,14 +42,17 @@ static i2cflags_t errors = 0;
/* This is main function. */ /* This is main function. */
void request_fake(void){ void request_fake(void){
msg_t status = RDY_OK;
systime_t tmo = MS2ST(4);
i2cAcquireBus(&I2CD1); i2cAcquireBus(&I2CD1);
i2cMasterReceive(&I2CD1, addr, rx_data, 2, &errors, TIME_INFINITE); status = i2cMasterReceiveTimeout(&I2CD1, addr, rx_data, 2, tmo);
i2cReleaseBus(&I2CD1); i2cReleaseBus(&I2CD1);
if (errors == I2CD_ACK_FAILURE){ if (status != RDY_OK){
__NOP(); errors = i2cGetErrors(&I2CD1);
} }
else{ else{
temperature = (rx_data[0] << 8) + rx_data[1]; temperature = (rx_data[0] << 8) + rx_data[1];
} }

View File

@ -45,7 +45,7 @@ void I2CInit_pns(void){
/* startups. Pauses added just to be safe */ /* startups. Pauses added just to be safe */
chThdSleepMilliseconds(100); chThdSleepMilliseconds(100);
init_lis3(); // init_lis3();
} }

View File

@ -32,8 +32,9 @@
/* /*
* Red LEDs blinker thread, times are in milliseconds. * Red LEDs blinker thread, times are in milliseconds.
*/ */
static WORKING_AREA(BlinkWA, 128); static WORKING_AREA(BlinkWA, 64);
static msg_t Blink(void *arg) { static msg_t Blink(void *arg) {
chRegSetThreadName("Blink");
(void)arg; (void)arg;
while (TRUE) { while (TRUE) {
palClearPad(IOPORT3, GPIOC_LED); palClearPad(IOPORT3, GPIOC_LED);
@ -47,21 +48,21 @@ static msg_t Blink(void *arg) {
/* /*
* Accelerometer thread * Accelerometer thread
*/ */
static WORKING_AREA(PollAccelThreadWA, 128); //static WORKING_AREA(PollAccelThreadWA, 256);
static msg_t PollAccelThread(void *arg) { //static msg_t PollAccelThread(void *arg) {
chRegSetThreadName("PollAccel"); // chRegSetThreadName("PollAccel");
(void)arg; // (void)arg;
while (TRUE) { // while (TRUE) {
// chThdSleepMilliseconds(rand() & 31); //// chThdSleepMilliseconds(rand() & 31);
chThdSleepMilliseconds(32); // chThdSleepMilliseconds(32);
request_acceleration_data(); // request_acceleration_data();
} // }
return 0; // return 0;
} //}
/* Temperature polling thread */ /* Temperature polling thread */
static WORKING_AREA(PollTmp75ThreadWA, 128); static WORKING_AREA(PollTmp75ThreadWA, 256);
static msg_t PollTmp75Thread(void *arg) { static msg_t PollTmp75Thread(void *arg) {
chRegSetThreadName("PollTmp75"); chRegSetThreadName("PollTmp75");
(void)arg; (void)arg;
@ -76,7 +77,7 @@ static msg_t PollTmp75Thread(void *arg) {
/* Temperature polling thread */ /* Temperature polling thread */
static WORKING_AREA(PollFakeThreadWA, 128); static WORKING_AREA(PollFakeThreadWA, 256);
static msg_t PollFakeThread(void *arg) { static msg_t PollFakeThread(void *arg) {
chRegSetThreadName("PollFake"); chRegSetThreadName("PollFake");
(void)arg; (void)arg;
@ -102,11 +103,11 @@ int main(void) {
I2CInit_pns(); I2CInit_pns();
/* Create accelerometer thread */ /* Create accelerometer thread */
chThdCreateStatic(PollAccelThreadWA, // chThdCreateStatic(PollAccelThreadWA,
sizeof(PollAccelThreadWA), // sizeof(PollAccelThreadWA),
NORMALPRIO, // NORMALPRIO,
PollAccelThread, // PollAccelThread,
NULL); // NULL);
/* Create temperature thread */ /* Create temperature thread */
chThdCreateStatic(PollTmp75ThreadWA, chThdCreateStatic(PollTmp75ThreadWA,

View File

@ -45,11 +45,17 @@ static i2cflags_t errors = 0;
/* This is main function. */ /* This is main function. */
void request_temperature(void){ void request_temperature(void){
int16_t t_int = 0, t_frac = 0; int16_t t_int = 0, t_frac = 0;
msg_t status = RDY_OK;
systime_t tmo = MS2ST(4);
i2cAcquireBus(&I2CD1); i2cAcquireBus(&I2CD1);
i2cMasterReceive(&I2CD1, tmp75_addr, tmp75_rx_data, 2, &errors, TIME_INFINITE); status = i2cMasterReceiveTimeout(&I2CD1, tmp75_addr, tmp75_rx_data, 2, tmo);
i2cReleaseBus(&I2CD1); i2cReleaseBus(&I2CD1);
if (status != RDY_OK){
errors = i2cGetErrors(&I2CD1);
}
t_int = tmp75_rx_data[0] * 100; t_int = tmp75_rx_data[0] * 100;
t_frac = (tmp75_rx_data[1] * 100) >> 8; t_frac = (tmp75_rx_data[1] * 100) >> 8;
temperature = t_int + t_frac; temperature = t_int + t_frac;