aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/platforms/STM32/I2Cv2
diff options
context:
space:
mode:
authorgdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2013-04-20 09:21:59 +0000
committergdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2013-04-20 09:21:59 +0000
commit11f7370e47503d79e31c0c910b696616433c26e4 (patch)
treea8330bd466ac706d0fc36f617a37b7d2fa449f73 /os/hal/platforms/STM32/I2Cv2
parentb482a3497eaaa47074feb65df171077853be0084 (diff)
downloadChibiOS-11f7370e47503d79e31c0c910b696616433c26e4.tar.gz
ChibiOS-11f7370e47503d79e31c0c910b696616433c26e4.tar.bz2
ChibiOS-11f7370e47503d79e31c0c910b696616433c26e4.zip
Improvements to the STM32 I2Cv2 driver.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@5596 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'os/hal/platforms/STM32/I2Cv2')
-rw-r--r--os/hal/platforms/STM32/I2Cv2/i2c_lld.c41
1 files changed, 26 insertions, 15 deletions
diff --git a/os/hal/platforms/STM32/I2Cv2/i2c_lld.c b/os/hal/platforms/STM32/I2Cv2/i2c_lld.c
index 7ba62a44c..1050dc08f 100644
--- a/os/hal/platforms/STM32/I2Cv2/i2c_lld.c
+++ b/os/hal/platforms/STM32/I2Cv2/i2c_lld.c
@@ -167,25 +167,33 @@ static void i2c_lld_safety_timeout(void *p) {
static void i2c_lld_serve_interrupt(I2CDriver *i2cp, uint32_t isr) {
I2C_TypeDef *dp = i2cp->i2c;
- if (isr & I2C_ISR_TC) {
- uint8_t rxbytes = dmaStreamGetTransactionSize(i2cp->dmarx);
+ if ((isr & I2C_ISR_TC) && (i2cp->state == I2C_ACTIVE_TX)) {
+ size_t rxbytes;
+
+ /* Make sure no more 'Transfer complete' interrupts.*/
+ dp->CR1 &= ~I2C_CR1_TCIE;
+
+ rxbytes = dmaStreamGetTransactionSize(i2cp->dmarx);
if (rxbytes > 0) {
+ i2cp->state = I2C_ACTIVE_RX;
+
/* Enable RX DMA */
dmaStreamEnable(i2cp->dmarx);
dp->CR2 &= ~I2C_CR2_NBYTES;
- dp->CR2 |= (uint8_t)rxbytes << 16;
+ dp->CR2 |= rxbytes << 16;
/* Starts the read operation.*/
dp->CR2 |= I2C_CR2_RD_WRN;
dp->CR2 |= I2C_CR2_START;
}
else {
+ /* Nothing to receive - send STOP immediately.*/
dp->CR2 |= I2C_CR2_STOP;
}
}
if (isr & I2C_ISR_NACKF) {
- /* Starts a STOP sequence immediately.*/
+ /* Starts a STOP sequence immediately on error.*/
dp->CR2 |= I2C_CR2_STOP;
i2cp->errors |= I2CD_ACK_FAILURE;
@@ -519,9 +527,9 @@ void i2c_lld_start(I2CDriver *i2cp) {
dmaStreamSetPeripheral(i2cp->dmarx, &dp->RXDR);
dmaStreamSetPeripheral(i2cp->dmatx, &dp->TXDR);
- /* Reset i2c peripheral.*/
+ /* Reset i2c peripheral, the TCIE bit will be handled separately.*/
dp->CR1 = i2cp->config->cr1 | I2C_CR1_ERRIE | I2C_CR1_STOPIE |
- I2C_CR1_NACKIE | I2C_CR1_TCIE | I2C_CR1_TXDMAEN | I2C_CR1_RXDMAEN;
+ I2C_CR1_NACKIE | I2C_CR1_TXDMAEN | I2C_CR1_RXDMAEN;
/* Set slave address field (master mode) */
dp->CR2 = (i2cp->config->cr2 & ~I2C_CR2_SADD);
@@ -633,13 +641,16 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
chSysUnlock();
}
+ /* This lock will be released in high level driver.*/
+ chSysLock();
+
/* Adjust slave address (master mode) for 7-bit address mode */
if ((i2cp->config->cr2 & I2C_CR2_ADD10) == 0)
addr_cr2 = (addr_cr2 & 0x7f) << 1;
/* Set slave address field (master mode) */
dp->CR2 &= ~(I2C_CR2_SADD | I2C_CR2_NBYTES);
- dp->CR2 |= ((uint8_t)rxbytes << 16) | addr_cr2;
+ dp->CR2 |= (rxbytes << 16) | addr_cr2;
/* Initializes driver fields */
i2cp->errors = 0;
@@ -652,9 +663,6 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
/* Enable RX DMA */
dmaStreamEnable(i2cp->dmarx);
- /* This lock will be released in high level driver.*/
- chSysLock();
-
/* Atomic check on the timer in order to make sure that a timeout didn't
happen outside the critical zone.*/
if ((timeout != TIME_INFINITE) && !chVTIsArmedI(&vt))
@@ -728,13 +736,16 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
chSysUnlock();
}
+ /* This lock will be released in high level driver.*/
+ chSysLock();
+
/* Adjust slave address (master mode) for 7-bit address mode */
if ((i2cp->config->cr2 & I2C_CR2_ADD10) == 0)
addr_cr2 = (addr_cr2 & 0x7f) << 1;
/* Set slave address field (master mode) */
dp->CR2 &= ~(I2C_CR2_SADD | I2C_CR2_NBYTES);
- dp->CR2 |= ((uint8_t)txbytes << 16) | addr_cr2;
+ dp->CR2 |= (txbytes << 16) | addr_cr2;
/* Initializes driver fields */
i2cp->errors = 0;
@@ -752,15 +763,15 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
/* Enable TX DMA */
dmaStreamEnable(i2cp->dmatx);
- /* This lock will be released in high level driver.*/
- chSysLock();
-
/* Atomic check on the timer in order to make sure that a timeout didn't
happen outside the critical zone.*/
if ((timeout != TIME_INFINITE) && !chVTIsArmedI(&vt))
return RDY_TIMEOUT;
- /* Starts the operation.*/
+ /* Transmission complete interrupt enabled.*/
+ dp->CR1 |= I2C_CR1_TCIE;
+
+ /* Starts the operation as the very last thing.*/
dp->CR2 &= ~I2C_CR2_RD_WRN;
dp->CR2 |= I2C_CR2_START;