aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal
diff options
context:
space:
mode:
authorbarthess <barthess@35acf78f-673a-0410-8e92-d51de3d6d3f4>2011-12-30 20:45:56 +0000
committerbarthess <barthess@35acf78f-673a-0410-8e92-d51de3d6d3f4>2011-12-30 20:45:56 +0000
commit2234fd3e31d4ce6e2b3990340b52719951e65731 (patch)
tree3d8dadab8ab98a46ab2f98ed0b94d648e86ce837 /os/hal
parent08feb80580ca82cfebd77a43d14d1197ec7c4f99 (diff)
downloadChibiOS-2234fd3e31d4ce6e2b3990340b52719951e65731.tar.gz
ChibiOS-2234fd3e31d4ce6e2b3990340b52719951e65731.tar.bz2
ChibiOS-2234fd3e31d4ce6e2b3990340b52719951e65731.zip
I2C. API changes mostly done.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3692 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'os/hal')
-rw-r--r--os/hal/include/i2c.h4
-rw-r--r--os/hal/platforms/STM32/i2c_lld.c94
-rw-r--r--os/hal/platforms/STM32/i2c_lld.h105
-rw-r--r--os/hal/src/i2c.c14
4 files changed, 188 insertions, 29 deletions
diff --git a/os/hal/include/i2c.h b/os/hal/include/i2c.h
index 80668f28c..8118bd73f 100644
--- a/os/hal/include/i2c.h
+++ b/os/hal/include/i2c.h
@@ -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,
diff --git a/os/hal/platforms/STM32/i2c_lld.c b/os/hal/platforms/STM32/i2c_lld.c
index d172abebb..bfbaa410f 100644
--- a/os/hal/platforms/STM32/i2c_lld.c
+++ b/os/hal/platforms/STM32/i2c_lld.c
@@ -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){
+
+ msg_t rdymsg;
- uint32_t mode = 0;
+ 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.
*
diff --git a/os/hal/platforms/STM32/i2c_lld.h b/os/hal/platforms/STM32/i2c_lld.h
index 378b3a335..db0704066 100644
--- a/os/hal/platforms/STM32/i2c_lld.h
+++ b/os/hal/platforms/STM32/i2c_lld.h
@@ -239,6 +239,11 @@
/*===========================================================================*/
/**
+ * @brief Type representing I2C address.
+ */
+typedef uint16_t i2caddr_t;
+
+/**
* @brief I2C Driver condition flags type.
*/
typedef uint32_t i2cflags_t;
@@ -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
}
diff --git a/os/hal/src/i2c.c b/os/hal/src/i2c.c
index 598719d24..f48ca9e7e 100644
--- a/os/hal/src/i2c.c
+++ b/os/hal/src/i2c.c
@@ -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__)