Page 1 of 2

CAN Bootloader

Posted: Sun Nov 28, 2021 2:54 am
by EV_Builder
As per title!
Couldn't find anything available so took the bootloader from Johannes and modified it towards a CAN version.

Build a GUI and the rest is history.

The CAN Interface used is a profi one from PEAK Systems.
https://www.peak-system.com/PCAN-USB-FD.365.0.html?&L=1

Didn't optimize yet for performance or size.

Currently 1 msg per mS (8bytes).
+/-8K/sec.
CanbootLoader.JPG
Update:
Currently the size needed is 0x2000 (8K) so we need to modify the LD files.
I'm thinking on a solution for that.

Re: CAN Bootloader

Posted: Sun Nov 28, 2021 3:13 pm
by johu
That's cool. Puzzled by the size though... Is it on github for further inspection?

Re: CAN Bootloader

Posted: Sun Nov 28, 2021 3:37 pm
by EV_Builder
johu wrote: Sun Nov 28, 2021 3:13 pm That's cool. Puzzled by the size though... Is it on github for further inspection?
No not yet i finished it last night.
Didn't optimize yet for size.
It uses both libraries cm3 and inv.

Re: CAN Bootloader

Posted: Sun Nov 28, 2021 8:25 pm
by EV_Builder
Ok i optimized it a bit i now reserve 8K in the loader.

This is my contribution to the community of OpenInverter.org.
Enjoy!

https://github.com/EV-Builder/CANBootloader

Re: CAN Bootloader

Posted: Sun Nov 28, 2021 11:13 pm
by johu
Superb, thanks!
So I did a build from the cloned repo and the binary was only 7k. Then I enabled -Os (optimize for size) and binary shrunk to 5.5k. While I much sympathize with using libopeninv, in this size critical application it could be worthwhile to carve it out even more than you did already. I can make a few quick experiments tomorrow to see if it's worthwhile

Re: CAN Bootloader

Posted: Sun Nov 28, 2021 11:51 pm
by EV_Builder
Ok cool! I'm building the Bootloader GUI app right now.
Current speed is like +/-12 seconds to program 27K but i have some tricks on my sleeve remaining.
I think its the host pc limiting the speed not the uController.
(each msg invokes the GUI currently and that's expensive).

(how big are our inverter / charger programs anyway?)

Another option might be to program it on the end of the memory and jump back and forth...
You can then have: and the Wifi bootloader (serial) and then jump to the CAN bootloader and then back to start address.
(maybe by simply checking in the first bootloader if the CAN bootloader is programmed?).

Re: CAN Bootloader

Posted: Thu Dec 02, 2021 10:06 pm
by EV_Builder
@johu; would you mind add to the bootloader (or paste it here) the code snippet to obtain the unique CPU id?
I need a 5 to 7byte ID.

I want to send it out on the first request for bootloader.
In the GUI we can then select which device we want to adress for the update and give normale names to the devices. (DHCP/DNS style).

This saves us from uploading to the wrong device in the network :)

Re: CAN Bootloader

Posted: Fri Dec 03, 2021 3:03 pm
by johu
Yes, check here: https://github.com/jsphuebner/stm32-sin ... j.cpp#L177

Inverter firmware is currently about 45k

Re: CAN Bootloader

Posted: Fri Dec 03, 2021 8:38 pm
by EV_Builder
txs!

Re: CAN Bootloader

Posted: Mon Dec 13, 2021 6:25 pm
by EV_Builder
Ok made the tool stand-alone.
CanbootLoader2.JPG
Node selection works.

Re: CAN Bootloader

Posted: Tue Dec 14, 2021 10:14 pm
by johu
That looks very nice! Would the GUI also run on Linux?

Re: CAN Bootloader

Posted: Sun Jan 15, 2023 4:11 pm
by davefiddes
This thread seems to have stalled when it looked like it was heading towards a useful solution. Are there any updates?

I'm kicking the tyres around a solution for a Tesla Model 3 (i.e. TI C2000 MCU) CAN bootloader. It would seem to be best to try and combine efforts with a solution for STM32 systems.

Re: CAN Bootloader

Posted: Fri Feb 03, 2023 7:08 pm
by johu
Will revisit this now because my BMS only has CAN communication. @EV_Builder: can you make that GUI available? That said I will probably make a python script anyway.

Re: CAN Bootloader

Posted: Sat Feb 04, 2023 9:18 am
by EV_Builder
johu wrote: Fri Feb 03, 2023 7:08 pm Will revisit this now because my BMS only has CAN communication. @EV_Builder: can you make that GUI available? That said I will probably make a python script anyway.
Now that im commercially active I can't share that for the obvious reasons...

Better use a python script; or add-on on savvycan i only use Windows so it won't run on linux. My HW support is limited to peak adapters too.

Most importantly: use the full 8bytes during transfer; and bit bang so ack each message. Flash burn and CRC takes most of the time anyway.

If you run into issues I can help.
You already have my canbus bootloader firmware right?

Re: CAN Bootloader

Posted: Sat Feb 04, 2023 9:45 am
by johu
Ok, np.
EV_Builder wrote: Sat Feb 04, 2023 9:18 am You already have my canbus bootloader firmware right?
Yes, I will reuse the protocol and restructure the firmware a bit to hopefully fit into 4k. Did you implement a reset command in firmware? Otherwise I think I'll just add an SDO index for it.

Re: CAN Bootloader

Posted: Sat Feb 04, 2023 12:06 pm
by davefiddes
When I didn't hear back I looked into the protocol some more. There looks to be a pretty serious problem with it when it comes to supporting more than one device on the same CAN bus. Think on turning on the ignition in a car with stm32-sine, stm32-vcu and your bms. Can I suggest you add a HW platform ID (stm32-sine, stm32-vcu, etc) and a unique node ID (say last 32-bits of the platform ID from DESIG_UNIQUE_ID0) to the initial "HELLO" packet? The reply to start the download would need to include the node ID to allow the competing nodes to determine if it was for them or not.
johu wrote: Sat Feb 04, 2023 9:45 am Did you implement a reset command in firmware? Otherwise I think I'll just add an SDO index for it.
Was considering doing something similar to replace other serial terminal commands (e.g. save, load, start, stop). Seems a hacky use of the protocol but easy to do. Would be good to share a common approach.

Re: CAN Bootloader

Posted: Sat Feb 04, 2023 2:41 pm
by EV_Builder
Yes; Later versions have that ID for exactly that purpose and the reset could be in the BMS firmware not in the bootloader.

The GUI can decide who to let go into user app and who not.
If you need todo multiple BMS boards i would do them one by one and keep others waiting. You can then release them all at once or one by one. I expect a small program so it won't take the world.
If you have Todo allot of boards i would broadcast the data and enable those devices who should write along. The ones who fail CRC could simply stop. This way I bet you don't over complicate and it will work. CRC never failed.

Re: CAN Bootloader

Posted: Sun Feb 05, 2023 5:38 pm
by johu
I went over the code and removed the dependency for the libopeninv CAN module and some other unneeded stuff, see here
https://github.com/jsphuebner/stm32-CANBootloader/

The result:

Code: Select all

   text	   data	    bss	    dec	    hex	filename
   4056	     16	   2088	   6160	   1810	stm32_canloader
yay, back to 4k. Now of course I need to test if it still works. I left the program logic mostly untouched.

Re: CAN Bootloader

Posted: Mon Feb 06, 2023 1:10 pm
by johu
I have now completely rewritten the loader while sticking pretty much to the original protocol. Tested and works. Also got the size down a bit more

Code: Select all

   text	   data	    bss	    dec	    hex	filename
   3796	     12	   2064	   5872	   16f0	stm32_canloader
Remaining issue: I initialize the clock to run off the internal oscillator (because I omitted the external one on the BMS). Now when I flash stm32_sine, it tries to switch to the external oscillator. This apparently fails and I get a very slow blinking LED. Is it not possible to change the oscillator after initial selection?
Wouldn't be a large problem, would just need to compile different boot loaders.

Protocol is now pretty much like the UART boot loader but I switched to 2k page size to be compatible with F105 and F107 without extra overhead.
  1. Send 0x7DE#1#'2' to indicate we entered version 2 boot loader
  2. Wait for reception of 0x7DD#1#0xAA magic
  3. Send 0x7DE#1#'S' to request number of pages, 2k per page
  4. Wait for reception of page size 0x7DD#1#S
  5. Send 0x7DE#1#'P' to request the first 8 bytes
  6. Repeat until full page has been received
  7. Send 0x7DE#1#'C' to request CRC over the 2k page
  8. Wait for CRC, check it
  9. If CRC correct program flash
    • If all pages received send 0x7DE#1#'D' and we're done
    • Otherwise go to 6
  10. If CRC incorrect send 0x7DE#1#'E' and go to 6
I have added an updater.py that implements this. Now need to implement a reset command via SDO.
EDIT: reset command should contain 32 bits of ID info in the data part to be able to precisely select which device to reset. Said ID should also be an SDO object. That said, the nodes should be set up in a way that they have different node ids anyway.
The BMS will achieve that with a daisy-chained address signal.

Re: CAN Bootloader

Posted: Mon Feb 06, 2023 6:43 pm
by davefiddes
Looked at the code. Unfortunately it fails the "What if I have more than one?" test as explained above.

If you have clashing CANopen node ids then you are in for a world of hurt. Adding redundant information to a network protocol rarely ends well...

Re: CAN Bootloader

Posted: Mon Feb 06, 2023 7:48 pm
by johu
Yes, aware of that. Changing the magic to a word of the processor uid would fix it but requires obtaining said uid making the process more complicated.

When you've got your node ids sorted there wouldn't be an issue as you only ever reset one node and the other ones won't even see the updater packets down to filtering. The updater could obtain the firmware version via SDO. If it gets more than one reply, there's trouble.

Then there's the corner case of some devices not being flashed with running firmware. They'd be in the boot loader cycle asking for firmware. In that case you'd flash random firmware to one of them. Not good. You'd have to power down all OI devices except the one you want to flash.

Re: CAN Bootloader

Posted: Tue Feb 07, 2023 6:47 am
by EV_Builder
I help:

Include in step 1 6 bytes of chip unique Id.
Now on boot the GUI gives lots of chips. You can self compose list of who is what.
Insert wait loop for can msg if nothing boot user app.
If received 'W' with 6bytes equal Id rerun said loop.
If received 'AA' with 6bytea Id proceed.

Now on boot GUI can show all and if no choice is made it sends to all of them W with id.

Now user selects Id. That one receives AA. Now you have 2 choices keep others waiting..send W and their ID or don't do anything and they will boot user app.

Now Dave's case is solid and johu can control what to update and what not. In step 1 one byte is left. Could be used as device description. ...

Re: CAN Bootloader

Posted: Wed Feb 08, 2023 10:15 am
by crasbe
johu wrote: Mon Feb 06, 2023 1:10 pm I have now completely rewritten the loader while sticking pretty much to the original protocol. Tested and works. Also got the size down a bit more

Code: Select all

   text	   data	    bss	    dec	    hex	filename
   3796	     12	   2064	   5872	   16f0	stm32_canloader
Remaining issue: I initialize the clock to run off the internal oscillator (because I omitted the external one on the BMS). Now when I flash stm32_sine, it tries to switch to the external oscillator. This apparently fails and I get a very slow blinking LED. Is it not possible to change the oscillator after initial selection?
Wouldn't be a large problem, would just need to compile different boot loaders.
I can't really say how libopencm3 does it, but I've done some PLL configuration on the register level of the STM32.
Generally speaking you have to be very careful about the correct order of operations. The reference manual is unfortunately not veeeery detailed about this, but you could check the PLL status flags as a start to see what's going on.

If the microcontroller doesn't like the PLL settings you're trying to do, it won't apply them. Maybe it thinks, that the clock is not ready yet?
7.2.6 System clock (SYSCLK) selection
After a system reset, the HSI oscillator is selected as system clock. When a clock source is
used directly or through the PLL as system clock, it is not possible to stop it.
A switch from one clock source to another occurs only if the target clock source is ready
(clock stable after startup delay or PLL locked). If a clock source which is not yet ready is
selected, the switch will occur when the clock source will be ready. Status bits in the Clock
control register (RCC_CR) indicate which clock(s) is (are) ready and which clock is currently
used as system clock.
https://www.st.com/resource/en/referenc ... ronics.pdf


I think you have to deactivate the peripheral clocks as well before switching over? But I really don't recall.

Re: CAN Bootloader

Posted: Thu Feb 09, 2023 7:57 am
by johu
Intead of calling rcc_clock_setup_pll() which sets a whole host of prescalers I have now initialized only what I need:

Code: Select all

   rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL6);
   rcc_set_pll_source(RCC_CFGR_PLLSRC_HSI_CLK_DIV2);
   rcc_osc_on(RCC_PLL);
   rcc_wait_for_osc_ready(RCC_PLL);
   rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
Then, most importantly the clock source must be reset to pure HSI (8 MHz) and the PLL must be disabled before leaving the boot loader

Code: Select all

   rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
   rcc_osc_off(RCC_PLL);
The peripheral clocks can stay on. Would be more clean to turn them off but they will be used by most applications anyway (GPIO, CRC and CAN)

EDIT: this also saved a few 100 bytes of flash and we're down to 3.4k. I wonder if a unified boot loader supporting both CAN and UART is in reach.

Re: CAN Bootloader

Posted: Thu Feb 09, 2023 11:12 am
by johu
I have now handled the multiple device scenario by allowing an optional ID to be specified in the magic packet. So if you have just one device on the bus you can do as before and just send a 1-byte can message with 0xAA to enter update mode. If you have multiple devices you must know their DESIG_UNIQUE_ID2 value. ID2 seems the one that always changes between processors, should be unique enough.
It remains to the user to find this. I don't think having the boot loader send it out is useful as then you still don't know who sent what. If you have a wifi module you can find it out with the "serial" command (it needs to be pimped to place a ":" between the words). In a CAN setup you can only find out with a yet to introduce SDO which means you need your node ids sorted.

Once you know the updater is launched with

Code: Select all

python3 updater.py -d can2 -f stm32_yourname.bin -i 8721503A
It places the ID in the last word or byte 4-7 of the magic packet.
It will wait for an 'S' to be returned forever. If no one returns an S, no update happens.

EDIT: I think it might be useful to develop (if not exists) an ESP32-CAN dongle that runs the openinverter web frontend just transferring its data via CAN.