I2C API proposal.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3684 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
gdisirio 2011-12-29 18:03:49 +00:00
parent 40a709f42f
commit b30ba31603
2 changed files with 99 additions and 152 deletions

View File

@ -51,7 +51,7 @@
#define I2CD_OVERRUN 0x08 /**< @brief Overrun/Underrun. */ #define I2CD_OVERRUN 0x08 /**< @brief Overrun/Underrun. */
#define I2CD_PEC_ERROR 0x10 /**< @brief PEC Error in #define I2CD_PEC_ERROR 0x10 /**< @brief PEC Error in
reception. */ reception. */
#define I2CD_TIMEOUT 0x20 /**< @brief Timeout Error. */ #define I2CD_TIMEOUT 0x20 /**< @brief Hardware timeout. */
#define I2CD_SMB_ALERT 0x40 /**< @brief SMBus Alert. */ #define I2CD_SMB_ALERT 0x40 /**< @brief SMBus Alert. */
/** @} */ /** @} */
@ -91,85 +91,10 @@ typedef enum {
#include "i2c_lld.h" #include "i2c_lld.h"
/*===========================================================================*/ /*===========================================================================*/
/* Driver macros. */ /* Driver macros. */
/*===========================================================================*/ /*===========================================================================*/
/**
* @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_wait_s(i2cp, timeout, rdymsg) { \
chDbgAssert((i2cp)->id_thread == NULL, \
"_i2c_wait(), #1", "already waiting"); \
chSysLock(); \
(i2cp)->id_thread = chThdSelf(); \
rdymsg = chSchGoSleepTimeoutS(THD_STATE_SUSPENDED, timeout); \
chSysUnlock(); \
}
/**
* @brief Wakes up the waiting thread.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define _i2c_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.
* @details This code handles the portable part of the ISR code:
* - Waiting thread wakeup.
* - 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_code(i2cp, i2cscfg) { \
(i2cp)->id_state = I2C_READY; \
_i2c_wakeup_isr(i2cp); \
}
/**
* @brief Error ISR code.
* @details This code handles the portable part of the ISR code:
* - Waiting thread wakeup.
* - 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_READY; \
_i2c_wakeup_isr(i2cp); \
}
/*===========================================================================*/ /*===========================================================================*/
/* External declarations. */ /* External declarations. */
/*===========================================================================*/ /*===========================================================================*/
@ -181,16 +106,16 @@ 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);
msg_t i2cMasterTransmit(I2CDriver *i2cp, i2cflags_t i2cGetErrors(I2CDriver *i2cp);
uint8_t slave_addr, msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp,
uint8_t *txbuf, size_t txbytes, i2caddr_t addr,
const uint8_t *txbuf, size_t txbytes,
uint8_t *rxbuf, size_t rxbytes, uint8_t *rxbuf, size_t rxbytes,
i2cflags_t *errors, systime_t timeout); systime_t timeout);
msg_t i2cMasterReceive(I2CDriver *i2cp, msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp,
uint8_t slave_addr, i2caddr_t addr,
uint8_t *rxbuf, size_t rxbytes, uint8_t *rxbuf, size_t rxbytes,
i2cflags_t *errors, systime_t timeout); systime_t timeout);
#if I2C_USE_MUTUAL_EXCLUSION #if I2C_USE_MUTUAL_EXCLUSION
void i2cAcquireBus(I2CDriver *i2cp); void i2cAcquireBus(I2CDriver *i2cp);
void i2cReleaseBus(I2CDriver *i2cp); void i2cReleaseBus(I2CDriver *i2cp);

View File

@ -132,6 +132,21 @@ void i2cStop(I2CDriver *i2cp) {
chSysUnlock(); chSysUnlock();
} }
/**
* @brief Returns the errors mask associated to the previous operation.
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @return The errors mask.
*
* @api
*/
i2cflags_t i2cGetErrors(I2CDriver *i2cp) {
chDbgCheck(i2cp != NULL, "i2cGetErrors");
return i2c_lld_get_errors(i2cp);
}
/** /**
* @brief Sends data via the I2C bus. * @brief Sends data via the I2C bus.
* @details Function designed to realize "read-through-write" transfer * @details Function designed to realize "read-through-write" transfer
@ -139,47 +154,49 @@ void i2cStop(I2CDriver *i2cp) {
* than set @b rxbytes field to 0. * than set @b rxbytes field to 0.
* *
* @param[in] i2cp pointer to the @p I2CDriver object * @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] slave_addr Slave device address (7 bits) without R/W bit * @param[in] addr slave device address (7 bits) without R/W bit
* @param[in] txbuf pointer to transmit buffer * @param[in] txbuf pointer to transmit buffer
* @param[in] txbytes number of bytes to be transmitted * @param[in] txbytes number of bytes to be transmitted
* @param[in] rxbuf pointer to receive buffer * @param[in] rxbuf pointer to receive buffer
* @param[in] rxbytes number of bytes to be received, set it to 0 if * @param[in] rxbytes number of bytes to be received, set it to 0 if
* you want transmit only * you want transmit only
* @param[in] errors pointer to variable to store error code, zero means * @param[in] timeout the number of ticks before the operation timeouts,
* no error. * the following special values are allowed:
* @param[in] timeout operation timeout * - @a TIME_INFINITE no timeout.
* .
* *
* @return timeout status * @return The number of received bytes or an exit code.
* @retval RDY_OK if timeout not reached * @retval RDY_RESET if one or more I2C errors occurred, the errors can
* @retval RDY_TIMEOUT if a timeout occurs * be retrieved using @p i2cGetErrors().
* @retval RDY_TIMEOUT if a timeout occurred before operation end.
*
* @api
*/ */
msg_t i2cMasterTransmit(I2CDriver *i2cp, msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp,
uint8_t slave_addr, i2caddr_t addr,
uint8_t *txbuf, const uint8_t *txbuf,
size_t txbytes, size_t txbytes,
uint8_t *rxbuf, uint8_t *rxbuf,
size_t rxbytes, size_t rxbytes,
i2cflags_t *errors,
systime_t timeout) { systime_t timeout) {
msg_t rdymsg; msg_t rdymsg;
chDbgCheck((i2cp != NULL) && (slave_addr != 0) && chDbgCheck((i2cp != NULL) && (addr != 0) &&
(txbytes > 0) && (txbuf != NULL) && (txbytes > 0) && (txbuf != NULL) &&
((rxbytes == 0) || ((rxbytes > 0) && (rxbuf != NULL))) && ((rxbytes == 0) || ((rxbytes > 0) && (rxbuf != NULL))) &&
(timeout > TIME_IMMEDIATE) && (errors != NULL), (timeout != TIME_IMMEDIATE),
"i2cMasterTransmit"); "i2cMasterTransmitTimeout");
i2c_lld_wait_bus_free(i2cp);
i2cp->errors = I2CD_NO_ERROR; /* clear error flags from previous run */
chDbgAssert(i2cp->id_state == I2C_READY, chDbgAssert(i2cp->id_state == I2C_READY,
"i2cMasterTransmit(), #1", "not ready"); "i2cMasterTransmitTimeout(), #1", "not ready");
chSysLock();
i2cp->errors = I2CD_NO_ERROR;
i2cp->id_state = I2C_ACTIVE_TRANSMIT; i2cp->id_state = I2C_ACTIVE_TRANSMIT;
i2c_lld_master_transmit(i2cp, slave_addr, txbuf, txbytes, rxbuf, rxbytes); rdymsg = i2c_lld_master_transmit_timeout(i2cp, addr, txbuf, txbytes,
_i2c_wait_s(i2cp, timeout, rdymsg); rxbuf, rxbytes, timeout);
i2cp->id_state = I2C_READY;
*errors = i2cp->errors; chSysUnlock();
return rdymsg; return rdymsg;
} }
@ -187,56 +204,60 @@ msg_t i2cMasterTransmit(I2CDriver *i2cp,
* @brief Receives data from the I2C bus. * @brief Receives data from the I2C bus.
* *
* @param[in] i2cp pointer to the @p I2CDriver object * @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] slave_addr slave device address (7 bits) without R/W bit * @param[in] addr slave device address (7 bits) without R/W bit
* @param[in] rxbytes number of bytes to be received * @param[in] rxbytes number of bytes to be received
* @param[in] rxbuf pointer to receive buffer * @param[in] rxbuf pointer to receive buffer
* @param[in] errors pointer to variable to store error code, zero means * @param[in] errors pointer to variable to store error code, zero means
* no error. * no error.
* @param[in] timeout operation timeout * @param[in] timeout the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_INFINITE no timeout.
* .
* *
* @return timeout status * @return The number of received bytes or an exit code.
* @retval RDY_OK if timeout not reached * @retval RDY_OK if the function succeeded.
* @retval RDY_TIMEOUT if a timeout occurs * @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.
*
* @api
*/ */
msg_t i2cMasterReceive(I2CDriver *i2cp, msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp,
uint8_t slave_addr, i2caddr_t slave_addr,
uint8_t *rxbuf, uint8_t *rxbuf,
size_t rxbytes, size_t rxbytes,
i2cflags_t *errors,
systime_t timeout){ systime_t timeout){
msg_t rdymsg; msg_t rdymsg;
chDbgCheck((i2cp != NULL) && (slave_addr != 0) && chDbgCheck((i2cp != NULL) && (addr != 0) &&
(rxbytes > 0) && (rxbuf != NULL) && (rxbytes > 0) && (rxbuf != NULL) &&
(timeout > TIME_IMMEDIATE) && (errors != NULL), (timeout != TIME_IMMEDIATE),
"i2cMasterReceive"); "i2cMasterReceiveTimeout");
i2c_lld_wait_bus_free(i2cp);
i2cp->errors = I2CD_NO_ERROR; /* clear error flags from previous run */
chDbgAssert(i2cp->id_state == I2C_READY, chDbgAssert(i2cp->id_state == I2C_READY,
"i2cMasterReceive(), #1", "not ready"); "i2cMasterReceive(), #1", "not ready");
chSysLock();
i2cp->errors = I2CD_NO_ERROR;
i2cp->id_state = I2C_ACTIVE_RECEIVE; i2cp->id_state = I2C_ACTIVE_RECEIVE;
i2c_lld_master_receive(i2cp, slave_addr, rxbuf, rxbytes); rdymsg = i2c_lld_master_receive_timeout(i2cp, addr, rxbuf, rxbytes, timeout);
_i2c_wait_s(i2cp, timeout, rdymsg); i2cp->id_state = I2C_READY;
chSysUnlock();
*errors = i2cp->errors;
return rdymsg; return rdymsg;
} }
#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) #if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
/** /**
* @brief Gains exclusive access to the I2C bus. * @brief Gains exclusive access to the I2C bus.
* @details This function tries to gain ownership to the I2C bus, if the bus * @details This function tries to gain ownership to the SPI bus, if the bus
* is already being used then the invoking thread is queued. * is already being used then the invoking thread is queued.
* @pre In order to use this function the option @p I2C_USE_MUTUAL_EXCLUSION
* must be enabled.
* *
* @param[in] i2cp pointer to the @p I2CDriver object * @param[in] i2cp pointer to the @p I2CDriver object
* *
* @note This function is only available when the @p I2C_USE_MUTUAL_EXCLUSION * @api
* option is set to @p TRUE.
*/ */
void i2cAcquireBus(I2CDriver *i2cp) { void i2cAcquireBus(I2CDriver *i2cp) {
@ -251,11 +272,12 @@ void i2cAcquireBus(I2CDriver *i2cp) {
/** /**
* @brief Releases exclusive access to the I2C bus. * @brief Releases exclusive access to the I2C bus.
* @pre In order to use this function the option @p I2C_USE_MUTUAL_EXCLUSION
* must be enabled.
* *
* @param[in] i2cp pointer to the @p I2CDriver object * @param[in] i2cp pointer to the @p I2CDriver object
* *
* @note This function is only available when the @p I2C_USE_MUTUAL_EXCLUSION * @api
* option is set to @p TRUE.
*/ */
void i2cReleaseBus(I2CDriver *i2cp) { void i2cReleaseBus(I2CDriver *i2cp) {