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 i2cStart(I2CDriver *i2cp, const I2CConfig *config);
void i2cStop(I2CDriver *i2cp);
i2cflags_t i2cGetErrors(I2CDriver *i2cp);
inline i2cflags_t i2cGetErrors(I2CDriver *i2cp);
msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp,
i2caddr_t addr,
const uint8_t *txbuf, size_t txbytes,
uint8_t *txbuf, size_t txbytes,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout);
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.
* @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.
*
* @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.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
static void i2c_serve_event_interrupt(I2CDriver *i2cp) {
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 */
if (i2cp->rxbytes > 1){
/* start "read after write" operation */
i2c_lld_master_receive(i2cp, (i2cp->slave_addr >> 1),
i2cp->rxbuf, i2cp->rxbytes);
i2c_lld_master_transceive(i2cp);
return;
}
else
i2cp->id_i2c->CR1 |= I2C_CR1_STOP;
_i2c_isr_code(i2cp, i2cp->id_slave_config);
i2c_lld_isr_code(i2cp);
break;
default:
@ -203,7 +205,7 @@ static void i2c_lld_serve_rx_end_irq(I2CDriver *i2cp){
dmaStreamDisable(i2cp->dmarx);
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 */
i2cp->errors |= errors;
_i2c_isr_err_code(i2cp, i2cp->id_slave_config);
i2c_lld_isr_err_code(i2cp);
}
#undef reg
}
@ -359,6 +361,7 @@ void i2c_lld_init(void) {
#endif /* STM32_I2C_USE_I2C3 */
}
/**
* @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] rxbuf pointer to the receive buffer
* @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,
uint8_t *rxbuf, size_t rxbytes){
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp,
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");
@ -509,11 +523,12 @@ void i2c_lld_master_receive(I2CDriver *i2cp, uint8_t slave_addr,
i2cp->rxbuf = rxbuf;
i2cp->errors = 0;
mode = STM32_DMA_CR_DIR_P2M;
/* TODO: DMA error handling */
dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
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*/
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->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] rxbuf pointer to the receive buffer
* @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,
uint8_t *txbuf, size_t txbytes,
uint8_t *rxbuf, size_t rxbytes){
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,
systime_t timeout){
uint32_t mode = 0;
msg_t rdymsg;
chSysUnlock(); /* release lock from high level call */
chDbgCheck(((rxbytes == 0) || ((rxbytes > 1) && (rxbuf != NULL))),
"i2cMasterTransmit");
@ -554,20 +582,50 @@ void i2c_lld_master_transmit(I2CDriver *i2cp, uint8_t slave_addr,
i2cp->rxbuf = rxbuf;
i2cp->errors = 0;
mode = STM32_DMA_CR_DIR_M2P;
/* TODO: DMA error handling */
dmaStreamSetMemory0(i2cp->dmatx, txbuf);
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)
;
i2cp->id_i2c->CR2 |= I2C_CR2_ITERREN | I2C_CR2_ITEVTEN;
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.
*

View File

@ -238,6 +238,11 @@
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type representing I2C address.
*/
typedef uint16_t i2caddr_t;
/**
* @brief I2C Driver condition flags type.
*/
@ -307,7 +312,7 @@ struct I2CDriver{
__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. **********************************/
@ -330,6 +335,90 @@ struct I2CDriver{
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. */
@ -358,10 +447,16 @@ void i2c_lld_set_clock(I2CDriver *i2cp);
void i2c_lld_set_opmode(I2CDriver *i2cp);
void i2c_lld_start(I2CDriver *i2cp);
void i2c_lld_stop(I2CDriver *i2cp);
void i2c_lld_master_transmit(I2CDriver *i2cp, uint8_t slave_addr,
uint8_t *txbuf, size_t txbytes, uint8_t *rxbuf, size_t rxbytes);
void i2c_lld_master_receive(I2CDriver *i2cp, uint8_t slave_addr,
uint8_t *rxbuf, size_t rxbytes);
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,
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
}

View File

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

View File

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

View File

@ -42,14 +42,17 @@ static i2cflags_t errors = 0;
/* This is main function. */
void request_fake(void){
msg_t status = RDY_OK;
systime_t tmo = MS2ST(4);
i2cAcquireBus(&I2CD1);
i2cMasterReceive(&I2CD1, addr, rx_data, 2, &errors, TIME_INFINITE);
status = i2cMasterReceiveTimeout(&I2CD1, addr, rx_data, 2, tmo);
i2cReleaseBus(&I2CD1);
if (errors == I2CD_ACK_FAILURE){
__NOP();
if (status != RDY_OK){
errors = i2cGetErrors(&I2CD1);
}
else{
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 */
chThdSleepMilliseconds(100);
init_lis3();
// init_lis3();
}

View File

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

View File

@ -45,11 +45,17 @@ static i2cflags_t errors = 0;
/* This is main function. */
void request_temperature(void){
int16_t t_int = 0, t_frac = 0;
msg_t status = RDY_OK;
systime_t tmo = MS2ST(4);
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);
if (status != RDY_OK){
errors = i2cGetErrors(&I2CD1);
}
t_int = tmp75_rx_data[0] * 100;
t_frac = (tmp75_rx_data[1] * 100) >> 8;
temperature = t_int + t_frac;