2016-12-17 07:48 AM
I have an STM32F103 that I would like to use for I2C communication. I have been using the 'Optimized examples for I2C' with the STM32F1, but I have modified it to send a subaddress before performing the read. With my modifications to the optimized examples, I can only receive one byte. Trying to receive two or more bytes always results in a NACK on the first byte, instead of the second.
I can't find anything in the documentation describing this behavior, or if there is a difference in receiving two bytes with or without a subaddress. I'm probably just not looking in the right places.
I hate how I can't just post a couple lines of microcontroller code to fully describe my problem, but I don't know what else to do. Here are the relevant lines of my function.
uint32_t timeout = I2C_DEFAULT_TIMEOUT;
uint16_t temp;
// send subaddress if we need to
if(reg_ != 0xFF)
{
/* Send START condition */
I2Cx_->CR1 |= I2C_CR1_START;
/* Wait until SB flag is set: EV5 */
while ((I2Cx_->SR1 & I2C_SR1_SB) != I2C_SR1_SB)
{
if (timeout-- == 0)
return hardware_failure();
}
/* Send slave address */
I2C_Send7bitAddress(I2Cx_, addr_, I2C_Direction_Transmitter);
timeout = I2C_DEFAULT_TIMEOUT;
/* Wait until ADDR is set: EV6 */
while ((I2Cx_->SR1 & I2C_SR1_ADDR) != I2C_SR1_ADDR)
{
if (timeout-- == 0)
return hardware_failure();
}
/* Clear ADDR flag by reading SR2 register */
temp = I2Cx_->SR2;
// Send subaddress
I2Cx_->DR = reg_;
// Make sure byte transfer finished
while ((I2Cx_->SR1 & I2C_SR1_BTF) != I2C_SR1_BTF);
}
if (len_ == 2)
{
/* Set POS bit */
I2Cx_->CR1 |= I2C_CR1_POS;
uint32_t timeout = I2C_DEFAULT_TIMEOUT;
/* Send START condition */
I2Cx_->CR1 |= I2C_CR1_START;
/* Wait until SB flag is set: EV5 */
while ((I2Cx_->SR1 & I2C_SR1_SB) != I2C_SR1_SB)
{
if (timeout-- == 0)
return hardware_failure();
}
/* Send slave address */
/* Set the address bit0 for read */
I2C_Send7bitAddress(I2Cx_, addr_, I2C_Direction_Receiver);
/* Wait until ADDR is set: EV6 */
timeout = I2C_DEFAULT_TIMEOUT;
while ((I2Cx_->SR1 & I2C_SR1_ADDR) != I2C_SR1_ADDR)
{
if (timeout-- == 0)
return hardware_failure();
}
/* 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 */
__disable_irq();
/* Clear ADDR by reading SR2 register */
temp = I2Cx_->SR2;
/* Clear ACK */
I2C_AcknowledgeConfig(I2Cx_, DISABLE);
I2Cx_->CR1 &= ~I2C_CR1_ACK;
/*Re-enable IRQs */
__enable_irq();
/* Wait until BTF is set */
timeout = I2C_DEFAULT_TIMEOUT;
while (!(I2Cx_->SR1 & I2C_SR1_BTF))
{
if(timeout-- == 0)
{
return hardware_failure();
}
}
/* Disable IRQs around STOP programming and data reading because of the limitation ?*/
__disable_irq();
/* Program the STOP */
I2C_GenerateSTOP(I2Cx_, ENABLE);
/* Read first data */
data_buffer_[index_] = I2Cx_->DR;
/* Re-enable IRQs */
__enable_irq();
/**/
index_++;
/* Read second data */
data_buffer_[index_] = I2Cx_->DR;
/* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
timeout = I2C_DEFAULT_TIMEOUT;
while (!(I2Cx_->CR1 & I2C_CR1_STOP))
{
if(timeout-- == 0)
return hardware_failure();
}
/* Enable Acknowledgement to be ready for another reception */
I2C_AcknowledgeConfig(I2Cx_, ENABLE);
/* Clear POS bit */
I2Cx_->CR1 &= (uint16_t) ~I2C_CR1_POS;
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
#i2c #polling #subaddress #stm32
Solved! Go to Solution.
2016-12-18 04:18 AM
I don't see where do you set I2Cx_CR1.ACK before reading.
JW
2016-12-17 08:12 AM
If trying to address an I2C EEPROM which memory content requires 2 byte subaddress, as an alternative until the issue is solved could be to use bit banging by GPIO. Search for 'I2C Checklist' on the community to grab a pseudo code inside the tip and tricks.
As long as speed is not critical (which would then favour SPI or QSPI memories), it will do the interim job.
Hope this helps in the short term,
2016-12-17 02:31 PM
Thanks Seb, I'll look into the I2C Checklist.
Unfortunately, GPIO bit-banging is definitely going to be too slow for my purposes. I only need a single byte subaddress, and I'm certain that it is possible to do this with the peripheral, since it's a very common paradigm to have a subaddress on I2C reads.
2016-12-18 04:18 AM
I don't see where do you set I2Cx_CR1.ACK before reading.
JW
2016-12-19 09:59 AM
Haha! Thanks JW.
I was trusting the optimized examples a bit too much. It turns out, the optimized I2C examples are set up to perform byte transfer via a NACK-NACK-ACK. Every I2C sensor I've ever used is a ACK-ACK-NACK and I didn't realize that the examples were backwards on purpose.