Skip to main content
Graduate
December 31, 2024
Question

Using I2C Communication Protocol with LCD

  • December 31, 2024
  • 4 replies
  • 2908 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.

    4 replies

    Visitor 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).

    Graduate
    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.

     

    Super User
    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.

    Visitor 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.

    Graduate
    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 

    Graduate
    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

     

    Super User
    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.

    Graduate
    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.

    Super User
    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.