Sunday, 23 October 2016

Custom bootloader for STM32F072RB (ARM Cotex M0)

Need for Custom Bootloader

Like every software embedded firmwares written can have bugs, especially in cases where we are doing rapid development. Extra challenge in the field of IoT is that the devices on which firmware is installed can be anywhere in the world, or maybe in space ?  
So we need the ability to update the firmware on these devices remotely, for this we write a piece of code which is robust (and never changes) and is programmed only once on the devices and this program is first to run after system reset, also this program is responsible for updating the firmware of the device. This program is called bootloader.

Architecture Of Bootloader

In this post we will be using STM32F072, an ARM cotex m0 microcontroller with 128K flash. Below is the memory map of this microcontroller.
en.DM00090510-page-045 (1).jpg

After a reset, this microcontroller fetchs instructions from address 0x0000 0000. This MCU has the capability to remap address 0x0000 0000 to the flash, RAM or system memory which is the embedded bootloader. This means that if the RAM is remapped to 0x0000 0000, accessing address 0x0000 1000 is the same as accessing address 0x2000 1000. After a reset, by default, internal flash is remapped to 0x0000 0000. If no data is programmed in the first address, the microcontroller will remap system memory and then execute internal bootloader automatically. Internal flash memory starts at address 0x08000000, so for our bootloader to be able to execute first after reset it needs to be located at address 0x08000000 which is the beginning of flash. Hence we will be configuring our IDE to link bootloader code at this address.

Below is the image describing how we will be distributing the flash among bootloader and application firmware.

First 32KB starting from 0x08000000 we will be reserving for bootloader. Next 16KB from 0x08008000 to 0x0800c000 we will be using to store some configuration flags like application firmware start address, version of current firmware etc. Now here is something different, we will be using two different address spaces for application firmware (Firmware 1 and Firmware 2). We will be doing so to avoid need of external flash/storage. And our flow will be something like this:
  • If currently the application firmware is in Firmware 1 area then we will download new firmware in Firmware 2 area, and vice versa.
  • After successfully writing new firmware at respective location, we will set the appropriate values of configuration flags so that bootloader executes the new firmware.
One drawback of using two different address space for application firmware is that we will have to manage application firmware for two different address space and device should download the appropriate address space firmware.

Restricting Address Space of Bootloader In Keil

We will be using first 32 KB of address space starting from 0x08000000 for bootloader. To configure this right click on root folder in project and click Options for Target ..
keil _ option.png
In the Target tab set Start value of IROM1 to 0x08000000 and Size to 0x8000 and click OK.
keil option.PNG
Now linker will use first 32KB of address space for bootloader.

Invoking Application Firmware from Bootloader

To invoke application firmware from bootloader following step are needed:
  • Disable all the interrupts.
  • Set main stack pointer to start of application firmware (0x0800c000 or 0x08018000 in our case)
  • Invoke the function at address pointed by start of application firmware + 4

Below is a code snippet which invokes the application firmware starting at address ApplicationAddress
if (checkApplicationAddress((*(__IO uint32_t*)APPLICATION_START_ADDR_PTR)))
   // Jump to user application
   JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
   Jump_To_Application = (pFunction) JumpAddress;
   // Initialize user application's Stack Pointer
   __set_MSP(*(__IO uint32_t*) ApplicationAddress);

Things to take care in application firmware

Interrupt Vector Table

First thing which we need to take care of in application firmware is to update the Interrupt Vector Table which is first 192 bytes of memory starting from 0x00000000 with first 192 bytes of application firmware. Vector table starts from address 0x00000000, to change it on Cortex M0 devices we copy the Vector Table from Flash to RAM starting from address 0x20000000. Then we use SYSCFG_MemoryRemapConfig to copy the values at address 0x00000000 from embedded SRAM starting at 0x20000000. Below is a code snippet to reconfigure vector table with that of firmware starting at FIRMWARE_START_ADDR.
void Remap_Table(void)
 // Copy interrupt vector table to the RAM.
 volatile uint32_t *VectorTable = (volatile uint32_t *)0x20000000;
 uint32_t ui32_VectorIndex = 0;
 for(ui32_VectorIndex = 0; ui32_VectorIndex < 48; ui32_VectorIndex++)
   VectorTable[ui32_VectorIndex] = *(__IO uint32_t*)((uint32_t)FIRMWARE_START_ADDR + (ui32_VectorIndex << 2));
 //  Enable SYSCFG peripheral clock
 // Remap RAM into 0x0000 0000

Address Space (Flash and RAM)

We will have to configure the address space of application firmware just like bootloader. For firmware 1 address space set IROM1 Start address to 0x0800C000 and Size to 0x8000. Also since first 192 byte of RAM we will be using to map the vector table therefore we need to make sure that it is not used by application firmware so set the IRAM1 Start value to 0x200000C4 and Size to 0x3F3C.
keil option 3.PNG
For firmware 2 address space set Start of IROM1 as 0x08018000 and Size to 0x8000. keil option2.PNG

References :-

Sunday, 11 September 2016

Interface XBEE with Arduino without shield

Some of the points which needs to be taken care of while interfacing XBEE with arduino are:
  • XBEE operates at 3.3V logic.
  • 3.3V supply on most of the Arduinos are not capable of supplying enough current to XBEE.
Solution to logic level problem is you can convert logic level of arduino at 5V to 3.3V.
For example in below schematic a n-channel mosfet(2n7000) is used to convert 5V logic of TX line of arduino to 3.3V. Converting 3.3V TX line of XBEE to 5V is not required as it's high and low signals are distinguishable on 5V input also.

For 3.3V supply you can convert 5V supply of arduino(5V Vcc of arduino is capable of supplying ~100mA current) into 3.3V using voltage regulator or use another power supply to fed 3.3V to xbee.

Below is complete breadboard diagram of how to interface XBEE with Arduino uno using 2n7000 n-channel mosfet and using LD1117 3.3V voltage regulator to supply 3.3V to XBEE.