Arksine / katapult

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

Unable to use CanBoot in custom rp2040 design #77

Closed Varghesemela closed 11 months ago

Varghesemela commented 1 year ago

Hi, I have a custom RP2040 design that i intend to use only with the CAN interface for communication and uploading new firmware. But i am unable to write the CanBoot firmware on my custom RP2040 pcb. I have tried doing the same on the stock Rpi Pico module and it works properly. I am able to detect the board using 'scripts/flash_can.py -i can0 -q'. The difference with the custom design is that i am using a W25Q32JVZPIQ flash chip instead of W25Q16 chip. And also the CAN IC that i used is TCAN337 (on custom board) instead of VP230 (on rpi pico module). Is there anything that i am missing here?

Varghesemela commented 1 year ago

I tried installing 'klipper' canboot with the below configuration and it works fine. I am able to query the board and it shows up with the uuid. But when i do the same for the Canboot firmware, nothing shows up. Screenshot from 2023-07-04 13-17-08

Below is the configuration on canboot that i am using. Screenshot from 2023-07-04 13-21-03

I was also using 2 different kinds of CAN ICs, and just to clear out any confusion, switched to using both of the same model (TCAN337). But as expected, there was no change.

Arksine commented 1 year ago

Have you dumped the flash contents to confirm that CanBoot is not present? Prior to uploading CanBoot are you performing a full chip erase on the flash? If CanBoot detects anything at the start of the application region of flash it won't enter the bootloader, and it doesn't appear that you have configured a method to manually enter the bootloader.

Varghesemela commented 1 year ago

This time i first uploaded the deployer.elf first and then uploaded the canboot.elf file. After this, i was able the detect the board while querying. I also set an offset of 32kB using a linker script for the main application before building it. Next i tried uploading my firmware using python3 scripts/flash_can.py -i can0 -f ../Picocontrol/cmake-build-debug/src/picocontrol.bin -u xxxx and it did upload successfully. But after the firmware was uploaded, the board did not showup while querying, neither did it work according to the application code. P.S. I am able to run this code by uploading it using the debug probe.

Arksine commented 1 year ago

CanBoot jumps to the application at a 16KiB offset on the rp2040, so it sounds like your build is misconfigured.

After CanBoot uploads an application it will not enter the bootloader again until the bootloader is requested. Therefore you won't be able to query the UUID unless your application responds.

Varghesemela commented 11 months ago

Correct. Sorry for the late reply. I just jumped back to my project. I was occupied in something else. So i now use a custom linker script to change the flash address by 16KiB offset and it is working. Can you please help me in understanding how to use canboot in my application? Right now, my understanding is that katapult sits at the 2nd stage bootloader and runs the main application at 16KiB offset. My application uses CAN for messaging and i will detect a custom command to switch back to flash update sequence before running 'flashtool.py'. How should i manually enter the bootloader?

Thanks again.

Arksine commented 11 months ago

I can show you how Klipper does it. The thing to keep in mind is that this is a unified method intended to work across all ARM based platforms supported by Klipper.

// CONFIG_FLASH_BOOT_ADDRESS is defined in Klipper's kconfig, the address below is
// is what should be the boot address for the rp2040
#define CONFIG_FLASH_BOOT_ADDRESS 0x10000100
#define REQUEST_CANBOOT 0x5984E3FA6CA1589B

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();
}

The basic explanation is that the application (Klipper) reads out the first 32-bits of Katapult in flash memory to get the address in sram where Katapult's stack ends. It then disables irqs, writes the 64-bit magic key to this location, and resets the device.

Varghesemela commented 11 months ago

Thank you @Arksine for pointing me in the right direction. I was able to upload my firmware over CAN with this approach.