The tinyK22 board (see “tinyK22 Boards arrived“) gets rolled out at the Lucerne University of Applied Sciences and Arts, so I thought I write-up an article this weekend how to use that board with a Flash Resident Bootloader.
This article describes how to program and use the NXP K22 with a flash resident bootloader. I tried to keep this article as much generic as possible, so you can use any other Eclipse based IDE (DIY, Kinetis Design Studio or the NXP MCUXpresso IDE). For the example project and sources used, see the link to GitHub at the end of this article.
💡 If you are interested in another very good open source bootloader, check out the μTasker project page (http://www.utasker.com/kinetis/tinyK22.html). That bootloader offers MSD loading and much more and is much smaller too.
USB HID Bootloader
A bootloader based on USB HID is a cool way to load applications on a microcontroller. For USB HID no special drivers are needed for a Windows/Mac/Linux host as USB HID drivers are part of the host operating system. The downside is that USB is a rather complex protocol, thus requires USB Hardware and a USB stack on the target device.
I ported the presented project from the NXP KBOOT and as well using the utilities that come with that package. The implemented bootloader is a flash resident bootloader. This means initially I program the microcontroller with the bootloader and it remains in flash and then is used to load any application I want. With optimization -O1 set, I have a USB HID bootloader which uses around 26 KBytes of FLASH.
The screenshot below shows the bootloader project structure.
- link: contains the linker file. The bootloader vector table and address is mapped to 0x0000’0000 which is the default vector table for ARM Cortex-M
- MK22F51212: contains the hardware specific port to the Kinetis K22 microcontroller. The bootloader_config.h file in this folder is used to configure the bootloader.
- src: contains all the bootloader sources which are pretty much generic
Bootloader Project Defines
The project uses a few global defines to configure the bootloader:
The above defines disable extra debug messages, set the USB stack to be bare-metal (no RTOS used), configures the device (MK22 and ARM Cortex-M4). The last define configures the bootloader to be FLASH resident.
The header file MK22F51212\bootloader_config.h is used to configure the bootloader, for example which communication protocols are supported. In the setting below I’m configuring it to use USH HID only:
#if !defined(BL_CONFIG_SCUART) #define BL_CONFIG_SCUART (0) #endif #if !defined(BL_CONFIG_I2C) #define BL_CONFIG_I2C (0) #endif #if !defined(BL_CONFIG_DSPI) #define BL_CONFIG_DSPI (0) #endif #if !defined(BL_CONFIG_USB_HID) #define BL_CONFIG_USB_HID (1) #endif #if !defined(BL_CONFIG_USB_MSC) #define BL_CONFIG_USB_MSC (0) #endif #if !defined(BL_TARGET_FLASH) #define BL_TARGET_FLASH (1) #endif
The more or the more complex communication protocols are used, the more FLASH memory is occupied by the bootloader. With the USB HID enabled, the size is around 26 KByte of FLASH it fits into the memory area below 0xb000 (see “text, data and bss: Code and Data Size Explained“) how to read the output below.
arm-none-eabi-size --format=berkeley "tinyK22_KBOOT_bootloader.elf" text data bss dec hex filename 26204 1856 14000 42060 a44c tinyK22_KBOOT_bootloader.elf
For example if I would communicate to the bootloader with UART, it would only need 21 KByte of FLASH memory.
The bootloader can use a GPIO pin to enter bootloader mode after a reset (e.g. POR, Power-On-Reset). Which pin is used is configured in MK22F51212\hardware_init_K22F512:
#define BOOT_PIN_NUMBER 17 #define BOOT_PIN_PORT PORTB #define BOOT_PIN_GPIO GPIOB #define BOOT_PIN_ALT_MODE 1
With the above code, I’m using the GPIO Pin PTB17. The function is_boot_pin_asserted() is used to check that pin. Typically this pin is pulled HIGH by a pull-up and pulling it to LOW during startup I will enter bootloader mode.
If not using any bootloader pin, I can configure the bootloader timeout specified in bootloader_config.h:
#define BL_DEFAULT_PERIPHERAL_DETECT_TIMEOUT 5000
With the above setting, after reset it will wait for 5 seconds for any communication from the host until the bootloader proceeds. If such a timeout is not desirable, then I recommend to configure a dedicated bootloader pin.
Another setting in the bootloader_config.h is where the vector table of the application resides. Basically this defines where my application FLASH memory space starts. Below I have set it to 0xC000 which means that the bootloader can use 0x0000 up to 0xBFFF.
// The bootloader will check this address for the application vector table upon startup. #if !defined(BL_APP_VECTOR_TABLE_ADDRESS) #define BL_APP_VECTOR_TABLE_ADDRESS 0xc000 #endif
Programming the bootloader
The bootloader needs to be programmed with a SWD/JTAG debug probe (e.g. Segger J-Link, P&E Multilink or CMSIS-DAP) to the microcontroller.
Stopping the bootloader with the debugger shows that it waits for incoming USB packets:
Building an Application to be loaded with the Bootloader
An application to be loaded with the bootloader needs to be linked at the correct address, where the bootloader expects it. As discussed above, I have my application start address (actually its vector table address) at 0x0000’C000.
With that linker file I create the S19 and/or the binary file of the application which I want to load with the bootloader. See “Binary (and S19) Files for the mbed Bootloader with Eclipse and GNU ARM Eclipse Plugins” and “MCUXpresso IDE: S-Record, Intel Hex and Binary Files” how to create S19 or binary files with GNU tools.
Connecting to the bootloader
KBOOT (see links at the end of this article) includes two utilities to communicate with the bootloader:
- blhost: command line utility
- KinetisFlashTool: Same as above, but with a GUI
Connect to the USB HID Bootloader using the 0x15A2 for VID and 0x0073 as PID:
💡 Note that I need to the the bootloader needs to be active for the Connect!
If that succeeds, it will show me the bootloader information:
The same way the blhost utility can be used to connect to the device on the command line (the USB VID/PID is optional):
blhost --usb 0x15a2,0x0073 -d get-property 1
Once connected, I can update the binary using the bootloader. As the binary file does not contain any destination address information, I have to specify this in the dialog (0x0000c000, as this is where my application starts with its vector table):
The same thing can be accomplished using the blhost command line:
In order to program the flash, it *must* be erased first:
blhost --usb -- flash-erase-region 0xC000 0x12000
If you get an error like the one below, then most likely the FLASH has not been erased first:
usbhid: received data phase abort status = 105 (0x69) kStatus_FlashCommandFailure
To load a binary file to address 0xc000:
blhost --usb 0x15A2,0x0073 write-memory 0xC000 tinyK22_KBOOT_led_blinky_1Hz_0xC000.bin
For loading S19 files the flash-image command is used:
blhost --usb 0x15A2,0x0073 flash-image tinyK22_KBOOT_led_blinky_1Hz_0xC000.srec
reset the board, and the new application is running 🙂
A flash resident bootloader is a bootloader which I can configure and program into the FLASH memory of the microcontroller. I can configure it for the communication protocol to be used to the outside world (USB HID in this case) and then connect either with a GUI or command line tool to the device and update the application. This is especially useful if I have devices in the field and I have to update them with a new firmware without the need for a debugger.
Happy Bootloading 🙂
- Sources on GitHub: https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/tinyK22
- NXP KBOOT web page: http://nxp.com/KBOOT
- tinyK22 Boards arrived
- First tinyK22 Board with NXP K22FN512 ARM Cortex-M4F
- Getting Started: ROM Bootloader on the NXP FRDM-KL03Z Board
- Serial Bootloader for the Freedom Board with Processor Expert
- μTasker project for the tinyK22: http://www.utasker.com/kinetis/tinyK22.html