Improvements to the STM32 I2Cv2 driver.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@5596 35acf78f-673a-0410-8e92-d51de3d6d3f4
master
gdisirio 2013-04-20 09:21:59 +00:00
parent b482a3497e
commit 11f7370e47
1 changed files with 26 additions and 15 deletions

View File

@ -167,25 +167,33 @@ static void i2c_lld_safety_timeout(void *p) {
static void i2c_lld_serve_interrupt(I2CDriver *i2cp, uint32_t isr) { static void i2c_lld_serve_interrupt(I2CDriver *i2cp, uint32_t isr) {
I2C_TypeDef *dp = i2cp->i2c; I2C_TypeDef *dp = i2cp->i2c;
if (isr & I2C_ISR_TC) { if ((isr & I2C_ISR_TC) && (i2cp->state == I2C_ACTIVE_TX)) {
uint8_t rxbytes = dmaStreamGetTransactionSize(i2cp->dmarx); size_t rxbytes;
/* Make sure no more 'Transfer complete' interrupts.*/
dp->CR1 &= ~I2C_CR1_TCIE;
rxbytes = dmaStreamGetTransactionSize(i2cp->dmarx);
if (rxbytes > 0) { if (rxbytes > 0) {
i2cp->state = I2C_ACTIVE_RX;
/* Enable RX DMA */ /* Enable RX DMA */
dmaStreamEnable(i2cp->dmarx); dmaStreamEnable(i2cp->dmarx);
dp->CR2 &= ~I2C_CR2_NBYTES; dp->CR2 &= ~I2C_CR2_NBYTES;
dp->CR2 |= (uint8_t)rxbytes << 16; dp->CR2 |= rxbytes << 16;
/* Starts the read operation.*/ /* Starts the read operation.*/
dp->CR2 |= I2C_CR2_RD_WRN; dp->CR2 |= I2C_CR2_RD_WRN;
dp->CR2 |= I2C_CR2_START; dp->CR2 |= I2C_CR2_START;
} }
else { else {
/* Nothing to receive - send STOP immediately.*/
dp->CR2 |= I2C_CR2_STOP; dp->CR2 |= I2C_CR2_STOP;
} }
} }
if (isr & I2C_ISR_NACKF) { if (isr & I2C_ISR_NACKF) {
/* Starts a STOP sequence immediately.*/ /* Starts a STOP sequence immediately on error.*/
dp->CR2 |= I2C_CR2_STOP; dp->CR2 |= I2C_CR2_STOP;
i2cp->errors |= I2CD_ACK_FAILURE; i2cp->errors |= I2CD_ACK_FAILURE;
@ -519,9 +527,9 @@ void i2c_lld_start(I2CDriver *i2cp) {
dmaStreamSetPeripheral(i2cp->dmarx, &dp->RXDR); dmaStreamSetPeripheral(i2cp->dmarx, &dp->RXDR);
dmaStreamSetPeripheral(i2cp->dmatx, &dp->TXDR); 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 | 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) */ /* Set slave address field (master mode) */
dp->CR2 = (i2cp->config->cr2 & ~I2C_CR2_SADD); 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(); chSysUnlock();
} }
/* This lock will be released in high level driver.*/
chSysLock();
/* Adjust slave address (master mode) for 7-bit address mode */ /* Adjust slave address (master mode) for 7-bit address mode */
if ((i2cp->config->cr2 & I2C_CR2_ADD10) == 0) if ((i2cp->config->cr2 & I2C_CR2_ADD10) == 0)
addr_cr2 = (addr_cr2 & 0x7f) << 1; addr_cr2 = (addr_cr2 & 0x7f) << 1;
/* Set slave address field (master mode) */ /* Set slave address field (master mode) */
dp->CR2 &= ~(I2C_CR2_SADD | I2C_CR2_NBYTES); 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 */ /* Initializes driver fields */
i2cp->errors = 0; i2cp->errors = 0;
@ -652,9 +663,6 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
/* Enable RX DMA */ /* Enable RX DMA */
dmaStreamEnable(i2cp->dmarx); 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 /* Atomic check on the timer in order to make sure that a timeout didn't
happen outside the critical zone.*/ happen outside the critical zone.*/
if ((timeout != TIME_INFINITE) && !chVTIsArmedI(&vt)) if ((timeout != TIME_INFINITE) && !chVTIsArmedI(&vt))
@ -728,13 +736,16 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
chSysUnlock(); chSysUnlock();
} }
/* This lock will be released in high level driver.*/
chSysLock();
/* Adjust slave address (master mode) for 7-bit address mode */ /* Adjust slave address (master mode) for 7-bit address mode */
if ((i2cp->config->cr2 & I2C_CR2_ADD10) == 0) if ((i2cp->config->cr2 & I2C_CR2_ADD10) == 0)
addr_cr2 = (addr_cr2 & 0x7f) << 1; addr_cr2 = (addr_cr2 & 0x7f) << 1;
/* Set slave address field (master mode) */ /* Set slave address field (master mode) */
dp->CR2 &= ~(I2C_CR2_SADD | I2C_CR2_NBYTES); 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 */ /* Initializes driver fields */
i2cp->errors = 0; i2cp->errors = 0;
@ -752,15 +763,15 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
/* Enable TX DMA */ /* Enable TX DMA */
dmaStreamEnable(i2cp->dmatx); 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 /* Atomic check on the timer in order to make sure that a timeout didn't
happen outside the critical zone.*/ happen outside the critical zone.*/
if ((timeout != TIME_INFINITE) && !chVTIsArmedI(&vt)) if ((timeout != TIME_INFINITE) && !chVTIsArmedI(&vt))
return RDY_TIMEOUT; 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_RD_WRN;
dp->CR2 |= I2C_CR2_START; dp->CR2 |= I2C_CR2_START;