dongiac / Can-bus-Bootloader

Testing OpenBLT on stm32f303k8 for firmware update via can-bus
1 stars 1 forks source link

Can-Bus Firmware Update STM32

Why?

Since we've built our own PCBs, the actual programming routine needs to take out each node and code it with the st-link via USB. This, in race condition, needs too much time to be applied. The idea is to leave the nodes attached to the car, and with the help of the LAWICEL CANUSB (can to usb interface) and Microboot (software updater) we can easily update them.

How?

This is achievable with the help of a bootloader inside the memory of each node.

Bootloader

The bootloader is itself a program inside the memory of the microprocessor. Bootloaders usually provide a method of flashing new code to the device and initialize the hardware before running the main program.

This is possible due to the fact that the bootloader and the user program are isolated from themselves.

Bootloader memory

At every reset (hardware or software) the bootloader runs and check if a new code is available.

Bootloader General cycle

STM32F303K8 Bootloader

Datasheet: stm32f303k8

For this purpose, since we will use the Nucleo-stm32f303k8, we will see how is possible to use a bootloader for this Microprocessor.

The first thing to know is that all the nucleo by the ST have their own bootloader by factory (Not only the nucleo, but also the single mcu made by ST). The chip it's the ARM Cortex-M4, nevertheless buying it from ST company, it will have some default setting.

For us is impossible to modify this bootloader, the idea is to put a "layer program" in the flash memory before the user program.

Nucleo memory map

From the image above we can see that the factory bootloader is for sure in the early memory pages from 0x0000 0000 to 0x0001 0000, and we can not access this location.

We will use the 64KBytes of the higher Flash Memory (from 0x0800 0000 to 0x0801 0000).

In the Boot program, opening the linker script (Demo\Boot\STM32F303K8TX.ld) we will set the start from 0x0800 0000 and LENGTH = 8K.

Meanwhile in the Prog program, opening the linker script (Demo\Prog\STM32F303K8TX.ld) we will set the start 8KBytes later, so it starts from 0x0800 2000 and LENGTH = 64K - 8K.

OpenBLT

This is an open source Bootloader, compatible with some microprocessor families.

OpenBLT structure

This is the general structure of OpenBLT.

The Application Specific have the function to modify the bootloader based on project specific needs. Here we can find the main() function, bootloader configuration file and hook functions. (Here we can enable the backdoor or handling watchdogs timers).

The Target Independent is the core of the bootloader, for our purpose. It handles the data transfer from the firmware file to the microcontroller's memory. We don't have the need to modify this part. This works with XCP protocol by ASAM, here can be found more information.

The Target Dependent is the only part that need some changes when porting the bootloader to a new microcontroller. It contains the low-level drivers for accessing the communication, timer and memory peripherals. Then there is a sub-part of the target dependent which is the Compiler Specific; It contains code such as the c-startup routine and the interrupt vector table, which typically needs a little compiler magic to link to the correct memory location.

Detailed bootloader structure

Can-Bus

The Controller Area Network is the protocol of a specific bus used mainly in the automotive field.

In our car, almost every node it's connected to the can-bus to have an easy and fast way to exchange information through the whole vehicle. It's based on a twisted pair of copper wire, with two 120 Ohm Resistor at both ends.

General Nodes

Each node have three fundamental parts.

CAN NODE

N.B. Each node can transmit and receive, but NOT SIMULTANEUOSLY

Communication

The CAN-Bus use two differential signals, CANH and CANL, rispectively High and Low state. Creating a "Dominant" bit when CANH>CANL and "Recessive" one in the other cases. Having a Wired-AND convenction this will give the priority to the nodes with lower ID. The can is based on a CSMA/CD+AMP. CSMA stands for Carrier Sense Multiple Access, so each node have to wait for a prescribed amount of time of inactivity, before attempting to send a message. CD stands for Collision Detection, basically a letteral meaning and Arbitration on Message Priority (Lower ID nodes have the priority).

Doing an complete explanation of the can-bus is not the purpose of this project, but knowing what it is will explain why we are going to use it as the bus for updating our nodes

Wheel Node

This are PCBs that we have made by ourselves.

MCU: STM32F3030K8

Transceiver CAN: MCP2551

External Clock: 12MHz Quartz

We can also use them for this project. The main difference between our wheel node and the nucleo is that Wheel Nodes doesn't have the programming mcu (stm32f103c8t6) so they need an ST-Link to write code in them meanwhile the nucleo have it on board so they are ready to be programmed. The bootloader will consent us to just leave the Wheel Nodes attached to the Vehicle's CAN-BUS without st-link.

What will we need?

Hardware

Software

Procedure

First step

Import Image

Once you have the project on the IDE you can modify the Boot program at your needs.

N.B If the main program need to use the external quartz clock the initialization must be made into the code not by modifying the .ioc confiuration, if this is done the openBLT will be overwritten.

Second step (If a multiple node can is used)

Since multiple nodes are connected to the can-and the XCP protocol works on a point-to-point connection between Host and Target, this will update each node with the same program! we can avoid this with this additional procedure.

Let's take a look at the connect command that XCP use to connect to the Target:

XCP Connect

FFh it's ALWAYS 0xFF, meanwhile the second part (node addr) can be anything. The idea is to use this part as a node address to identify which node needs to be updated.

Modification needed:

Now we can take care of the Program, cause the Boot is done but since in the Program we have functions that detect firmware update we want to avoid useless boot start up. So we will modify this part by cheking the Node Address.

Open the \App\boot.c

Find this lines:

 /* check if this was an XCP CONNECT command  */
     if ((rxMsgData[0] == 0xff) && (rxMsgHeader.DLC == 2))
     {
       / * connection request received so start the bootloader */
       BootActivate();
     }

And change it to:

 /* check if this was an XCP CONNECT command * /
     if ((rxMsgData[0] == 0xff) && (rxMsgHeader.DLC == 2) && (rxMsgDat[1] == BOOT_XCP_CONNECT_MODE_NODE_ADDR))
     {
       /* connection request received so start the bootloader */
       BootActivate();
     }

Rebuild project.

Third step

Now that the bootloader is ready:

Now if the led blink fast, the bootloader is active.

Last step

Now we have both the user program and Bootloader in the flash memory.