2015-11-09 05:59 AM
Hello,
I'm trying to write an I2C application that should read/write one or more bytes as master with polling mode. I'm able to write one ore more bytes and read one byte, but when I try to read 2 bytes after a single byte read the first call goes wrong; next 2 bytes read works! I'm try to explain better:send NACK (WRONG) -> (Read value (1byte) => WRONG)
-> send NACK -> Stopsend ACK (OK) -> (Read value (1byte))
-> send NACK -> StopSet POS and ACK
Wait ADDR flag
Wait ADDR flag
Set POS
I2Cx->CR2 |= I2C_IT_ERR;
I2C_GenerateSTART(I2Cx, ENABLE);
WAIT_FOR_CONDITION_OR_RESET_ON_TIMEOUT(I2C_GetFlagStatus(I2Cx, I2C_FLAG_SB) == SET);
I2C_Send7bitAddress(I2Cx, (uint8_t)(i2c_addr <<
1
), dir);
WAIT_FOR_CONDITION_OR_RESET_ON_TIMEOUT(I2C_GetFlagStatus(I2Cx, I2C_FLAG_ADDR) == SET);
/* Clear ACK bit */
I2C_AcknowledgeConfig(I2Cx, DISABLE);
/* Disable all active IRQs around ADDR clearing and STOP programming because the EV6_3
software sequence must complete before the current byte end of transfer */
__disable_irq();
/* Clear ADDR flag */
CLEAR_REGISTER(I2Cx->SR1); //TODO:BASCETTA:TEST: Aggiunto da me
CLEAR_REGISTER(I2Cx->SR2);
/* Program the STOP */
I2C_GenerateSTOP(I2Cx, ENABLE);
/* Re-enable IRQs */
__enable_irq();
WAIT_FOR_CONDITION_OR_TIMEOUT(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BTF) == SET);
/* Disable IRQs around STOP programming and data reading because of the limitation ?*/
__disable_irq();
/* Program the STOP */
I2C_GenerateSTOP(I2Cx, ENABLE);
/* Read first data */
bytes[i] = I2C_ReceiveData(I2Cx);
i++;
/* Re-enable IRQs */
__enable_irq();
/* Read second data */
bytes[i] = I2C_ReceiveData(I2Cx);
i++;
/* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
//WAIT_FOR_CONDITION_OR_TIMEOUT((I2Cx->CR1 & I2C_CR1_STOP) == I2C_CR1_STOP);
WAIT_FOR_CONDITION_OR_TIMEOUT((I2Cx->CR1 & I2C_CR1_STOP) == 0);
/* Enable Acknowledgement to be ready for another reception */
I2C_AcknowledgeConfig(I2Cx, ENABLE);
/* Clear POS bit */
I2C_NACKPositionConfig(I2Cx, I2C_NACKPosition_Current);
Could you help me to find my mistake??
Thank you for your replies,
Regards
#i2c #master-receiving #stm32
2015-11-11 09:31 AM
After many tries this is a synthesizedversion of my solution
I2C_GenerateSTART(I2Cx, ENABLE);
WAIT_FOR_CONDITION_OR_RESET_ON_TIMEOUT(I2C_GetFlagStatus(I2Cx, I2C_FLAG_SB) == SET);
I2C_Send7bitAddress(I2Cx, (uint8_t)(i2c_addr <<
1
), dir);
WAIT_FOR_CONDITION_OR_RESET_ON_TIMEOUT(I2C_GetFlagStatus(I2Cx, I2C_FLAG_ADDR) == SET);
switch( read_bytes ) {
case 0: //DO NOTHING
CLEAR_REGISTER(I2Cx->SR1);
CLEAR_REGISTER(I2Cx->SR2);
break;
case 1:
/* Clear ACK bit */
I2C_AcknowledgeConfig(I2Cx, DISABLE);
/* Disable all active IRQs around ADDR clearing and STOP programming because the EV6_3
software sequence must complete before the current byte end of transfer */
__disable_irq();
/* Clear ADDR flag */
CLEAR_REGISTER(I2Cx->SR1);
CLEAR_REGISTER(I2Cx->SR2);
/* Program the STOP */
I2C_GenerateSTOP(I2Cx, ENABLE);
/* Re-enable IRQs */
__enable_irq();
WAIT_FOR_CONDITION_OR_TIMEOUT(I2C_GetFlagStatus(I2Cx, I2C_FLAG_RXNE) == SET);
bytes[i] = I2C_ReceiveData(I2Cx);
WAIT_FOR_CONDITION_OR_TIMEOUT((I2Cx->CR1 & I2C_CR1_STOP) == 0);
I2C_AcknowledgeConfig(I2Cx, ENABLE);
break;
case 2:
/* EV6_1: The acknowledge disable should be done just after EV6,
that is after ADDR is cleared, so disable all active IRQs around ADDR clearing and
ACK clearing */
// Vedi ''AN2824''@16
I2C_NACKPositionConfig(I2Cx, I2C_NACKPosition_Next);
__disable_irq();
/* Clear ADDR by reading SR2 register */
CLEAR_REGISTER(I2Cx->SR1);
CLEAR_REGISTER(I2Cx->SR2);
/* Clear ACK bit */
I2C_AcknowledgeConfig(I2Cx, DISABLE);
/*Re-enable IRQs */
__enable_irq();
WAIT_FOR_CONDITION_OR_TIMEOUT(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BTF) == SET);
/* Disable IRQs around STOP programming and data reading because of the limitation ?*/
__disable_irq();
/* Program the STOP */
I2C_GenerateSTOP(I2Cx, ENABLE);
/* Read first data */
bytes[i] = I2C_ReceiveData(I2Cx);
i++;
/* Re-enable IRQs */
__enable_irq();
/* Read second data */
bytes[i] = I2C_ReceiveData(I2Cx);
i++;
/* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
WAIT_FOR_CONDITION_OR_TIMEOUT((I2Cx->CR1 & I2C_CR1_STOP) == 0);
/* Enable Acknowledgement to be ready for another reception */
I2C_AcknowledgeConfig(I2Cx, ENABLE);
/* Clear POS bit */
I2C_NACKPositionConfig(I2Cx, I2C_NACKPosition_Current);
break;
default: { //Read 3+ bytes
CLEAR_REGISTER(I2Cx->SR1);
CLEAR_REGISTER(I2Cx->SR2);
uint16_t remain = size;
// Scorro tutti i byte fino a rimanere a 3
for (i = 0, remain = size; remain > 3; remain--, i++) {
WAIT_FOR_CONDITION_OR_TIMEOUT(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BTF) == SET);
bytes[i] = I2C_ReceiveData(I2Cx);
}
// Qui certamente sono rimasto con 3 byte da leggere.
WAIT_FOR_CONDITION_OR_TIMEOUT(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BTF) == SET);
/* Clear ACK bit */
I2C_AcknowledgeConfig(I2Cx, DISABLE);
/* Disable IRQs around data reading and STOP programming because of the limitation ? */
__disable_irq();
/* Read Data N-2 */
bytes[i] = I2C_ReceiveData(I2Cx);
i++;
/* Program the STOP */
I2C_GenerateSTOP(I2Cx, ENABLE);
/* Read DataN-1 */
bytes[i] = I2C_ReceiveData(I2Cx);
i++;
/* Re-enable IRQs */
__enable_irq();
/* Wait until RXNE is set (DR contains the last data) */
WAIT_FOR_CONDITION_OR_TIMEOUT(I2C_GetFlagStatus(I2Cx, I2C_FLAG_RXNE) == SET);
/* Read DataN */
bytes[i] = I2C_ReceiveData(I2Cx);
i++;
/* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
WAIT_FOR_CONDITION_OR_TIMEOUT((I2Cx->CR1 & I2C_CR1_STOP) == 0);
/* Enable Acknowledgement to be ready for another reception */
I2C_AcknowledgeConfig(I2Cx, ENABLE);
break;
}
}