Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

embassy-boot sample issues on STM32F3DISCOVERY #3945

Open
Phirks opened this issue Mar 4, 2025 · 2 comments
Open

embassy-boot sample issues on STM32F3DISCOVERY #3945

Phirks opened this issue Mar 4, 2025 · 2 comments

Comments

@Phirks
Copy link

Phirks commented Mar 4, 2025

There's a good chance this is related to me missing a step, so I apologize if that's the case, but I've been trying to get this example working for a week with no luck and I think it should be working. The board I'm working with is an STM32F3DISCOVERY with an STM32F303VCT6 on it.

Here's what I'm doing:

cloning embassy fresh into a new directory

I'm going to the embassy/examples/boot/application/stm32f3/

I'm updating Cargo.toml , replacing "stm32f303re" with "stm32f303vc" in embassy-stm32 features

I'm updating the bootloader, a.rs, and b.rs with LEDs and input pins that are usable on my board

bootloader main.rs

#![no_std]
#![no_main]

use core::cell::RefCell;

use cortex_m_rt::{entry, exception};
#[cfg(feature = "defmt")]
use defmt_rtt as _;
use embassy_boot_stm32::*;
use embassy_stm32::flash::{Flash, BANK1_REGION};
use embassy_sync::blocking_mutex::Mutex;
use embassy_stm32::gpio::{Level, Output, Pull, Speed};
#[entry]
fn main() -> ! {
    let p = embassy_stm32::init(Default::default());
    let mut led = Output::new(p.PE10, Level::Low, Speed::Low);
    // Uncomment this if you are debugging the bootloader with debugger/RTT attached,
    // as it prevents a hard fault when accessing flash 'too early' after boot.
        for i in 0..2000000 {
            cortex_m::asm::nop();
        }
        led.set_high();
        for i in 0..2000000 {
            cortex_m::asm::nop();
        }
        led.set_low();
        for i in 0..2000000 {
            cortex_m::asm::nop();
        }

    let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
    let flash = Mutex::new(RefCell::new(layout.bank1_region));

    let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash);
    let active_offset = config.active.offset();
    let bl = BootLoader::prepare::<_, _, _, 2048>(config);
        led.set_high();
        for i in 0..2000000 {
            cortex_m::asm::nop();
        }
        led.set_low();
        for i in 0..2000000 {
            cortex_m::asm::nop();
        }

    unsafe { bl.load(BANK1_REGION.base + active_offset) }
}

#[no_mangle]
#[cfg_attr(target_os = "none", link_section = ".HardFault.user")]
unsafe extern "C" fn HardFault() {
    cortex_m::peripheral::SCB::sys_reset();
}

#[exception]
unsafe fn DefaultHandler(_: i16) -> ! {
    const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
    let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16;

    panic!("DefaultHandler #{:?}", irqn);
}

#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
    cortex_m::asm::udf();
}

a.rs

#![no_std]
#![no_main]

#[cfg(feature = "defmt")]
use defmt_rtt::*;
use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
use embassy_embedded_hal::adapter::BlockingAsync;
use embassy_executor::Spawner;
use embassy_stm32::exti::ExtiInput;
use embassy_stm32::flash::{Flash, WRITE_SIZE};
use embassy_stm32::gpio::{Level, Output, Pull, Speed};
use embassy_sync::mutex::Mutex;
use panic_reset as _;
use embassy_time::Timer;

#[cfg(feature = "skip-include")]
static APP_B: &[u8] = &[0, 1, 2, 3];
#[cfg(not(feature = "skip-include"))]
static APP_B: &[u8] = include_bytes!("../../b.bin");

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
    let p = embassy_stm32::init(Default::default());
    let flash = Flash::new_blocking(p.FLASH);
    let flash = Mutex::new(BlockingAsync::new(flash));

    let mut button = ExtiInput::new(p.PC6, p.EXTI6, Pull::Up);

    let mut led = Output::new(p.PE11, Level::Low, Speed::Low);
    let mut led_2 = Output::new(p.PE13, Level::Low, Speed::Low);
    let mut led_3 = Output::new(p.PE14, Level::Low, Speed::Low);
    
    led.set_high();
    led_2.set_high();

    let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash);
    let mut magic = AlignedBuffer([0; WRITE_SIZE]);
    let mut updater = FirmwareUpdater::new(config, &mut magic.0);
    button.wait_for_falling_edge().await;
    let mut offset = 0;
    for chunk in APP_B.chunks(2048) {
        let mut buf: [u8; 2048] = [0; 2048];
        buf[..chunk.len()].copy_from_slice(chunk);
        updater.write_firmware(offset, &buf).await.unwrap();
        offset += chunk.len();
    }
    updater.mark_updated().await.unwrap();
    led.set_low();
    led_3.set_high();
    Timer::after_millis(500).await;
    cortex_m::peripheral::SCB::sys_reset();
}

b.rs

#![no_std]
#![no_main]

#[cfg(feature = "defmt")]
use defmt_rtt::*;
use embassy_executor::Spawner;
use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_time::Timer;
use panic_reset as _;

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
    let p = embassy_stm32::init(Default::default());
    let mut led = Output::new(p.PE9, Level::High, Speed::Low);

    loop {
        led.set_high();
        Timer::after_millis(500).await;

        led.set_low();
        Timer::after_millis(500).await;

    }
}

I'm flashing the bootloader with:
cargo flash --manifest-path ../../bootloader/stm32/Cargo.toml --release --features embassy-stm32/stm32f303vc --chip STM32F303VCTx

I'm building the secondary firmware with:
cargo build --release --bin b

I'm creating the bin file with:
cargo objcopy --release --bin b -- -O binary b.bin

I'm flashing the initial firmware with:
cargo flash --release --bin a --chip STM32F303VCTx

At first everything works well. I get 2 flashes from PE10 showing the bootloader runs.
Then I get PE11 and PE13 on showing that the "a" firmware is running
I short PC6 to ground and PE11 turns off while PE14 turns on which shows the update was completed without a panic
The board then boots back to the bootloader, which flashes PE10 twice.
Then, nothing. The "b" firmware does not run. All LEDs turn off and stay off.

Because PE10 flashes twice, I know that the bootloader makes it to the last line without trouble

unsafe { bl.load(BANK1_REGION.base + active_offset) }

I can go back and run the same thing with "b" as the main firmware with:
cargo build --release --bin b --chip STM32F303VCTx

That works well, and PE9 flashes continuously after the bootloader finishes.

I've tried this with several machines and have really tried to run this problem down, but have not had any luck.

side note, I know that .cargo/config.toml also has a reference to the target chip, but when I went to change it I noticed that the runner is already set to STM32F303VCTx.

@lulf
Copy link
Member

lulf commented Mar 7, 2025

Looks to me like you're doing everything correct here. I'm assuming you're using the memory.x https://github.com/embassy-rs/embassy/blob/main/examples/boot/application/stm32f3/memory.x for the application as well, since b is working if you flash it with the bootloader running.

One thing to check next is maybe to verify that the flash operations work as expected on your chip (i.e. run an example that erase, write, read flash across the same regions to check that there is no bug in the flash driver).

Then, another point might be to verify that bank1_region.base + active_offset points to 0x08008000. Fwiw the chip metadata used by the HAL should be this https://github.com/embassy-rs/stm32-data-generated/blob/main/stm32-metapac/src/chips/stm32f303vc/metadata.rs

@Phirks
Copy link
Author

Phirks commented Mar 9, 2025

Yes, this one:

MEMORY
{
  /* NOTE 1 K = 1 KiBi = 1024 bytes */
  BOOTLOADER                        : ORIGIN = 0x08000000, LENGTH = 24K
  BOOTLOADER_STATE                  : ORIGIN = 0x08006000, LENGTH = 4K
  FLASH                             : ORIGIN = 0x08008000, LENGTH = 64K
  DFU                               : ORIGIN = 0x08018000, LENGTH = 66K
  RAM                         (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
}

__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER);
__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER);

__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOTLOADER);
__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOTLOADER);

I also got a NUCLEO-F303RE dev board and tried the same steps (with the different board specified obviously). It had the same issue. I tried using cargo run to get some debugging, and I found that this was the last information before the crash.

ERROR probe_rs::architecture::arm::core::armv7m: The core is in locked up status as a result of an unrecoverable exception
ERROR probe_rs::architecture::arm::core::armv7m: The core is in locked up status as a result of an unrecoverable exception
Error: The core is locked up.

I've had some trouble getting debug messages going in the bootloader, so I'm having a little difficulty troubleshooting the flash driver and pointer to the flash vector table address, but I will get something going this week and get back to you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants