2019-02-05 5:01 AM
I have a problem with the operation of the I2C interface on stm32f103. Hangs waiting for ADDR bit(while(!(I2C1->SR1 & I2C_SR1_ADDR))) in the master transmit mode.
In the Internet, many people have this problem, but is no solution. Who was the problem and who solved it?
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;			//enable AF
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;			/enable clock port b
AFIO->MAPR &= ~AFIO_MAPR_I2C1_REMAP;
 
GPIOB->CRL |= GPIO_CRL_CNF6;				//Alternate function open drain
GPIOB->CRL |= GPIO_CRL_CNF7;				//Alternate function open drain
 
GPIOB->CRL |= GPIO_CRL_MODE6;				// Output mode, max speed 50 MHz.
GPIOB->CRL |= GPIO_CRL_MODE7;				// Output mode, max speed 50 MHz.
 
/*********** Init I2C *******************************/
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;		//Enable clock I2C1
I2C1->CR1 |= I2C_CR1_SWRST;                                  //reset i2c
I2C1->CR1 &= ~I2C_CR1_SWRST;
I2C1->CR1 &= ~I2C_CR1_PE;
 
I2C1->CR2 |= 36;							//set FREQ = APB1= 36MHz
 
I2C1->CCR |= 180;
I2C1->TRISE = 0x00;
I2C1->TRISE |= 37;						//TRISE = 36MHz APB1 bus + 1
I2C1->CR1 |= I2C_CR1_PE;					// I2C_CR1 register to enable the peripheral
 
/*********************send data***************************/
    //Start
I2C1->CR1 |= I2C_CR1_START;
while(!(I2C1->SR1 & I2C_SR1_SB)){};           ///Here is normal
(void) I2C1->SR1;
 
        //send addres unit
I2C1->DR = adr_unit;
while(!(I2C1->SR1 & I2C_SR1_ADDR)){};    //// Here is loop!
(void) I2C1->SR1;
(void) I2C1->SR2;
 
        //send addres reg
I2C1->DR = reg_addr;
while(!(I2C1->SR1 & I2C_SR1_TXE)){};
 
        //write data
I2C1->DR = data;
while(!(I2C1->SR1 & I2C_SR1_BTF)){};
I2C1->CR1 |= I2C_CR1_STOP;
					
				
			
			
				
			
			
				Solved! Go to Solution.
2019-02-05 5:26 AM
It means the master isn't receiving the ACK bit for some reason. Check the connectivity between master and slave, check the pull-ups, check the slave address. Use a logic analyzer or an oscilloscope to check whether the ACK is coming from the slave.
In real-world application you would want to add timeout mechanisms to all those infinite loops so your firmware doesn't hang indefinitely.
2019-02-05 5:26 AM
It means the master isn't receiving the ACK bit for some reason. Check the connectivity between master and slave, check the pull-ups, check the slave address. Use a logic analyzer or an oscilloscope to check whether the ACK is coming from the slave.
In real-world application you would want to add timeout mechanisms to all those infinite loops so your firmware doesn't hang indefinitely.
2019-02-05 7:49 AM
Thank you very much friend, the address of the device is 7 bits, so need shift to the left by 1 bit to the address was correct.:thumbs_up:
In real-world application you would want to add timeout mechanisms to all those infinite loops so your firmware doesn't hang indefinitely.
Agreed. I seen many implementations, which one do you use?
2019-02-05 11:44 PM
> I seen many implementations, which one do you use?
One based on SysTick's counter (I assume it is configured to tick every millisecond). I make my polling functions return int 0 for good result, negative values for bad results (like timeout), and positive values when it must return something useful (like number of characters read). Part of your code in such a function would become something like this (... for omitted parts):
#define I2C_TIMEOUT_MS (1000U)
...
...
...
int i2c_read_sensor(void)
{
    uint32_t timeout;
    ...
    ...
    I2C1->CR1 |= I2C_CR1_START;
    timeout = I2C_TIMEOUT_MS;
    while (!(I2C1->SR1 & I2C_SR1_SB)) {
        if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) {
            if (timeout-- == 0) {
                ERR("I2C_SR1_SB timeout\n");
                return -4;
            }
        }
    }
    (void) I2C1->SR1;
    ...
    ...
    I2C1->DR = adr_unit;
    timeout = I2C_TIMEOUT_MS;
    while (!(I2C1->SR1 & I2C_SR1_ADDR)) {
        if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) {
            if (timeout-- == 0) {
                ERR("I2C_SR1_ADDR timeout\n");
                return -5;
            }
        }
    }
    (void) I2C1->SR1;
    (void) I2C1->SR2;
    ...
    ...
    return 0;
}