Author Topic: I2C on STM32F4 [SOLVED]  (Read 6547 times)

0 Members and 1 Guest are viewing this topic.

Offline DELTA67Topic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: fr
I2C on STM32F4 [SOLVED]
« on: August 20, 2023, 03:31:54 pm »
Hi all,
For many days I'm struggling to get I2C working on an STM32F401CE (emulated in PROTEUS).
USART works great, but I2C not yet!  I'm using default values, HSI 16MHz as source clock and no prescalers.
I need your help please.
My code to initialize I2C1 and send a start condition is:

Code: [Select]
void i2c1_init(){
// Enable clocks to the peripherals
RCC -> APB1ENR |= 1<<21; // Enable I2C1 clock
RCC -> AHB1ENR |= 1<<1; // Enable GPIOB clock

// set pins B6=SCL and B7=SDA to Alternate Function, Pull-up enabled, Open-Drain and high speed
GPIOB -> MODER  = 2<<2*7 | 2<<2*6; //MODER7/6[1:0] = 10 => Alternate function mode
GPIOB -> OTYPER = 1<<1*7| 1<<1*6; // B6/7 = 1 => Output open-drain
GPIOB -> OSPEEDR = 3<<2*7 | 3<<2*6;  // OSPEEDR7/6[1:0] = 11 => High speed
GPIOB -> PUPDR = 1<<2*7 | 1<<2*6; // PUPDR7/6[1:0] = 01 => Pull-up
GPIOB -> AFRL = (4 << 4*7) | (4 << 4*6); //AFRL7/6[3:0] = 0100 => AF4  (I2C1)

// initialization steps:
I2C1 -> CR1 |= 1<<15; // SWRST (bit15) = 1 => Enable the software reset
I2C1 -> CR1 &= ~(1<<15); // then immediately resetting the SWRST bit.
I2C1 -> CR2 = 16; // FREQ[5:0] (Bits 5:0) = 16 => Peripheral clock frequency = 16 MHz
// other bits  = 0 => Interrupts and DMA disabled
//I2C1 -> OAR1 = 0x30; // Own address in slave mode only
// set SCL clock: Thigh = Tlow = CCR * TPCLK1 (here TPCLK1 = 1/16 MHz)
// For 100kHz, Thigh = Tlow = 5uS => CCR = (5/0.0625) = 80
I2C1 -> CCR = 80; // F/S (Bit 15) = 0 => standard master mode
// CCR[11:0] (Bits 11:0) =  80 => SCL clock = 100kHz
I2C1 -> TRISE |= 11;                 // TRISE[5:0] (Bits 5:0) = 9 => Maximum rise time in standard mode
I2C1 -> CR1 |= 1; // PE (bit0) = 1 => Enable the peripheral
}

//  send a start condition and slave address
void I2C1_Start(char address){
uint16_t reg;

//I2C1->CR1 |= (1<<10);  // Enable the ACK
I2C1 -> CR1 |= 1<<8; // START (Bit 8) = 1 => start generation (and enter master mode)
while(!(I2C1 -> SR1 & 1<<0)); // wait until SB (Bit 0) = 1 => Start condition generated

reg = I2C1 -> SR1; // MUST read SR1 reg first
// then send the address to clear SB bit
I2C1 -> DR = (address << 1) | 0x00; // write address in DR reg
while(!(I2C1 -> SR1 & 1<<1)); // wait until ADDR (Bit 1) = 1 => End of address transmission
// ADDR bit is cleared by software reading SR1 followed by reading SR2
reg = I2C1 -> SR1;
reg = I2C1 -> SR2;
//In datasheet p499: TxE is not set during address phase ?!
//while(!(I2C1 -> SR1 & 1<<7)); // wait until TxE (Bit 7) = 1 => Data register empty
}


void main(){
i2c1_init();
I2C1_Start(0x60);
for (;;) ;
}

Full project is attached.
PLEASE help

EDIT:
To build the code, decomment line33 in  "periph.h".

EDIT2:
SOLVED.
The I2C module for STM32F401CE in PROTEUS is buggy!!
I tested the one for ATMEGA328 it works great.
Anyway, PROTEUS is really a  marvellous  tool.
« Last Edit: August 23, 2023, 08:31:44 am by DELTA67 »
 

Offline eutectique

  • Frequent Contributor
  • **
  • Posts: 477
  • Country: be
Re: I2C on STM32F4
« Reply #1 on: August 20, 2023, 05:43:30 pm »
Code: [Select]
    GPIOB -> MODER  = 2<<2*7 | 2<<2*6;
    GPIOB -> OTYPER = 1<<1*7| 1<<1*6;
    GPIOB -> OSPEEDR = 3<<2*7 | 3<<2*6;
    GPIOB -> PUPDR = 1<<2*7 | 1<<2*6;
    GPIOB -> AFRL = (4 << 4*7) | (4 << 4*6);

Is there any good reason not to use C macros?
Is there any good reason not to use STM header files?
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6539
  • Country: es
Re: I2C on STM32F4
« Reply #2 on: August 20, 2023, 06:40:56 pm »
OMG, at least use the cmsis headers and macros!
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline DELTA67Topic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: fr
Re: I2C on STM32F4
« Reply #3 on: August 20, 2023, 08:38:34 pm »
What's wrong with this style of programming?
I LOVE bare metal C and assembler. I don't like ready to use libraries. I find more plaisir  when working at the bit level. I do this just for fun not for work.
I've followed the datasheet step by step and I don't know what I'm missing!
If some one can help, I'll be very grateful.
Thanks
« Last Edit: August 20, 2023, 08:40:26 pm by DELTA67 »
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6539
  • Country: es
Re: I2C on STM32F4
« Reply #4 on: August 20, 2023, 09:20:14 pm »
What's wrong ? Because human DO make mistakes.
Just an example:
Are you sure 1<<15 is SWRST? Or maybe 1<<14. Or 1<<13?

Or wait 2 months and open this project again.
The comments are just saying "Trust me bro", if not working you'll have a very hard time checking everything out.

And now it doesn't work you ask for help (Which is ok!).

But.. Maybe your code is wrong... or one of these bits are mistaken ?
So now you have 40 hardcoded bits everywhere.
That's not asking for help, that's almost an audit, requiring anyone to open the RM and check every reg bit to make sure everything is ok...
A total waste of time.
But using the CMSIS headers it's much, much better:

I2C1 -> CR1 |= I2C1_CR1_SWRST;

I2C1_CR1_SWRST instantly says it all:
- It's for I2C1
- It's for CR1
- It's the SWRST bit

So any mistake can be easlily detected:
I2C1 -> CR1 |= I2C2_CR1_SWRST;
I2C1 -> CR1 |= I2C1_CR1_POTATO;
I2C1 -> CR2 |= I2C1_CR1_SWRST;

I'm just saying, make your/our life easier!
CMSIS headers are made by ARM itself, it isn't any kind of library, you'll still be coding at baremetal level.
« Last Edit: August 20, 2023, 09:27:42 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 
The following users thanked this post: luudee

Offline DELTA67Topic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: fr
Re: I2C on STM32F4
« Reply #5 on: August 20, 2023, 09:59:21 pm »
Thanks DavidAlpha for your responses.
I'm sorry, I appologize for abusing your precious time.
Apart of enabling GPIOB clock and configure SDA and SCL lines, enabling I2C1 clock in RCC_APB1ENR reg and enabling the peripheral by setting the PE bit in I2C_CR1 reg is there any other thing to enable?

« Last Edit: August 20, 2023, 10:07:39 pm by DELTA67 »
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6539
  • Country: es
Re: I2C on STM32F4
« Reply #6 on: August 20, 2023, 10:55:33 pm »
No need  to reinvent the wheel.
Simply search "stm32 F4 baremetal i2c":
https://github.com/fcayci/stm32f4-bare-metal/blob/master/projects/i2c/i2c.c
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline DELTA67Topic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: fr
Re: I2C on STM32F4
« Reply #7 on: August 21, 2023, 04:55:48 am »
Thanks again DavidAlpha for your help.
I've already tested the "INITIALIZATION PART" of that code ( and many other projects), with no success!
I debugged the code in PROTEUS, all the registers have the expected values but the start condition is not generated.
« Last Edit: August 21, 2023, 08:18:27 am by DELTA67 »
 

Online Berni

  • Super Contributor
  • ***
  • Posts: 5106
  • Country: si
Re: I2C on STM32F4
« Reply #8 on: August 21, 2023, 05:23:34 am »
The MCU simulators often don't perfectly emulate all the peripherals. It is possible the code works just fine on a real STM32
 

Offline DELTA67Topic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: fr
Re: I2C on STM32F4
« Reply #9 on: August 21, 2023, 08:27:00 am »
Thanks Berni
As I've said, I tested only the "INITIALIZATION PART" of that code not all the project, perhaps I need to do some thing relative to CLOCKs, I2C module is fed with APB1 clock.
In principle PROTEUS simulates the I2C peripheral very well. I tested the USART and it works.
I'm using default values, HSI 16MHz as source clock and no prescalers.
I've an STM32F411 based board but no logic analyzer, How to test using a basic oscillo?
Perhaps I need to send some data continuosly and see the activity on the I2C lines?
« Last Edit: August 21, 2023, 08:34:42 am by DELTA67 »
 

Offline wek

  • Frequent Contributor
  • **
  • Posts: 560
  • Country: sk
Re: I2C on STM32F4
« Reply #10 on: August 21, 2023, 10:24:21 am »
> I've an STM32F411 based board but no logic analyzer, How to test using a basic oscillo?

On a two-channel oscilloscope, you would see both SCL and SDA, and you need nothing more.

JW
 

Online Berni

  • Super Contributor
  • ***
  • Posts: 5106
  • Country: si
Re: I2C on STM32F4
« Reply #11 on: August 21, 2023, 10:43:34 am »
Yeah clocks have to be configured of course. On most STM32s all the peripherals start with a disabled bus clock to save power. Failing to turn on clocks is easily sported by looking at the whole peripherals register values(be it using the peripheral view in CubeIDE, or just placing a struct of the peripheral registers into the Watch window). You tend to see a lot of 0s as the values and writing to a register results in no change. Easy fix takes one line to turn the clock on.

Best way to actually setup the clocks speeds is using the CubeMX tool, not only does it let you adjust the potentially very complicated clock paths in a nice GUI, but it also calculates the MHz at each stage and warns you if any clocks are too high or too low to work correctly. You can let it generate the code for you and then just copy paste out the parts of the code you want to use.

Oscilloscope is the perfect tool for checking it. Tho it does need to be a digital scope, the analog scope won't show it in a usable way. If you don't have a decent digital scope i would highly suggest you go pick up a USB logic analyzer.  Here is a nice cheep Chinese one that i use http://www.qdkingst.com/en I have plenty of nice scopes, but for analyzing communications it is more convenient to use.(Practically infinite sample memory, easier to navigate with a mouse, supports all sorts of protocol decoders in parallel...)
 

Online langwadt

  • Super Contributor
  • ***
  • Posts: 4993
  • Country: dk
Re: I2C on STM32F4
« Reply #12 on: August 21, 2023, 11:14:02 am »
Yeah clocks have to be configured of course. On most STM32s all the peripherals start with a disabled bus clock to save power. Failing to turn on clocks is easily sported by looking at the whole peripherals register values(be it using the peripheral view in CubeIDE, or just placing a struct of the peripheral registers into the Watch window). You tend to see a lot of 0s as the values and writing to a register results in no change. Easy fix takes one line to turn the clock on.

Best way to actually setup the clocks speeds is using the CubeMX tool, not only does it let you adjust the potentially very complicated clock paths in a nice GUI, but it also calculates the MHz at each stage and warns you if any clocks are too high or too low to work correctly. You can let it generate the code for you and then just copy paste out the parts of the code you want to use.

Oscilloscope is the perfect tool for checking it. Tho it does need to be a digital scope, the analog scope won't show it in a usable way. If you don't have a decent digital scope i would highly suggest you go pick up a USB logic analyzer.  Here is a nice cheep Chinese one that i use http://www.qdkingst.com/en I have plenty of nice scopes, but for analyzing communications it is more convenient to use.(Practically infinite sample memory, easier to navigate with a mouse, supports all sorts of protocol decoders in parallel...)

for I2C something like https://www.ebay.com/itm/134692438303 and pulseview is plenty

 

Offline DELTA67Topic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: fr
Re: I2C on STM32F4
« Reply #13 on: August 21, 2023, 01:43:31 pm »
Thanks Berni, wek and langwadt.
When debugging I found that the program stucks at the line:
Code: [Select]
while(!(I2C1 -> SR1 & 1<<0)); // wait until SB (Bit 0) = 1 => Start condition generated
The bit "start" in I2C_CR1 is set as expected  and also  the bit MSL in I2C_SR2 which means that the peripheral is in master mode.
But the bit SB still cleared and the start condition is not generated on the bus .
« Last Edit: August 21, 2023, 04:04:56 pm by DELTA67 »
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6539
  • Country: es
Re: I2C on STM32F4
« Reply #14 on: August 21, 2023, 01:47:37 pm »
That's exactly a start condition:


You must write the slave address next!

Simply:
- Search a working example.
- Simulate it.
- It works? Try your own.
- It doesn't? Not rare, proteus MCU models have plenty of bugs.
« Last Edit: August 21, 2023, 01:51:25 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline DELTA67Topic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: fr
Re: I2C on STM32F4
« Reply #15 on: August 21, 2023, 02:19:16 pm »
I said that the start condition is NOT generated as expected despite the bit MSL is set !!
And the SB bit stays cleared so the program stucks waiting for it to goes high.
Have you a simple working example for F401CE or F411CE please?
 

Offline wek

  • Frequent Contributor
  • **
  • Posts: 560
  • Country: sk
Re: I2C on STM32F4
« Reply #16 on: August 21, 2023, 02:38:18 pm »
Quote
But the bit SB still cleared and the start condition is not generated on the bus (SDA goes low while SCL stays high).
To me, this also sounds as that you've observed what is in the brackets, and interpreted it as "not start condition".

So, what did you exactly observe?

If you set both pins as GPIO Out in MODER (other things unchanged), can you generate the start condition - or for that matter, any pulses combination - on the bus "manually"?

JW
« Last Edit: August 21, 2023, 02:40:08 pm by wek »
 

Offline wek

  • Frequent Contributor
  • **
  • Posts: 560
  • Country: sk
Re: I2C on STM32F4
« Reply #17 on: August 21, 2023, 03:00:56 pm »
Code: [Select]
d:\tmp\tmp>make
d:/PROGRA~1/ARMTools/launchpad.net_gcc-arm-embedded_5.4/bin/arm-none-eabi-as -g crt0.s -o crt0.o
d:/PROGRA~1/ARMTools/launchpad.net_gcc-arm-embedded_5.4/bin/arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -Os    -c -o i2c.o i2c.c
i2c.c: In function 'i2c1_init':
i2c.c:19:2: error: 'I2C1' undeclared (first use in this function)
  I2C1 -> CR1 |= 1<<15;   // SWRST (bit15) = 1 => Enable the software reset
  ^
i2c.c:19:2: note: each undeclared identifier is reported only once for each function it appears in
i2c.c: In function 'I2C1_Start':
i2c.c:39:2: error: 'I2C1' undeclared (first use in this function)
  I2C1 -> CR1 |= 1<<8;   // START (Bit 8) = 1 => start generation (and enter master mode)
  ^
make: *** [i2c.o] Error 1

d:\tmp\tmp>
 

Offline DELTA67Topic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: fr
Re: I2C on STM32F4
« Reply #18 on: August 21, 2023, 04:08:36 pm »
Quote

So, what did you exactly observe?

No thing!
Sorry, what  I've quoted it's the expected result.

You've a problem compiling the code?
I appologize, I2C1 definition is commented (line33) in  the attached "periph.h" !!!
decomment it please.
« Last Edit: August 21, 2023, 04:16:05 pm by DELTA67 »
 

Offline DELTA67Topic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: fr
Re: I2C on STM32F4
« Reply #19 on: August 21, 2023, 04:20:00 pm »
The corrected file with binary is attached bellow.
 

Offline wek

  • Frequent Contributor
  • **
  • Posts: 560
  • Country: sk
Re: I2C on STM32F4
« Reply #20 on: August 21, 2023, 06:22:13 pm »
>> So, what did you exactly observe?
> No thing!

What does that mean? SDA and SCL are surely at some levels.

I happen to have a hardware on my desk, with STM32F407, which in all respects of this program has identical GPIOB/I2C1, and I happen to have connected an EEPROM on PB6/PB7. So I simply burned the elf into that hardware, run, and it produced (probably) a START and transmission of address, after which it stuck in the loop waiting for I2C_SR1.ADDR (which never gets set as there's nothing which would ACK the given address - you should check also for I2C_SR1.AF, and I recommend you to add also timeouts later).

(probably) means  that I observed SDA and SCL separately, as the given bus is buried deeply in the device in question and I have no intention to bring out the bus to be probed properly, so I just stuck a oscilloscope probe onto first then second pullup.

So, if you observe something else, I'd say it's hardware failure. You may want to use a "known good" hardware such as Nucleo or Disco boards, together with some means to debug through SWD.

JW

PS. Describe your hardware. What is connected to the bus - slaves, pullups?
« Last Edit: August 21, 2023, 06:25:33 pm by wek »
 

Offline DELTA67Topic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: fr
Re: I2C on STM32F4
« Reply #21 on: August 21, 2023, 08:31:06 pm »
What does that mean? SDA and SCL are surely at some levels.
SCL and SDA stay high.
I'm using PROTEUS for simulation and debugging using included logic analyzer. I've already used it with an ATMEGA328 and it works.
I used also a BlackPIll with F411, and probed SCL and SDA with an oscillo, no activity detected.
At the moment I need only a start condition with address transmission as a proof that the code works.
It's not mandatory to have a device connected to the bus in order to have a start condition and address transmission, the lines are already pulled-up by the internal resistors on PB6 and PB7.
Good news if the code works for you! The address of an EEPROM if A2A1A0 =000 is 0x50 in 7bits format and 0xA0 in 8bits. Can you give it a try please?
« Last Edit: August 21, 2023, 08:35:58 pm by DELTA67 »
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6539
  • Country: es
Re: I2C on STM32F4
« Reply #22 on: August 21, 2023, 08:42:48 pm »
STM32 addition in Proteus is pretty recent, it's much more complex than AVRs, so expect bugs!
You can't say "it works in AVR so it makes sense that STM32 also does".

Just get a cheap board, a stlink and the analyzer. All for $10 or less.

Another code example:
https://dk7ih.de/an-introduction-to-bare-metal-programming-the-arm-cortex-m4r-mcus-lesson-10-i%C2%B2c/
« Last Edit: August 21, 2023, 10:24:52 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline DELTA67Topic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: fr
Re: I2C on STM32F4
« Reply #23 on: August 21, 2023, 10:04:07 pm »
Thanks DavidAlpha for the link which I've already read the content many times!
I've tried their initialization code also with no success.
Yes I have a BLackPill with HID bootloader and a 10MHz USB picoscope.
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6539
  • Country: es
Re: I2C on STM32F4
« Reply #24 on: August 21, 2023, 10:21:48 pm »
I simulated that example with a 24c02 (Addr = 0xA0) and it partially worked.
Sending start then stop crashed somewhere, it didn't like the elf file so I loaded the hex, thus I couldn't step the program.
But I could see start, address, byte 0, stop.
It should inmediately send a start and read the data, but nope.
« Last Edit: August 21, 2023, 10:25:38 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf