STM32F1 two byte receive with subaddress
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