Skip to main content
Visitor II
August 13, 2024
Question

STM32F103 holding I2C

  • August 13, 2024
  • 3 replies
  • 1352 views

I am trying to use the F103 as a I2C master but it is holding the I2C pins low, there is nothing else on the bus 5k1 pullups, when I hold the device in reset the lines are 5V. 

Because the lines are low, SB is never being set, so the first while statement of the transmit function is blocking. 

Any suggestions as to what could be causing this? I have no ideas left. 

 

/* USER CODE BEGIN */ 

 

 

 

//----------------------------------------------------------------------
//                                      I2C init
//----------------------------------------------------------------------
 

 

void ll_i2c1_init(void){
 
RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST;
RCC->APB1RSTR &= ~RCC_APB1RSTR_I2C1RST;
 
I2C1->CR1 &= ~I2C_CR1_PE;
 
I2C1->CR1 |= I2C_CR1_SWRST;
I2C1->CR1 &= ~I2C_CR1_SWRST;
 
ll_clocks_enable_i2c1(); 
 
ll_gpio_remap_i2c1();
 
I2C1->CR2 |= 16;
I2C1->CCR |= 0x50;
I2C1->TRISE = 0x10;
 
I2C1->OAR1 |= (0x14 << 1); 
 
I2C1->CR1 |= I2C_CR1_PE; //Peripheral Enable
 
}
 
//----------------------------------------------------------------------
//                                      Transmit
//----------------------------------------------------------------------
 
 
void ll_i2c1_transmit(uint8_t address, uint8_t message){
 
uint16_t status_register_1_read = 0;
 
address = (address << 1);
address &= ~(0x01); // clear LSB 0 = write
 
I2C1->CR1 |= (I2C_CR1_START | I2C_CR1_ACK);
 
while (!(I2C2->SR1 & I2C_SR1_SB)); // wait for start condition to be generated
 
I2C1->DR = address; //address is just sent on the line as data, after a start bit MSB first
//I2C1->CR1 |= (I2C_CR1_START);
 
while (!(I2C2->SR1 & I2C_SR1_ADDR));
 
status_register_1_read = I2C1->SR1; // these two reads clear addr
status_register_1_read = I2C1->SR2;
 
while (!(I2C2->SR1 & I2C_SR1_TXE));
 
I2C1->DR = message;
//I2C1->CR1 |= (I2C_CR1_START);
 
while (!(I2C2->SR1 & I2C_SR1_BTF));
 
I2C1->CR1 |= (I2C_CR1_STOP);
 
}
 
//----------------------------------------------------------------------
//                             Call of Transmit
//----------------------------------------------------------------------
 
ll_i2c1_transmit(0x55, 0x33);
 
/* USER CODE END */ 
 
 
 
/* USER CODE BEGIN 2 */
//----------------------------------------------------------------------
//                                      Clocks
//----------------------------------------------------------------------
 
//---------- Port for the LED and I2C --------------------------
 
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
 
RCC->APB2ENR |= (RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN);
 
//----------------------------------------------------------------------------------------
 
void ll_clocks_enable_i2c1(void){
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
}
 
 
//----------------------------------------------------------------------
//                                      GPIO
//----------------------------------------------------------------------
 
 
//I2C1 Alternate functions
 
GPIOB->CRH &= ~GPIO_CRH_CNF8;
GPIOB->CRH |= (GPIO_CRH_CNF8); //set 10 of the config bits
GPIOB->CRH |= GPIO_CRH_MODE8; // 50MHz output
 
GPIOB->CRH &= ~GPIO_CRH_CNF9;
GPIOB->CRH |= (GPIO_CRH_CNF9); //set 10 of the config bits
GPIOB->CRH |= GPIO_CRH_MODE9; // 50MHz output

 //----------------------------------------------------------------------------------------------------

void ll_gpio_remap_i2c1(void){
 
AFIO->MAPR |= AFIO_MAPR_I2C1_REMAP;
 
}

 /* USER CODE END 2*/  

    This topic has been closed for replies.

    3 replies

    Technical Moderator
    August 15, 2024

    Hello @Ryan-SmartIR ,

    Have a look at the Errata sheet related to the STM32F103 devices and check if you have the same conditions as described in the I2C limitations.

    Visitor II
    August 21, 2024
    Never figured out what was going wrong with the above, copy and pasted the code into i2c2, that didn't work, wrote it from scratch without any while delays and it worked fine, added the whiles back in and it it still works fine. Here is the working code. 
     
    P.s. I didn't meet any of the conditions for the issues outlined in the errata
     
    void ll_i2c2_init(void){
     
    ll_clocks_enable_i2c2();
     
    ll_gpio_remap_i2c2();
     
    I2C2->CR1 |= 16; // bottom 5 bits are frequency 16MHz
     
    I2C2->CCR = 50;
    I2C2->TRISE = 9;
     
    I2C2->CR1 |= I2C_CR1_PE;
     
    }
     
    void ll_i2c2_transmit(uint8_t address, uint8_t message){
     
    uint16_t register_reader = 0;
     
    address <<= 1;
    address &= ~0x01; //7 bit address, LSB 0 = write
     
    I2C2->CR1 &= ~I2C_CR1_STOP;
     
    register_reader = I2C2->SR1;
    register_reader = I2C2->SR2;
     
    I2C2->CR1 |= I2C_CR1_START;
     
    while(!(I2C2->SR1 & I2C_SR1_SB));
     
    register_reader = I2C2->SR1;
    register_reader = I2C2->SR2;
     
    I2C2->DR = address;
     
     
    while(!(I2C2->SR1 & I2C_SR1_ADDR));
    //The ADDR bit is only set after the ACK is received
     
    register_reader = I2C2->SR1;
    register_reader = I2C2->SR2;
     
    //I2C2->CR1 |= I2C_CR1_START;
     
    I2C2->DR = message;
     
    //I2C2->CR1 |= I2C_CR1_START;
     
    I2C2->CR1 |= I2C_CR1_STOP;
     
    register_reader = I2C2->SR1;
    register_reader = I2C2->SR2;
     
    }
     
     
    uint16_t ll_i2c2_read(uint8_t address){
     
    uint16_t register_reader = 0;
    uint16_t received_data = 0;
     
    address <<= 1;
    address |= 0x01; //7 bit address, LSB 1 = read
     
    I2C2->CR1 &= ~I2C_CR1_STOP;
     
    register_reader = I2C2->SR1;
    register_reader = I2C2->SR2;
     
    I2C2->CR1 |= (I2C_CR1_START | I2C_CR1_ACK);
     
    while(!(I2C2->SR1 & I2C_SR1_SB));
     
    register_reader = I2C2->SR1;
    register_reader = I2C2->SR2;
     
    I2C2->DR = address;
     
     
    while(!(I2C2->SR1 & I2C_SR1_ADDR));
    //The ADDR bit is only set after the ACK is received
     
    register_reader = I2C2->SR1;
    register_reader = I2C2->SR2;
     
     
    //I2C2->CR1 |= I2C_CR1_START;
    while(!(I2C2->SR1 & I2C_SR1_RXNE));
     
    received_data = I2C2->DR;
    received_data <<= 8;
     
    while(!(I2C2->SR1 & I2C_SR1_RXNE));
     
    received_data |= I2C2->DR;
     
    //I2C2->CR1 |= I2C_CR1_START;
     
    I2C2->CR1 |= I2C_CR1_STOP;
     
    register_reader = I2C2->SR1;
    register_reader = I2C2->SR2;
     
    I2C2->CR1 &= ~I2C_CR1_ACK;
     
    return received_data;
    }
    Visitor II
    August 21, 2024

    Also note, from my original post, the while loop conditions are checking the I2C2 registers instead of the I2C1 registers so that would never work. I did fix this after posting and it still didn't work.