Upload firmware via CANbus

Status
Not open for further replies.

ilium007

Well-known member
I am looking at CANbus for a project I am working on and it has been suggested that some MCU's would allow me to distribute firmware updates via CANbus packets (I realise the the protocol is limited to 8 bytes per frame).

I am thinking I could transfer the code in 8 byte blocks to attached FRAM (via SPI) / EEPROM and then have the Teensy load the new code on reboot. CANbus has pretty solid CRC checking so I would know that each 8 bytes of the firmware has been successfully delivered and stored in FRAM.

Can I update firmware on the Teensy 3.5/3.6 via CANbus ? If not are there other remote ways to update the runnign firmware on a Teensy ?
 
PJRC only supports Teensy sketch update over the USB port.

Others have managed to do code flash updates on T_3.2 - but not seen any notes pass by on T_3.5/3.6 yet?
 
Ok thanks. I’ll have to look at ESP32 and STM32 to see if this is possible on them. It’s a shame because I really wanted to be able to support Paul’s product.
 
I don't think any of the popular MCU's support uploading code through CAN out of the box. You will need to write you own bootloader for this, just like Paul has done to support uploading code through USB.
 
OK - I understand however it is pretty limiting. Anyone who wants to remote deploy one of these then can't manage firmware updates to their code remotely. I have to send someone to site with a laptop and USB cable.
 
OK - I understand however it is pretty limiting. Anyone who wants to remote deploy one of these then can't manage firmware updates to their code remotely. I have to send someone to site with a laptop and USB cable.
And now you have an CAN bus between your desk and all your remote devices? :)
 
Hi

I had a play with firmware flashing on the teensy 3.6, I found I got quite a few lock ups during the moving of the flash from top halve to bottom halve.
This only happened when I was compiling the code for cpu speeds higher than 120MHz (like the default 180MHz).

I was able to fix that by making a local copy of the functions (they are in mk20dx128.c):

Code:
kinetis_hsrun_disable()
kinetis_hsrun_enable()

and adding the

Code:
RAMFUNC

to the front of them. Like this:

Code:
#if defined(HAS_KINETIS_HSRUN) && defined(__MK66FX1M0__) && F_CPU > 120000000

// This reduce the cpu frequency to 120MHz and disable the HSRUN mode (high speed).
// This is copied from mk20dx128.c and added the RAMFUNC attrib to make sure its run from RAM.
RAMFUNC int kinetis_hsrun_disable_RAM(void)
{
	if (SMC_PMSTAT == SMC_PMSTAT_HSRUN) {
		// First, reduce the CPU clock speed, but do not change
		// the peripheral speed (F_BUS).  Serial1 & Serial2 baud
		// rates will be impacted, but most other peripherals
		// will continue functioning at the same speed.
#if F_CPU == 240000000 && F_BUS == 60000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 3, 1, 7); // ok
#elif F_CPU == 240000000 && F_BUS == 80000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok
#elif F_CPU == 240000000 && F_BUS == 120000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 7); // ok
#elif F_CPU == 216000000 && F_BUS == 54000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 3, 1, 7); // ok
#elif F_CPU == 216000000 && F_BUS == 72000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok
#elif F_CPU == 216000000 && F_BUS == 108000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 7); // ok
#elif F_CPU == 192000000 && F_BUS == 48000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 3, 1, 7); // ok
#elif F_CPU == 192000000 && F_BUS == 64000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok
#elif F_CPU == 192000000 && F_BUS == 96000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 7); // ok
#elif F_CPU == 180000000 && F_BUS == 60000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok
#elif F_CPU == 180000000 && F_BUS == 90000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 7); // ok
#elif F_CPU == 168000000 && F_BUS == 56000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 5); // ok
#elif F_CPU == 144000000 && F_BUS == 48000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 5); // ok
#elif F_CPU == 144000000 && F_BUS == 72000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 5); // ok
#else
		return 0;
#endif
		// Then turn off HSRUN mode
		SMC_PMCTRL = SMC_PMCTRL_RUNM(0);
		while (SMC_PMSTAT == SMC_PMSTAT_HSRUN); // wait
		return 1;
	}
	return 0;
}

RAMFUNC int kinetis_hsrun_enable_RAM(void)
{
	if (SMC_PMSTAT == SMC_PMSTAT_RUN) {
		// Turn HSRUN mode on
		SMC_PMCTRL = SMC_PMCTRL_RUNM(3);
		while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) { ; } // wait
													 // Then configure clock for full speed
#if F_CPU == 240000000 && F_BUS == 60000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 7);
#elif F_CPU == 240000000 && F_BUS == 80000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 7);
#elif F_CPU == 240000000 && F_BUS == 120000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 7);
#elif F_CPU == 216000000 && F_BUS == 54000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 7);
#elif F_CPU == 216000000 && F_BUS == 72000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 7);
#elif F_CPU == 216000000 && F_BUS == 108000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 7);
#elif F_CPU == 192000000 && F_BUS == 48000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 6);
#elif F_CPU == 192000000 && F_BUS == 64000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 6);
#elif F_CPU == 192000000 && F_BUS == 96000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 6);
#elif F_CPU == 180000000 && F_BUS == 60000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 6);
#elif F_CPU == 180000000 && F_BUS == 90000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 6);
#elif F_CPU == 168000000 && F_BUS == 56000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 5);
#elif F_CPU == 144000000 && F_BUS == 48000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 4);
#elif F_CPU == 144000000 && F_BUS == 72000000
		SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 4);
#else
		return 0;
#endif
		return 1;
	}
	return 0;
}
#else // HAS_KINETIS_HSRUN && F_CPU > 120000000
__attribute__((always_inline)) static inline int kinetis_hsrun_disable_RAM(void) { return 0; }
__attribute__((always_inline)) static inline int kinetis_hsrun_enable_RAM(void) { return 0; }
#endif

The problem seemed to have been that those functions (which are only used at cpu speeds > 120MHz) were running from flash memory (which is getting overwritten).

Does anybody know how to push a function into ram and then run it from there without having to make a copy?
 
Hi, I realize this is quite an old post.

But I have managed to build a CAN bootloader that also works on teensy3.2 (and stm32f373)
It's part of a bigger project.

If anyone finds it interesting its located here:
https://github.com/mumme74/CarTransporter/tree/master/firmware/bootloader

Although I have tested it, I'm sure there more are issues to find:cool:

It works differently from PhotosyncQ. It can not overwrite the config bytes in lower part of flash.
Reason for this is that the bootloader is a normal Teensy program, but with a custom linkscript.
It takes 12Kb of the lower part of flash, that can not be occupied by your normal program.

When you compile a program for use with this bootloader you must compile against a custom linkscript.
https://github.com/mumme74/CarTransporter/blob/master/firmware/suspension_ECU/mk20dx256.ld

Otherwise your program.bin will have wrong adressess internally and it wont work.

To upload, download, erase etc via CAN bus, you use the host program in folder firmware/bootloader/bootloader-host/* which is a commandline program.
I have tested with raspberrypi industrialberry CAN board through socketcan, and also with Lawicell CANUSB adapter.

Sorry for my bad english, Swedish is my native tongue.
 
Status
Not open for further replies.
Back
Top