2024-12-31 11:15 AM - edited 2024-12-31 11:16 AM
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)
{
}
}
2025-01-01 03:07 PM
OK, great! Now you can see the startup code.
The disassembly code makes sense, but the memory dump at 0x0800000 - I do not understand:
OK, the Reset_Handler code seems to start correctly: the SP is read from a memory location and set (not the default SP value in ResetHandler). And the code (e.g. after b LoopCopyDataInit) makes also sense (to initialize your RAMs).
And I assume it will jump (call) to main() at the end.
So, actually, the startup without debugger should work. Does it continue correctly?
The only thing which looks suspicious:
You cannot still boot this FW without debugger? (on a new power cycle)
2025-01-01 03:20 PM
When you let the code start itself (after power cycle) - can "we" connect with debugger to the running session?
Maybe with STM32CubeProgrammer: let the board boot, start STM32CubeProgrammer, connect and stop the MCU (where it is, potentially it will stop the MCU anyway on connect).
Where is the PC?
Does it make sense? (compare with IDE Disassembly view where the MCU is)
Let's watch out if MCU with standalone boot would end up in an HardFault_Handler, looping endlessly.
2025-01-01 03:49 PM
OK, I have compared this startup code with one of my project (e.g. for STM32F764): it looks a bit different:
My startup code for this project is:
Reset_Handler:
ldr sp, =_estack /* set stack pointer */
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
movs r3, #0
str r3, [r2], #4
LoopFillZerobss:
ldr r3, = _ebss
cmp r2, r3
bcc FillZerobss
/* Call the clock system initialization function.*/
bl SystemInit
/* Call static constructors */
bl __libc_init_array
/* Call the application's entry point.*/
bl main
bx lr
The "big" difference I see is this:
Where is this startup code coming from?
Do you have another project (with same MCU and board) where it works?
Could you compare the startup.S code?
Or could you find the startup.S code on the CubeHAL drivers (demo projects)?
Is it the same one?
SystemInit should be called AFTER all SRAM is initialized, directly before it jumps to main(). In your code example it looks to be done too early (before SRAM initialization - potentially too early).
2025-01-01 04:01 PM
Meanwhile I am thinking: something goes wrong with your startup.S.
Maybe a need to update the HAL drivers (this CubeHAL) for your board?
Can it be that the startup.S is old and not correct for you board?
Can you find other projects, demo code, in CubeHAL, with "same" (or similar) LinkerScripts and startup.S?
Can you create a very simple demo project (e.g. blinking LED) which boots also standalone?
Compare the differences in source code files, linker script...
Try to find the root cause with debugger (and STM32CubeProgrammer), memory dumps, checking if it makes sense (e.g. SRAM initialized and content able to display and properly written in SRAM), where is the PC (register) when booting as stand-alone...?
Potentially: if it works in IDE (with debugger) it should also work as stand-alone.
The only main reason why it might not work: debugger initializes also SRAM (load all memories, including SRAM). But on stand-alone: the startup.S code has to initialize (copy from ROM to RAM).
2025-01-01 05:44 PM - edited 2025-01-01 05:58 PM
As I mentioned at very beginning.By using HAL library in other project (the same principle), it works very well. Maybe I misled you. I do not know if it is releated to some debugging issue. I just did something wrong. I could not observe that BTF bit was set.It is always cleared. When I debug the program, LCD gives the output only when I go through step by step on each line of code.
void lcd_send_cmd (char cmd)
{
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]);
//while(!I2C1_SR1_BTF_READ());
}
}
When I set a breakpoint into the LCD_Init(); due to TxE is not set, debugger stucks in the 15. line.
Also, I wonder more, as you see in the 18. line my BTF bit is never set. That's why I got it into the comment line.
In the debugging process in the 18.line it goes infinite loop.
Also, I know it's wrong and but I do not think it directly affects my current situation but I used empty loop to give a delay.Because I replaced Hal_delay functions with my own ugly delay functions in the working HAL project.I do not know, hope this explanation can remove the fogg from the sky @tjaekel
2025-01-04 06:52 AM
while (!I2C1_SR1_TXE_READ())
Code enters infinite loop in this control, TxE bit is never set. What should I do to assure it will be set?
2025-01-04 07:41 AM
You're not providing the full picture here. TXE won't be set until you send the address. Have you done that? Can you show a logic analyzer trace of SDA/SCL?
The reference manual is very explicit about what happens when during a transmission. In the case of a master i2c transmission, see here: