Skip to main content
Associate III
December 31, 2024
Question

Using I2C Communication Protocol with LCD

  • December 31, 2024
  • 21 replies
  • 3030 views

STM32F407G DISC-1   STMCubeIDE

Greetings, I am trying to send data to LCD screen by using I2C Communication Protocol. I succeed in doing it by using HAL library. Also, my current work does work in debug mode.However, I could not make it work by running it normally.

I did it in HAL by using the same clock, frequency configurations. I could not find the problem. 

Here is my code:

 

 

 

int main(void)
{
				GPIO_Handle_t I2C1_SCL_PB6 = { .PORTNAME = GPIOB,
												.PINCONF.PIN = GPIO_PIN_6,
												.PINCONF.MODE = GPIO_MODE_ALTARNATE,
												.PINCONF.OTYPE = GPIO_OTYPE_OD,
												.PINCONF.OSPEED = GPIO_OSPEED_VHIGH,
												.PINCONF.PUPD = GPIO_PUPD_PU,
												.PINCONF.AF = AF4

				 	 	 	 	 	 };
				GPIO_Handle_t I2C1_SDA_PB7 = { .PORTNAME = GPIOB,
										 	 .PINCONF.PIN = GPIO_PIN_7,
												.PINCONF.MODE = GPIO_MODE_ALTARNATE,
												.PINCONF.OTYPE = GPIO_OTYPE_OD,
										 .PINCONF.OSPEED = GPIO_OSPEED_VHIGH,
											 .PINCONF.PUPD = GPIO_PUPD_PU,
												.PINCONF.AF = AF4
								 	 };
				gpioInit(&I2C1_SCL_PB6);
				gpioInit(&I2C1_SDA_PB7);
				I2C1_CLOCK_ENABLE();
				I2C1_FREQ_16MHZ();
				I2C1_FREQ_SCL_100MHZ();
				I2C1_RISE_TIME_17();

				I2C1_ENABLE();
				I2C1_ACK_ENABLE();
				I2C1_START_GENERATION();
				I2C1->I2C_DR = SLAVE_ADDRESS_LCD;
				 
			 lcd_init ();
	 		 lcd_send_string ("ABCDE");


			while(1)
			{
			}

}

 

 

 

 

This topic has been closed for replies.

21 replies

Lead II
December 31, 2024

It is hard to tell why "normal" mode does not work (you mean booting itself from flash, w/o debugger loading the code).

Do you any clock configuration without debugger? You code in main() just uses I2C config, nothing else. But booting from flash my need a lot more initialization code (e.g. clock config, flash latency, ...).

Also possible that you build with Linker Script a code image which is loaded and running from SRAM. The debugger will load fine and launch the code on SRAM. But in "normal" mode - there is no SRAM content.

Do you have any simple FW example, e.g. toggling an LED, which runs in "normal" mode? Check what all is done in main() and how your Linker Script will build and load the image. Extend such a "normal" project with your code.

My guess: you build FW to load and run only in SRAM (not properly booting from flash).

Associate III
December 31, 2024

@tjaekel  Yes, basically importing the code into the MCU by clicking  RUN icon. I have no clock config it uses default HSI 16Mhz. 

Sorry, I could not understand fully your point but I am able to toggle some LEDs with the same structure as the above code.

 

TDK
January 1, 2025

Let it "run normally" then when it isn't doing what you want, launch a debugger configuration without downloading new code or resetting the chip and find out where it is and why it's there.

Could also use a logic analyzer to watch the I2C lines.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Lead II
January 1, 2025

I mean: if your project is setup and built (with Linker Script) to be loaded and run in SRAM - with debugger is works fine. But it cannot boot with code "this" stored in flash ROM.
What is your Linker Script?

Yes: try to boot from flash ("normal"), have debugger connected and try to stop debugger, step with debugger... which code is executed? Where are you in code execution?

I assume (still): you create a code image which works fine when debugger loads code to SRAM - but it cannot run the code from flash ROM (as "normal", potentially no code in flash ROM).
Use the debugger in order to check:

  • do you see your code flashed in flash ROM (0x08000000)?
  • can you step in code and does it make sense?
  • can you check your linker script (if it would just assign to be loaded into SRAM and not generating code
    to be stored in flash ROM)?
  • Do you have any other example project which boots code from flash ROM?

I think: if code works with debugger loading and launching the code (on SRAM) - but as "normal" (booting the code stored in flash) it does not work:

  1. code was not built in a way to be stored in flash (Linker Script)
  2. the startup code is missing or startup goes wrong

Just boot in "normal" mode, connect with debugger (the running session) - check what is in flash memory, what is on SRAM, where is the Program Counter (PC, which code does it try to execute)...

Or:
Set a breakpoint in debugger mode on the very instruction done (not on main(), instead a breakpoint on first instruction in ResetHandler.
Set compile options to "-g" and "optimize for debug".

Try to figure out if SRAM is initialized (startup.S was working), if code was written into flash ROM... how the code jumps (in "normal" mode), if startup.S has initialized SRAM...

For me it sounds more as: you build code to be loaded into SRAM via debugger (therefore it works), but without debugger ("normal") there is code in flash ROM.

You can try to flash the code generated also via STM32Programmer: flash the ROM with the BIN file.
But if the linker script has all bound to SRAM addresses it can still fail.

Just post the content of your Linker Script you use.
And tell us what is flashed in Flash Memory. What is the SRAM content before and after "startup.S" was executed?

The debugger is your best friend.

Associate III
January 1, 2025

I checked my project uses either FLASH or RAM by looking here.Ekran Alıntısı.PNG

In my STM32F407VGTX_FLASH.ld file. It seems OK.

/* Memories definition */
MEMORY
{
 CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
 RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
 FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
}

/* Sections */
SECTIONS
{
 /* The startup code into "FLASH" Rom type memory */
 .isr_vector :
 {
 . = ALIGN(4);
 KEEP(*(.isr_vector)) /* Startup code */
 . = ALIGN(4);
 } >FLASH

 and I realized somehing I have tried running it several times later on and was receiving this message Ekran Alıntısı.PNG

This must be the problem causing everything goes bad. What should I do at this point. I am quite confused.

Thanks for your attention

@tjaekel @TDK 

Associate III
January 8, 2025

Duplicate - merged.


Hello,    STM32F407G-DISC1   STMCubeIDE

I am trying to send data to LCD, but  TxE bit is never set and program stucks in while loop of lcd_send_cmd function.Also, SDA line seems always low as you can see in the below. What did I wrong? Any suggestion...

Thanks.

 

 

 

int main(void)
{
				GPIO_Handle_t I2C1_SCL_PB6 = { .PORTNAME = GPIOB,
												.PINCONF.PIN = GPIO_PIN_6,
												.PINCONF.MODE = GPIO_MODE_ALTARNATE,
												.PINCONF.OTYPE = GPIO_OTYPE_OD,
												.PINCONF.OSPEED = GPIO_OSPEED_HIGH,
												.PINCONF.PUPD = GPIO_PUPD_PU,
												.PINCONF.AF = AF4

				 	 	 	 	 	 };
				GPIO_Handle_t I2C1_SDA_PB7 = { .PORTNAME = GPIOB,
										 	 .PINCONF.PIN = GPIO_PIN_7,
												.PINCONF.MODE = GPIO_MODE_ALTARNATE,
												.PINCONF.OTYPE = GPIO_OTYPE_OD,
										 .PINCONF.OSPEED = GPIO_OSPEED_HIGH,
											 .PINCONF.PUPD = GPIO_PUPD_PU,
												.PINCONF.AF = AF4
								 	 };
				I2C1_CLOCK_ENABLE();
				gpioInit(&I2C1_SCL_PB6);
				gpioInit(&I2C1_SDA_PB7);
				//delayFunc();


				I2C1_FREQ_16MHZ();
				I2C1_FREQ_SCL_100MHZ();
				I2C1_RISE_TIME_17();

				I2C1_ENABLE();
				I2C1_ACK_ENABLE();
				I2C1_START_GENERATION();
				I2C1_SR1_READ();
				while(!I2C1_START_READ());
				I2C1->I2C_DR = SLAVE_ADDRESS_LCD;
				I2C1_SR1_READ();
				I2C1_SR2_READ();
			 lcd_init ();
 		 lcd_send_string ("ABCDE");



			while(1)
			{

			}

}
void lcd_init (void)
{
 // 4 bit initialisation


 delayFunc(); // wait for >40ms
 lcd_send_cmd (0x30);
 delayFunc(); // wait for >4.1ms
 lcd_send_cmd (0x30);
 delayFunc(); // wait for >100us
 lcd_send_cmd (0x30);
 delayFunc();
 lcd_send_cmd (0x20); // 4bit mode
 delayFunc();

 // display initialisation
 lcd_send_cmd (0x28); // Function set --> DL=0 (4 bit mode), N = 1 (2 line display) F = 0 (5x8 characters)
 delayFunc();
 lcd_send_cmd (0x08); //Display on/off control --> D=0,C=0, B=0 ---> display off
 delayFunc();
 lcd_send_cmd (0x01); // clear display
 delayFunc();
 lcd_send_cmd (0x06); //Entry mode set --> I/D = 1 (increment cursor) & S = 0 (no shift)
 delayFunc();
 lcd_send_cmd (0x0C); //Display on/off control --> D = 1, C and B = 0. (Cursor and blink, last two bits)
 delayFunc();
 
}
void lcd_send_cmd (char cmd) // lcd_send_data is identically the same 
{ // function with this one as well

 char data_u, data_l;
 data_u = (cmd&0xf0);
 data_l = ((cmd<<4)&0xf0);

 uint8_t data_t[4];
 data_t[0] = data_u|0x0C; //en=1, rs=0 -> bxxxx1100
 data_t[1] = data_u|0x08; //en=0, rs=0 -> bxxxx1000
 data_t[2] = data_l|0x0C; //en=1, rs=0 -> bxxxx1100
 data_t[3] = data_l|0x08; //en=0, rs=0 -> bxxxx1000

 for(int i = 0; i < 4; i++)
 {

 	 while (!I2C1_SR1_TXE_READ())
 		 ; // null statement
 		I2C1->I2C_DR = (data_t[i]);

 }
 	
}

 

 

 

 

SDA.PNGsda1.PNGEkran Görüntüsü (71).png

 

TDK
January 8, 2025

Those SDA/SCL traces are not valid. Something is bad with your configuration. Do you have external pullups? I'd check GPIO settings in the registers to ensure OD AF mode is set. Perhaps do an analog capture, should see a fast falling edge and slow rising edge on both lines.

If it works with HAL, clearly a bug in your code, and you're the only one with insight into that. We can't see what you don't show us.

Perhaps compare I2C1 register settings with HAL to those with your own code. Should be able to spot differences quickly.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Associate III
January 8, 2025

Yes, I already checked them, in HAL structured code, no-pull up, no pull-down is configured.Also, I tried to use external pull-up resistor but in any case TxE is never set.I already shared each file as public.

TDK
January 8, 2025

> Yes, I already checked them

Chip should work the same way then. Registers dictate how it works. It's a mystery. Good luck.

"If you feel a post has answered your question, please click ""Accept as Solution""."