# stm32f103 I2C Bare Metal Programming Question

I am trying to send a simple data from STM32f103 to another one. But I am having trouble with my code. I have been working on it since 2 weeks and I couldn't find any solution. I am using PROTEUS to simulate and KEIL to compile.

according to data sheet, after start event SB bit is set in SR1 register. To test this I placed this code:

while( !(I2C1->SR1 & I2C_SR1_SB) );


But it stucks inside the loop. Can someone help me please? Thank you for reading.

And Here is my main function.

int main(){

clock_init();

//GPIOB clock enable,AFIO enable
RCC -> APB2ENR |= RCC_APB2ENR_AFIOEN | RCC_APB2ENR_IOPBEN;
//I2C1 clock enable
RCC -> APB1ENR |= RCC_APB1ENR_I2C1EN;
//Pin B6 , B7 alternative function open drain enable, GPIOB other CRL pins output and 50mhz
GPIOB -> CRL   |= 0xff333333;

// reset the I2C1 peripheral
RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST;
RCC->APB1RSTR &=~RCC_APB1RSTR_I2C1RST;
I2C1 -> CR2 |= 0x08<<0;  //8mhz freq[5:0]
I2C1 ->CCR  &= ~(1<<15); //clear bit 15 to 0 (to have Standard Mode)
I2C1 ->CCR   |= 0x0028;
I2C1 ->TRISE |= 0x0009;

I2C1->CR1 |= I2C_CR1_PE; //peripheral enable

I2C1->CR1 |= I2C_CR1_START; //Start bit set

while( !(I2C1->SR1 & I2C_SR1_SB) );

GPIOB -> BSRR |= 0x0000ffff;

• Do you have pullups on clock and data? Have you configured one of the devices as a slave and the other as the master? – Elliot Alderson Dec 29 '19 at 21:50
• Yes, I have pullups. But actually the default value is allready slave. As far as I concerned, In case of master, start condition generation is enough to set as master – iraquois Dec 29 '19 at 22:01
• Just as a side note and of no specific help here: When I want to have two or more similar devices talking with each other and the rate isn't otherwise a killer for the idea, I usually just bit-bang it between them over two I/O pins that don't have peripherals (that I care about.) That's usually because my peripherals are a very scarce resource and I don't waste them on such things. Even in the case of dozens of MCUs running at different clock rates and out of sync even when they are, a multi-master situation is quite easily managed. Hung on an interrupt event so it runs in the background. – jonk Dec 29 '19 at 22:41
• Jonk thanks for your note. I don't exactly know the bit-bang term but as I understand ,you use another pin (like another GPIO pin with no alternate function) within the microcontroller, to test communication. Am I correct? – iraquois Dec 29 '19 at 23:21
• No, when you bit-bang a protocol, you are manually setting/reading an I/O line to either send or receive data. In other words you are bypassing the hardware version and doing everything in software. It's not often used with STM32 hardware because, with rare exceptions, these chips have a large number of peripherals embedded in them. As an example, all versions of the F103 have at minimum 1 SPI, 1 I2C, and 2 USARTS. In a pinch, the USARTS can be used for slow speed SPI quite easily. – GB - AE7OO Dec 30 '19 at 0:04

I'm seeing a couple of configuration problems.

You configure PB6/PB7 for open drain, but then you remap the I2C1 pins to PB8/PB9 and those have not been configured.

For fpclk1(which is your master clock/2) to be 25Mhz means that your running the master clock at 50Mhz, which is an oddball frequency. Are you running with an external or internal high speed clock?

Next, how did you calculate that TRISE? That value(26) seems sort of high. I would normally expect to see a range from 9 to 12, with 9 being set about 90% of the time(for SM). And the reason why 9 is common is because with a Tpclk1 of 125ns, the calculation is (1000/125) + 1 = 8 + 1 = 9.

Just one mis-configuration can cause a non-start, but it looks like you have more than one.

Side note: Unless your committed to dorking around in the guts of the chip, I would just find a good HAL library. NOT the one from ST! My personal favorite is the ChibiOS HAL which has an Apache license.

• Thanks a lot for your effort. Ok now I also actually knew there was a problem about remap configuration. Which is; if I don't remap I2C1, after enabling the peripheral PB8/PB9 goes high surprisingly. So I tought there should be a problem. Then I remap I2C1 to activate P6/P7. So as you said I didn't configure PB8/PB9 because I think after remap PB6 and PB7 are my new I2C1 pins, I might be wrong. To calculate Clock I referred tath.eu/projects/stm32/… I am using HSE for clock. CR2 = 25MHz T(high)=5000ns CCR =T(high)/T(pclk1) =0x7D – iraquois Dec 30 '19 at 0:38
• For trise [T(maxrise)/T(pclk1)]+1 = 0x1A. And thanks for the link. I will look at it. But for now I just want to learn reading datasheets and understand how to handle with registers to know how it works. – iraquois Dec 30 '19 at 0:41
• See the reference manual, B6/B7 are the default pins, B8/B9 are used after remapping. Are the B8/B9 pins the only ones that go high? Your not setting the defaults for port B to high are you? I think you should edit your question and include more information, what are your various prescales set to (i.e. AHB and APB1), are you using a crystal or an osc, and what is it's value, what is your PLL level set to. Because again, using common values(AHB/1, APB1/2) with a PLLCLK of 72Mhz, you get a fpclk1 of 36Mhz, not 25. Which chip exactly are you using? – GB - AE7OO Dec 30 '19 at 1:08
• @iraquois As for TRISE, where are you getting 5000ns from? From the reference manual: "in Sm mode, the maximum allowed SCL rise time is 1000 ns." – GB - AE7OO Dec 30 '19 at 1:12
• Ok. I will look for clock calculation. but just these code makes PB8/PB9 high unexpectedly: RCC -> APB2ENR |= RCC_APB2ENR_AFIOEN |RCC_APB2ENR_IOPBEN; RCC -> APB1ENR |= RCC_APB1ENR_I2C1EN; GPIOB -> CRL |= 0xff333333; I2C1->CR1 |= I2C_CR1_PE; – iraquois Dec 30 '19 at 1:30