Arksine / katapult

Configurable bootloader for Klipper
GNU General Public License v3.0
390 stars 67 forks source link

STM32G0 Series Workaround for BOOT0-Pin Problem #82

Open skuep opened 11 months ago

skuep commented 11 months ago

Hi everyone, I would like to address a very recent issue popping up at multiple places related to the BOOT0 Pin in the STM32G0 series devices. See:

The issue basically is, that STM thought it was a good idea, to disable the BOOT0-Pin functionality (unless the flash is empty). That means, DFU mode can be reached on those devices when you buy them and they are unprogrammed. You can flash CanBoot to those devices via dfu-util without any issues. However, if you want to change e.g. the CAN baudrate of CanBoot, you will quickly find, the device will no longer enter DFU mode by asserting BOOT0-Pin = 3.3V, because it is disabled by default in the STM32 option bytes.

As a fix, it is possible to program the option bytes, setting the nBOOT_SEL=0. This enables the "legacy" (sic!) behaviour. This can be done via SWD (needs hardware probe), DFU (clunky) or from within the device itself (cool). I am proposing to add a CanBoot menuconfig option for STM32G0 series devices STM32G0_ENABLE_BOOT0PIN (or similar, which is enabled by default), that checks on startup if the above option bit is set, and if it is, it will reset the bit permanently. This will function very similar to the already available menuconfig-option STM32F103GD_DISABLE_SWD for the GigaDevice stuff.

Here is a code snippet on how to do that: https://github.com/olikraus/stm32g031/blob/main/enable_boot0/enable_boot0.c

I am willing to integrate this feature and issue a pull request, if you think, this is a good idea, however the following question arises: I think most of the source is pulled from Klipper upstream, right? Would I need to integrated this feature into Klipper and wait for it to trickle down into CanBoot, or can we make this adjustment in the CanBoot sourcecode? I think most users (with CAN boards) will use CanBoot as a bootloader (i.e. the first thing they will flash to the board), so CanBoot is (in my opinion) a good place to make this change to the option-bytes.

NAPCAL commented 11 months ago

If Klipper firmware is installed, then that would be problematic to update.

If there is another bootloader present, then the CanBoot deployer can be used to replace the current bootloader by following that bootloader’s loading procedure.

If CanBoot is already on the STM32G0, then using the deployer option can update the current CanBoot.

CanBoot deployer does wipe the flash memory beyond the CanBoot application space, so loading Klipper firmware is required after using deployer.

NAPCAL commented 11 months ago

Also,

I have never had a problem with getting STM32G0B1 into DFU mode (BTT U2C V2.0/2.1, BTT EBB36/42 V1.1/1.2, BTT EBB SB2209/2240 [G0B1]).

Maybe a newer version of the G0B1 or other versions of the G0’s?

skuep commented 11 months ago

If Klipper firmware is installed, then that would be problematic to update.

How so? What exactly would be problematic to update? CanBoot?

If there is another bootloader present, then the CanBoot deployer can be used to replace the current bootloader by following that bootloader’s loading procedure.

To be clear, I am not talking about the deployer. I am talking about adding the check in the actual CanBoot bootloader startup code. So that anyone flashing CanBoot at least once, has this issue solved forever.

I have never had a problem with getting STM32G0B1 into DFU mode (BTT U2C V2.0/2.1, BTT EBB36/42 V1.1/1.2, BTT EBB SB2209/2240 [G0B1]).

Maybe a newer version of the G0B1 or other versions of the G0’s?

No, I think BTT is already doing what I am proposing when they flash their own devices. They clear the bit (in their own firmware or using other means) before the board ships to you. If you buy a blank STM32G0 chip from a distributor, it WILL have this issue.

Arksine commented 11 months ago

I don't think its a good idea to have Katapult modify the option bytes. IMO you have a few options here: 1) Create a tutorial for updating the option bytes over DFU using STM32CubeProgrammer 2) Perhaps create a script that can do it using the CLI 3) Create a small application that does it and use Katapult to upload and run it.

skuep commented 11 months ago

I don't think its a good idea to have Katapult modify the option bytes. IMO you have a few options here:

Thanks for your reply. Sure, it puts Katapult a bit "on the spot" and if issues arise, you would be the one to blame. I can understand that. My issue is, that getting a Klipper firmware with Katapult running on a random board is already hard enough (for the layman).

To me, it's a real pity to add just another layer of (in this case unnecessary) complexity the user has to go through. It's bugging me to an extent, where I am thinking about switching to a different MCU.

1. Create a tutorial for updating the option bytes over DFU using STM32CubeProgrammer

Possible, user would have to install yet another (crappy and proprietary) DFU software (e.g. dfu-util is easily available on Linux platforms). And making the user have to take another tutorial for no value is very undesirable, if we want to maximise the number of people being able to use our hardware.

2. Perhaps create a script that can do it using the CLI

Same argument, make them run a script (on what OS?). Another issue I have with this is, that this problem is universal with this MCU. So it would be best if the issue is solved in a central location. Otherwise there will be various scripts scattered around different board projects being (probably almost) copies of each other.

3. Create a small application that does it and use Katapult to upload and run it.

I could do that, with the same issue of universality as in the previous point. As I understand I would have to create a full-fledged CAN capable firmware (so it can be requested to jump back into the Katapult bootloader) just for modifying the option bytes.

Still, thanks for the reply. Will need to find another way, that (at best) is completely transparent to the user and does not generate additional work for no gain.

EDIT: Just wanted to add I'm okay with closing the issue :+1:

Arksine commented 11 months ago

I could do that, with the same issue of universality as in the previous point. As I understand I would have to create a full-fledged CAN capable firmware (so it can be requested to jump back into the Katapult bootloader) just for modifying the option bytes.

The application doesn't need to support CAN, USB, or UART. All it needs to do is set the option bytes. If you want to jump back to the bootloader all that is necessary is to set the Magic Key in Memory and reset the device (via NVIC_SystemReset()). Below is the code taken from Klipper:

void
try_request_canboot(void)
{
    uint32_t *bl_vectors = (uint32_t *)(CONFIG_FLASH_BOOT_ADDRESS);
    uint64_t *req_sig = (uint64_t *)bl_vectors[0];
    irq_disable();
    *req_sig = REQUEST_CANBOOT;
#if __CORTEX_M >= 7
    SCB_CleanDCache_by_Addr((void*)req_sig, sizeof(*req_sig));
#endif
    NVIC_SystemReset();
}

What this does is read out the first 32 bits of flash (CONFIG_FLASH_BOOT_ADDRESS should be 0x08000000 for stm32), which contains the memory address for the end of the stack. It then writes the request signature to that location. After the reset Katapult will for the boot entry signature and enter when it is detected.

skuep commented 11 months ago

Okay, I will have a look at this, thanks a bunch!

katosabi commented 8 months ago

I ran into this issue on my SB2209 (I replaced the STM32 myself after shorting the old one out). Thanks to this I managed to update with the deployer, which is more convenient than DFU flashing anyway.

For anyone else with an SB2209 (your menuconfig will possibly be different for other boards):

Find UUID

You will have to stop the Klipper service before applying power to the MCU/toolhead, otherwise Klipper will take control of them and the next UUID query will return nothing.

sudo service klipper stop (or use the stop button in the power menu on Mainsail if you're using that)

Power cycle your MCU/toolhead if you've already applied power, or power it up now.

Then we need to find the UUID of the MCU/toolhead:

python3 ~/katapult/scripts/flashtool.py -i can0 -q

image

If you're using your MCU as a bridge/on the canbus like I am, unplug your toolhead CAN or power, run the command again, and see which one disappears; that will be the UUID you want.

Bootloader Update via Deployer

cd ~/katapult

make menuconfig for Katapult

image

make

python3  ~/katapult/scripts/flashtool.py  -i  can0  -f  out/deployer.bin  -u  UUID_HERE

Klipper Update

cd ~/klipper

make menuconfig for Klipper

image

make

python3  ~/katapult/scripts/flashtool.py  -i  can0  -f  ~/klipper/out/klipper.bin  -u  UUID_HERE