2024-09-24 12:56 PM - last edited on 2024-10-04 04:53 AM by SofLit
Hi,
I'm trying to use built in can bus bootloader in STM32L433 Nucleo Board. To enter the bootloader, I configure the Flash option byte as below:
void configure_bootloader_option_bytes(void) {
// Define a structure to hold the option byte configuration
FLASH_OBProgramInitTypeDef ob_config;
// 1. Unlock the Flash control register access
while(HAL_FLASH_Unlock() != HAL_OK)
{
printf("Waiting Flash Unlock\r\n");
}
// 2. Unlock the Option Byte register access and check busy bit
while(HAL_FLASH_OB_Unlock() != HAL_OK)
{
printf("Waiting OB Unlock\r\n");
}
while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)){}
// 3. Get the current Option Bytes configuration
HAL_FLASHEx_OBGetConfig(&ob_config);
/*
*__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)
* FLASH_OPTR_nBOOT1 23
* FLASH_OPTR_nBOOT0 27
* FLASH_OPTR_nSWBOOT0 26
* */
// 4. Set the desired values for nBoot0, nBoot1, and nBoot0_SW
// Set nBoot0 = 0 (so that the bootloader is controlled by BOOT0 pin)
ob_config.OptionType = OPTIONBYTE_USER;
// ob_config.USERType &= (OB_USER_nBOOT1 | OB_USER_nSWBOOT0 | OB_USER_nBOOT0);
ob_config.USERType |= (OB_USER_nBOOT1 | OB_USER_nSWBOOT0 | OB_USER_nBOOT0);
ob_config.USERConfig &= ~FLASH_OPTR_nBOOT0; // This sets nBoot0 to 0
// Set nBoot1 = 1 (boot from system memory - bootloader)
ob_config.USERConfig |= FLASH_OPTR_nBOOT1; // FLASH_OB_USER_nBOOT1 ; // This sets nBoot1 to 1
// Set nBoot0_SW = 0 (disable software override for BOOT0)
ob_config.USERConfig &= ~FLASH_OPTR_nSWBOOT0; // FLASH_OB_USER_nSWBOOT0 ; // This clears nBoot0_SW, making it 0
// 5. Program the new Option Bytes configuration
if (HAL_FLASHEx_OBProgram(&ob_config) != HAL_OK) {
// Handle error if programming fails
HAL_FLASH_OB_Lock();
HAL_FLASH_Lock();
Error_Handler();
}
// 6. Launch the option byte reload to apply changes
HAL_FLASH_OB_Launch();
/* We should not make it past the Launch, so lock
* flash memory and return an error from function
*/
// 7. Lock the Option Bytes and Flash control registers
HAL_FLASH_OB_Lock();
HAL_FLASH_Lock();
// 8. Reset the microcontroller to apply the new boot settings
NVIC_SystemReset();
// return HAL_ERROR;
}
Then I made sure I'm in the bootloader from STM32 Programmer. That the PC (Program counter) in the Bootloader range (at 0x1FFF0000)
And I followed the flow chart in AN2606, and AN3154(CAN protocol used in the stm32 bootloader).
But it not responding, I'm able to send and receive can messages between my STM32L433 Neucluo Board and Beagle Bone AI (using python in BB AI) before STM32 enter Bootloader mode, but AFTER the stm32 enter the bootloader mode it will not response to any message.
this is my simple python program to talk to the stm32L433 can bootloader:
class UpdateFirmware():
def __init__(self):
self.can_channel = 'can1'
self.bus = can.interface.Bus(interface='socketcan', channel= self.can_channel, bitrate=125000)
def TX_can_msg(self, ID, can_data, extended_id=False):
self.TX_msg = can.Message( arbitration_id=ID, data=can_data, is_extended_id=extended_id)
try:
self.bus.send(self.TX_msg)
# print(f"Message sent on {self.bus.channel_info}")
except can.CanError:
print("Error: Message NOT sent")
traceback.print_exc()
def RX_can_msg(self, timeout=0.1):
try:
msg = self.bus.recv(timeout)
# if msg is None:
# print("No message recived")
# else:
if msg is not None:
# print(f"Message Received: {msg}")
# print(f"Message Received: STD ID: {msg.arbitration_id} -- DLC = {msg.dlc} -- Data = {' '.join(f'{byte:02x}' for byte in msg.data)}")
pass
return msg
except can.CanError:
print("Error: Message NOT received")
traceback.print_exc()
if __name__=="__main__":
x = UpdateFirmware()
# Send BL Start Message
x.TX_can_msg(0x79, [])
time. sleep(2)
msg = x.RX_can_msg()
if msg is not None:
print(f"1 Message Received: STD ID: 0x{msg.arbitration_id:X} -- DLC = {msg.dlc} -- Data = {' '.join(f'{byte:02x}' for byte in msg.data)}")
# Send BL Get command Message
x.TX_can_msg(0x00, [0x79])
time.sleep(0.1)
# receive BL Can message from Get Command (16 can massages should be received )
while True: # Get command
msg = x.RX_can_msg()
time.sleep(0.1)
if msg is not None:
print(f"{i + 1} Message Received: STD ID: 0x{msg.arbitration_id:X} -- DLC = {msg.dlc} -- Data = {' '.join(f'{byte:02x}' for byte in msg.data)}")
i += 1
if i == 16:
msg = None
break
if msg.data == 0x1F:
print('NACK')
raise
msg = None
Am I doing something wrong here? Does anyone have a good example showing how to use the built-in can bootloader for the STM32L4XXX?
Thank you.
2024-09-25 02:25 AM - edited 2024-09-25 02:29 AM
Hello @KAhmed,
Let me first welcome you to the ST Community :)
Did you follow the "Table 148. STM32L43xxx/44xxx configuration in system memory boot mode" from AN2606 and set PB8 and PB9 for CAN1_RX and CAN1_TX pins?
Check the clock and HSE settings.
2024-09-25 05:02 AM - edited 2024-09-25 06:42 AM
Hi Imen,
Thank you for your response.
Yes, I did configure CAN1 in PB8 and PB9 at 125 kbps , I'm able to send and receive can messages between my STM32L433 Nucleo Board and Beagle Bone AI (using python in BB AI) before STM32 enter Bootloader mode, but AFTER the stm32 enter the bootloader mode it will not response to any message.
2024-09-25 07:11 AM
Hi Imen,
I’m working with the Nucleo STM32L433 and don’t have an external clock available. Do I need to solder on an external clock, or can I use the internal HSI? I’ve configured the HSI to run at 60 MHz and set the CAN baud rate to 125 Kbps.
2024-09-30 09:55 AM
Hello @KAhmed
This post has been escalated to the ST Online Support Team for additional assistance. We'll contact you directly.
Regards,
Roger