Boot problem with STM32 HAL, I2C HDD44780 and 1602 LCD
The delay before initialization will not help in the long run.

The state of IO expander controlling the LCD bus and the LCD controller are reset to known state only when there is a power-up, as they have a power-up reset.

After power-up reset, the LCD bus (IO expander) will be set to all pins high, and the LCD controller is in 8-bit mode, waiting for 8-bit data cycles. The current initialization is not perfect and fails to go reliably into 4-bit mode. The first falling E pulse of first nibble is understood as 8-bit command, and after it the LCD goes to 4-bit mode, but the sending of second nibble throws the bus out of sync, as the LCD is expecting first nibble of 4-bit command now. So in fact, after power-up, the sequence will always cause the display nybbles to be out of sync, by a nybble. That is why resetting MCU helps, as the sequence might get back to sync accidentally.

But when MCU code has been running, and if only MCU is reset, there is no guarantee at which state the LCD bus (IO expander output) or the LCD controller is, so that sequence should be hand-crafted to walk out of any state to a known state. As there is no reset pins or ability to power-cycle the IO expander and LCD via IO pin, it must be performed via I2C bus.

The LCD Enable pin might already be up, while RS and RW need to be set up before rising edge of Enable. Therefore the IO expander (LCD bus) needs one I2C write to get it to known state, preferably by setting Enable low if it was high, and backlight state set to whatever necessary. If it was high, this can execute an unwanted LCD command or send data to it, but not to worry, it is handled next.

The LCD is most likely in 4-bit mode from previous running sequence of MCU, but it is unknown whether it is expecting the first nibble or second nibble of 4-bit command, or still in 8-bit mode after power-up reset. Therefore, the proper sequence to syncronize the 4-bit bus mode is to send single nybbles to LCD at first, commanding it to go back to 8-bit mode. It needs three nybbles of commands to go to 8-bit mode, but there must be enough time between the nybbles, to allow execution of the slowest commands available after the first and second nybble. When the LCD is properly set back to 8-bit mode, it can be commanded to go back to 4-bit mode. This needs basically three nybbles - first an 8-bit command to go to 4-bit mode, and then it will be in 4-bit mode, but without proper font and lines configuration. From this point on, the command bytes can be sent as two nybbles as usual, so first thing it needs is the command byte again as two nybbles, so it stays in 4-bit mode but this time it gets proper font and lines config.