Flash-Resident USB-HID Bootloader with the NXP Kinetis K22 Microcontroller

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.

tinyK22 with USB HID Bootloader

tinyK22 with USB HID Bootloader

Outline

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.

As hardware the NXP Kinetis K22FN512 is used. This ARM Cortex-M4F microcontroller is present on the tinyK22 board as well on the NXP FRDM-K22F board.

Blinky on a FRDM-K22F with SDK V2.0 and Processor Expert

tinyK22 with USB HID Bootloader

tinyK22 with USB HID Bootloader

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.

Project Structure

The screenshot below shows the bootloader project structure.

bootloader project

bootloader project

  • 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:

Bootloader Defines

Bootloader Defines

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.

Bootloader Configuration

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
tinyK22 Pinout

tinyK22 Pinout

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:

USB HID Bootloader waiting for USB packets

USB HID Bootloader waiting for 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.

Linker File Mapping Application at 0xC000

Linker File Mapping Application at 0xC000

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.

Memory Map with Bootloader and Application

Memory Map with Bootloader and Application (adopted from FTF-DES-F1299.pdf)

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:

Connect to USB HID Bootloader

Connect to USB HID Bootloader

💡 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:

connected with USB HID Bootloader

connected with USB HID Bootloader

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 - get-property 1
blhost with USB HID Bootloader

blhost with USB HID Bootloader

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):

Update with new binary

Update with new binary

The same thing can be accomplished using the blhost command line:

To load a binary file to address 0xc000:

blhost.exe --usb 0x15A2,0x0073 write-memory 0xC000 tinyK22_KBOOT_led_blinky_1Hz_0xC000.bin
loading binary file

loading binary file

For loading S19 files the flash-image command is used:

blhost.exe --usb 0x15A2,0x0073 flash-image tinyK22_KBOOT_led_blinky_1Hz_0xC000.srec
loading S19 file

loading S19 file

reset the board, and the new application is running 🙂

Summary

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 🙂

Links

Advertisements

14 thoughts on “Flash-Resident USB-HID Bootloader with the NXP Kinetis K22 Microcontroller

  1. Hi Eric

    Please take a look at http://www.utasker.com/kinetis/tinyK22.html where I have added a simulation of your board and made a USB-MSD loader for it, which is usually more convenient that the KBOOT HID one. It allows simple connection (no driver installation) and drag-and-drop on Windows, macOS X and Linux [without needing to install and learn any program on the PC either]. Each time the board starts in the boot loader it displays the loaded program (with its size, date etc.) and allows it to be read back – also drag-and-drop – with optional password protection on the read-back operation.

    As you will see from the file size it is also more memory efficient that the Kboot code – it needs 14.4k (about 55% of the Kboot one) of flash.

    I also have a version there which supports loading either binary, SREC or iHEX formation (it detects and decodes each automatically) which is slightly larger [15.4k] but still less that 60% the Kboot’s memory footprint.

    Regards

    Mark

    Like

    • Hi Mark,
      thanks for that page and port to the tinyK22, I’m sure my students will love that version too! I tried out the uTasker bootloader and demo apps with the tinyK22, and it works great.
      About the size: I did not optimize the KBOOT version because on that device I have plenty of space available, but for sure for more memory restriced devices saving a few KBytes can make a big difference.
      In my view, the MSD bootloader is very handy, but I usually prefer for ‘real’ applications in the field a serial one (which your uTasker) includes too. There is far too much danger and and possibilities what can go wrong with USB MSD interfaces. Maybe I had too many bad experiences in the past. So I prefer a controlled (e.g. UART) way. The KBOOT USB HID is still somewhat problematic as it requries that special tool or command line interface on the host, but has worked fine so far in the field.

      Thanks again,
      Erich

      Like

      • Hi Eric

        I just added a version that does USB-MSD and Kboot-HID as composite USB device, plus UART (SREC/iHex) loading on PTE0 and PTE1 at 115200 Baud [21.4k].
        This means that it should satisfy all tastes.

        Note that I never had any USB loading problems after several years in many commercial products and in my experience USB-MSD tends to be the preferred method (quite rare UART nowadays, SD-card and USB-memory stick possibly second place). I never heard of Kboot being used for commercial products – I use it only for factory programing of things like KL27 but only to install a more flexible solution for later field use.

        I am also happy to hear that the loader and application worked since I don’t have your board so could only simulate it. It took about 2 hours to port and simulate the loader and application for the HW and create a web page with downloads, so I was taking a chance in publishing binaries that hadn’t been used before…. 😉

        Regards

        Mark

        Like

  2. Hi Erich,
    Its good to see this USB HID bootloader in KBOOT working with MCUXpresso , I had tried it a while ago with a Freedom board and KDS but was not convinced by the results I learned that IAR was used to compile it originally. A USB HID bootloader could be very appropriate if your developing a product destined to be used by the masses that could provide firmware updates since the HID driver is native to windows and all you need is a standard USB cable.
    Using serial ports is OK if you know what one is, using virtual COM ports sometimes requires going into device manager to determine if you have the right port and USB MSD requires more user interaction – to drop the firmware update file onto the right drive. In my evaluation of KBOOT I thought it would be great if there was a stripped down version that just supported USB HID.
    Best regards
    Chad

    Like

      • Hi Erich,
        for sure it would require adapting the bflwkdll library thats used by the Kinetis flash tool and integrating it into a custom windows application if that can be done.
        Chad

        Like

    • Chad

      USB-MSD comes up with a disk with the name of the board (or whatever one wants it to come up with) so not a lot can go wrong. I use USB-MSD in many commercial devices (hundreds of thousands or possibly > million such in the field) and there are no know issues.

      I just changed the disk name to show as “TINYK22” rather than “UPLOAD_DISK”.

      I also added a new loader version which performs USB-MSD and Kboot (as composite USB device), plus UART SREC/iHEX on pins PTE0 and PTE1. This means that it should satisfy everyone since the method can simply be chosen as desired (21.4k Flash size).

      Regards

      Mark

      P.S: Builds with CW, KDS, MCUXpresso, Keil uVision, IAR, Standalone GNU make file (which I tend to use for speed and simplicity), Visual Studio, S32 Design Studio, Rowley Crossworks, CooCox, Green Hills and Atollic TrueSTUDIO.

      Liked by 1 person

  3. Pingback: Tutorial: CRC32 Checksum with the KBOOT Bootloader | MCU on Eclipse

  4. Pingback: Converting Binary Files to Intel Hex Format with the SRecord Tool | MCU on Eclipse

  5. Hello Erich, My application is similar to this except that the Kinetis is the host microcontroller which has access to the .bin file that is supposed to go into the application section of the target microcontroller(ATmega88) which has its own bootloader. I would like to transmit the said .bin file through UART to the Atmega88 controller.and test my bootloader also in this process. I am using MKV10Z32xx Kinetis micro as the host and PE to write code. I am also using the SDK. A litlle nudge in the right direction would be helpful.
    Thanks.

    Like

      • I have the hex file also for the application to be coded on the Atmega88. I have the bootloader also on the Atmega88. All the KV has to do is read information from the hex file store it in a buffer and then send that buffer over through UART to be written on the Atmega88.
        I am unsure how the .hex/.bin/srec file needs to be sent through UART? Is there a sample code for me to look at that does this?
        Thanks

        Like

        • With the UART you can send any data or bytes, nothing special needed. You can use any sample code for this which sends something to the UART, so there won’t be any special app note for binary data.

          Like

  6. Hello Erich,
    I tried reading the intel hex file using fopen command in KDS and somehow the code doesnot open the intelhex file. I have the code snippet attached here.

    The functions used here are load_file and parse_hex_line.
    What it does is it opens the hex file that is to flashed on the target and takes the address and data bytes in separate buffers and saves them. This code compiles on an online C compiler and gives me a result that says that so many bytes have been saved in this buffer. What I want to do is to transmit the said buffer to the target microcontroller. When I try debugging this on KDS, the problem is that the code gets stuck on fopen line.

    Is there a way to debug this?

    int main(int argc, char** argv)
    /*lint -restore Enable MISRA rule (6.3) checking. */
    {
    int parse_hex_line(theline, bytes, addr, num, code)
    char *theline;
    int *addr, *num, *code, bytes[];
    {
    int sum, len, cksum;
    char *ptr;

    *num = 0;
    if (theline[0] != ‘:’) return 0;
    if (strlen(theline) < 11) return 0;
    ptr = theline+1;
    if (!sscanf(ptr, "%02x", &len)) return 0;
    ptr += 2;
    if ( strlen(theline) > 8) & 255) + (*addr & 255) + (*code & 255);
    while(*num != len) {
    if (!sscanf(ptr, “%02x”, &bytes[*num])) return 0;
    ptr += 2;
    sum += bytes[*num] & 255;
    (*num)++;
    if (*num >= 256) return 0;
    }
    if (!sscanf(ptr, “%02x”, &cksum)) return 0;
    if ( ((sum & 255) + (cksum & 255)) & 255 ) return 0; /* checksum error */
    return 1;
    }

    void load_file(filename)
    char *filename;
    {
    char line[1000];
    FILE *fin;
    int addr, n, status, bytes[256];
    int i, total=0, lineno=1;
    int minaddr=65536, maxaddr=0;

    fin = fopen(filename, “r”);
    while (!feof(fin) && !ferror(fin)) {
    line[0] = ‘\0’;
    fgets(line, 1000, fin);
    if (line[strlen(line)-1] == ‘\n’) line[strlen(line)-1] = ‘\0’;
    if (line[strlen(line)-1] == ‘\r’) line[strlen(line)-1] = ‘\0’;
    if (parse_hex_line(line, bytes, &addr, &n, &status)) {
    if (status == 0) { /* data */
    for(i=0; i<=(n-1); i++) {
    mem[addr] = bytes[i] & 255;
    total++;
    if (addr maxaddr) maxaddr = addr;
    addr++;
    }
    }
    if (status == 1) { /* end of file */
    fclose(fin);
    printf(” Loaded %d bytes between:”, total);
    printf(” %04X to %04X\n”, minaddr, maxaddr);
    return;
    }
    if (status == 2) ; /* begin of file */
    } else {
    printf(” Error: ‘%s’, line: %d\n”, filename, lineno);
    }
    lineno++;
    }
    }

    load_file(“BlinkTest.hex”);

    Like

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.