HID boot loader (referencing AN4764)

cancel
Showing results for 
Search instead for 
Did you mean: 

HID boot loader (referencing AN4764)

2,634 Views
mjbcswitzerland
Specialist V

Hi All

 

I have been monitoring with interest the new Kinetis boot loader developments and also the HID loader as detailed in the application note AN4764.

For those who don't know it, the AN4764 HID loader is a small piece of code which allows Kinetis (and some other families of devices) to be programmed via USB (HID class) from a small PC application (HIDBootloader.exe), which is included in the software belonging to the application note. The SW includes loaders for a few Kinetis types and these are small, occupying just 4k Flash space.

 

So I decided to see whether it would be difficult to support the Freescale "HIDBootloader.exe" program in the uTasker serial boot loader. After about 4 hours work it was possible to use this program to load any KL or K device.

 

However the idea is not to replace the small 4k HID loader in the AN4764 package but instead to allow it more flexibility (if and when needed). For this reason, and also to make development and maintenance simpler and more efficient, the uTasker OS and generic USB stack was used (the development could also be performed in the uTasker simulator, which made is fast). The result is a bigger code size of about 10k for the HIB loader but with a number of advantages when the code size is not critical:

- builds on all K and KL devices and boards (it also builds in Coldfire V2 projects if of interest)
- builds with GCC, KDS, IAR, Keil, Rowley Crossworks, Atollic, CooCox CoIDE or CodeWarrior 10.x (therefore no missing device/board support)

- automatic program end recognition and application startup, plus adjustable operation displays (like LEDs showing state and SLCD messages, etc.)
- simpler to modify and customise

- can be combined with other loaders (eg. HID loader and SREC and SD-card loader and Web Server loader at the same time, or any other combinations)

These are the code sizes of a few combinations that I checked:

- HID loader alone (10k)               [comparison: - USB-MSD loader 12k]

- HID loader + UART SREC loader (14k)

- HID loader + SD card loader (16k)     [comparison USB-MSD loader + SD card loader 18k]
- HID loader + SD card + UART SREC (20k)

- HID loader + Ethernet Web Server loader (22k)     [comparison - Ethernet Web Server loader alone (16k)]
- HID loader + UART SREC + Ethernet Web Server loader (26k)

 

For anyone interested, I have attached a zip file containing code for the FRDM-KL25Z and TWR-K60F120 (two popular but quite different beasts).

- In the directory FRDM-KL25Z there is an *.imp file for configuring the PC program for the board, plus a boot loader binary for the board and an application that can be loaded via the PC tool. The boot loader shows both HID via USB (for the PC program) and SREC on its UART (via OpenSDA) [short J1-pin 6 to GND to force the boot loader mode at reset]

- In the directory TWR-K60F120 there is an *.imp file for configuring the PC program for the board, plus a boot loader binary for the board and an application that can be loaded via the PC tool. The boot loader shows HID via USB (for the PC programn) plus SREC UART on the tower SER board, as well as Ethernet Web Server loader on address 192.168.0.125. The application (when loaded either using a web browser or the HID loader PC tool will move to IP 192.168.0.3. [hold SW2 to force the boot loader mode at reset]

 

Personally I find combining Ethernet Web server (when the board has Ethernet) and a local method (like HID loading with the Freescale PC program) to be interesting since it gives remote and local loading support. Combining different local methods then caters for personal taste as to which method is preferred.

 

 

Now I am however a little worried about the PC tool. My feeling is that it is probably not going to be further developed due to the newer FSL program that will become available (which I can't get working on my PC yet though) and it presently has a few issues:
- crashes when attempting to delete flash on a board that is not attached
- loads old SREC content if the path is not re-selected when the SREC on disk changes

 

But it is otherwise fast and usable.

 

The final issue that is worrying is that the VID/PID that the connected device uses "should" be configurable in the *.imp file but if any combination apart from Freescale's

VendorID=0x15A2

ProductID=0xFF03

is attempted the program also crashes.

 

This means that I am presently (forced to) setting these values in the HID bootloader.

 

Therefore I would like to ask Freescale whether this is acceptable and/or whether the PC program could be slightly improved to make it a good tool for Kinetis users with an interest in using its capabilities?

 

Thanks!

 

Mark

Original Attachment has been moved to: HID_Loader.zip

16 Replies

517 Views
NVazquez
Contributor III

@mjbcswitzerland I am trying to use the Freescale HID bootloader. I am new to USB HID. I am using LPC54016 custom board. Any help is really appreciated. 

What all things do I need to include in the .imp file? Can I get the source code for it? Can I use "HID generic" software on the controller side?

0 Kudos

511 Views
mjbcswitzerland
Specialist V

Hi

I doubt that the LPC54xx code base supports the Freescale HID bootloader and so in order to be able to use it you would need to develop it.
Probably it makes sense to use whatever is standard for the LPC54xx if you don't want to have to re-develop a solution.

Regards

Mark

 

0 Kudos

502 Views
NVazquez
Contributor III

Thank you for your quick response!

 

Can you tell me what is standard for LPC54xx controller?

I can try to develop Freescale HID bootloader, where can I find the source code for it?

0 Kudos

497 Views
bobpaddock
Senior Contributor III

You would be better severed porting TinyUSB to the LPC than dealing with Freescales mess of USB code.

I've got it up on the KL27 and working on getting it on the K32 now.  Found it far more stable in good connections than the Freescale code on marginal hardware.

TinyUSB has KL25 example in the standard distribution.

https://docs.tinyusb.org/en/latest/

0 Kudos

445 Views
NVazquez
Contributor III

@bobpaddock Thank you for your reply. 

I am using a custom board consisting of LPC54xx controller. Do you think it would be still easier to use, tinyUSB than Freescale? I have never worked on bootloader, so bootloader with HID sounds intimating to me already.

0 Kudos

443 Views
bobpaddock
Senior Contributor III

If you have the choice of working with the Freescale USB stack or the TinyUSB stack do TinyUSB.
Only reason to use Freescale is if there is some canned demo that already works for you.

If memory serves the LPC family never was part of Freescale, so porting Freescale code to LPC is already porting foreign code to the LPC.


The concept of the bootloader is the same for any processor.

Fundamentally you have a file in some format and it needs to get into Flash as binary code in the correct memory locations.

There is the PC side, as source, and the embedded side, as destination, that needs dealt with.

There is a LPC forum section here, you may find better bootloader help there.


424 Views
mjbcswitzerland
Specialist V

Hi

Just mentioning that there is an open source solution for all Kinetis devices which supports off-the-shelf HID boot loader (according to AN4764), KBOOT, USB-MSD and various other methods according to the document
https://www.utasker.com/docs/uTasker/uTaskerSerialLoader.pdf
This is on GITHUB at https://github.com/uTasker/uTasker-Kinetis and includes support for most Kinetis devices and STM32 (see the operation on a Blue Pill, for example, at https://github.com/uTasker/uTasker-Kinetis/tree/master/Hardware)

It can also operate on LPC2xxx and LPC17xxx, where the HW code bases can be inserted into the solution from the sources:
https://www.utasker.com/forum/index.php?topic=1324.0
and
https://www.utasker.com/forum/index.php?topic=1285.0
respectively, which supplies the compatible USB device HAL.
[Also SAM7, AVR32, LM3S, Coldfire V2 HALs are available that drop in if legacy devices need to be supported, which contain compatible USB device drivers, as well as an i.MX RT HAL for modern needs].

It may be possible that the LPC2xxx/LPC17xx HALs (and their compatible USB device drivers) could be used on LPC54xx parts (directly or with tweaking, if not entirely compatible).

Regards

Mark


 

962 Views
DerekLau
Contributor IV

Hello Mark,

I figured out that the problem is the use of lower case letter for the vendor or product ID (0x03fe) in the imp file. I always use capital letter (0x03FD) and didn't notice the issue. The attached file has fixed this issue.

KBOOT

For K64F, the code in bootloader_config.h indicates that the application program's vector must start at 0xa000.

The base address in the winupdater has to be set to 0xa0000.

The linker file of the application code also needs to be changed to reflect this. (for linker file modification, please refer to our bootloader appnotes, eg: AN4764).

Please also note that you may need to use the release version if the code size of the debug one exceeds the BL_APP_VECTOR_TABLE_ADDRESS.

In bootlaoder_config.h:

/ /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 0xa000

#endif

Winupdater does support HID, you just need to select the HID-compliant device and ignore the slection at Transport.

winupdater.JPG

For I2C and SPI, addition hardware is needed as mentioned in the release note. You may take a look at AN4655. However, I am not in the Kboot's team. I will post here if I have more info about it.

962 Views
mjbcswitzerland
Specialist V

Hi Derek

Thanks for the new HIDBootloader.exe!

MBOOT:

- with UART I was loading the example application that comes with the package and I also set the offset to 0xa000 but it didn't run

- It is correct that there is an HID device that appears but this failed to load code when I first tried (trying to load the same binary). But later it worked - I found that the Base Address field where I was entering 0x0000A000 was not letting itself be written (I could select the field but not type in anything so I probably missed that and was getting errors due to the incorrect address). At some point the Base address field started working again (?) and then it was successful. [I also successfully uploaded via UART so maybe the Base Address problem caught me out the last time too(?)]

I see that the protocol used by the HID device is different to that used by HIDloader.exe but is otherwise simple to follow - it also looks to command a reset at the end so that the new code starts, which the HIDloader.exe doesn't.

Regards

Mark

0 Kudos

962 Views
mjbcswitzerland
Specialist V

Hi Derek

Since I see the HIDloader.exe as an intermediate HID loader solution to be taken over by the KBOOT I spend this afternoon studing the KBOOT HID operation in more detail and implementing a KBOOT HID mode in the uTasker project. I will be creating a new thread concerning this implementation which was succesful and verified on several targets (in particular the FRDM-K64K since it is one of the few targets presently supported by the KBOOT loader SW), the TWR-K60F120 and FRDM-KL25Z (since these boards are presently not supported, in order to verify that there are basically no incompatibilities involved on a couple of diverse devices).

I would like to point out two detals here that may be of interest (to Freescale and generally):

1. To understand the protocol I used the boot loader source code in the V1.0.1 package. The protocol has a lot of possible features although the present KBOOT utility uses only a few of them - this made it a little more complicated to implement than first expected but for SW loading compatibility with the present tool only a part of it is needed. It is however to be said that it is not that easy to follow the code to find where define sources and where handling routines are to be found due to the fact they are spread out over many files and much operation is based on function calls stored in structs - as well as driver code being partly inter-twined with application code; it is possible to follow it but needs some patience. I am also wondering about its maintainability due to its complication. [At the bottom of the post I have attached the new code that I added to the uTasker project to implement the KBOOT HID mode which shows that it is in fact quite easy to have it all in one location to make it easy to understand and maintain (although I admit to taking shortcuts for the moment and addressing directly array content since it is all fixed in the SW loading case - I expect to revisit it once more of the protocol features are enable in the PC application...]

2. I tested some application binaries of > 100k in size and found the HID loader to be painfully slow. In fact about 1/3 the speed of UART loading at 115kBaud. The HIDloader.exe operation is very fast in comparison. The OUT interrupt endpoint is set to 10ms, which means that only 32 bytes of program code can be programmed in 8ms - or 4000 Bytes / s (equivalent to a UART at about 38.4kBaud). Therefore I modified the endpoint 1 IN interrupt setting to 1ms instead so that it becomes about twice as fast as UART loading at 115kBaud. I do however wonder whether it wouldn't have been better to use a bulk transfer since the KBOOT loader will otherwise be rather slower than most other USB based loaders?

Regards

Mark

    while (fnMsgs(USBPortID_comms) != 0) {                               // reception from endpoint 2

        KBOOT_PACKET KBOOT_packet;

        KBOOT_PACKET KBOOT_response;

        uMemset(&KBOOT_response, 0, sizeof(KBOOT_response));

        fnRead(USBPortID_comms, (unsigned char *)&KBOOT_packet, sizeof(KBOOT_packet));

        switch (KBOOT_packet.ucCommandType) {

        case KBOOT_REPORT_ID_COMMAND_OUT:

            KBOOT_response.ucCommandType = KBOOT_REPORT_ID_COMMAND_IN;

            switch (KBOOT_packet.ucData[0]) {

            case KBOOT_COMMAND_TAG_GET_PROPERTY:                         // 0x07 this routine is partly prepared for multiple parameters but assumes only a single one

                {

                    int iParameters = KBOOT_packet.ucData[3];

                    unsigned long ulStatus = 0;

                    unsigned long ulValue;

                    unsigned char *prType = &KBOOT_packet.ucData[4];

                    while (iParameters--) {                              // for each requested parameter

                        ulStatus = fnHandlePropertyGet(*prType, &ulValue);

                    }

                    KBOOT_response.ucLengh[0] = 12;

                    KBOOT_response.ucData[0] = (KBOOT_packet.ucData[0] | 0xa0);

                    KBOOT_response.ucData[3] = (KBOOT_packet.ucData[3] + 1); // status plus requested parameters

                    KBOOT_response.ucData[8] = (unsigned char)ulValue;

                    KBOOT_response.ucData[9] = (unsigned char)(ulValue >> 8);

                    KBOOT_response.ucData[10] = (unsigned char)(ulValue >> 16);

                    KBOOT_response.ucData[11] = (unsigned char)(ulValue >> 24);

                }

                break;

            case KBOOT_COMMAND_TAG_WRITE_MEMORY:                         // 0x04

            case KBOOT_COMMAND_TAG_ERASE_REGION:                         // 0x02

                {

                    unsigned long ulStartAddress;

                    unsigned long ulLength;

                    ulStartAddress = (KBOOT_packet.ucData[4] | (KBOOT_packet.ucData[5] << 8) | (KBOOT_packet.ucData[6] << 16) | (KBOOT_packet.ucData[7] << 24));

                    ulLength = (KBOOT_packet.ucData[8] | (KBOOT_packet.ucData[9] << 8) | (KBOOT_packet.ucData[10] << 16) | (KBOOT_packet.ucData[11] << 24));

                    if (KBOOT_COMMAND_TAG_ERASE_REGION == KBOOT_packet.ucData[0]) {

                        if ((ulStartAddress >= UTASKER_APP_START) && (ulStartAddress < (unsigned long)UTASKER_APP_END)) {

                            if ((ulStartAddress + ulLength) > (unsigned long)UTASKER_APP_END) {

                                ulLength = ((unsigned long)UTASKER_APP_END - ulStartAddress);

                            }

                            fnEraseFlashSector((unsigned char *)ulStartAddress, (MAX_FILE_LENGTH)ulLength);

                        }

                    }

                    else {

                        ptrFlashAddress = (unsigned char *)ulStartAddress;

                        ulProg_length = ulLength;

                    }

                    KBOOT_response.ucLengh[0] = 12;                      // generic response

                    KBOOT_response.ucData[0] = 0xa0;

                    KBOOT_response.ucData[2] = 2;

                    KBOOT_response.ucData[8] = KBOOT_packet.ucData[0];

                }

                break;

            case KBOOT_COMMAND_TAG_RESET:                                // 0x0b

                uTaskerMonoTimer(OWN_TASK, (DELAY_LIMIT)(1 * SEC), TIMEOUT_RESET_NOW);

                KBOOT_response.ucLengh[0] = 12;                          // generic response

                KBOOT_response.ucData[0] = 0xa0;

                KBOOT_response.ucData[2] = 2;

                KBOOT_response.ucData[8] = KBOOT_packet.ucData[0];

                break;

            }

            fnWrite(USBPortID_comms, (unsigned char *)&KBOOT_response, sizeof(KBOOT_response));

            break;

        case KBOOT_REPORT_ID_DATA_OUT:                                   // data to be written

            {

                unsigned short usBuff_length = KBOOT_packet.ucLengh[0];

                if ((ptrFlashAddress >= (unsigned char *)UTASKER_APP_START) && (ptrFlashAddress < UTASKER_APP_END)) { // if the sector belongs to the application space

                    if ((ptrFlashAddress + usBuff_length) >= UTASKER_APP_END) { // if the write would be past the end of the application space

                        usBuff_length = (unsigned short)(ptrFlashAddress - UTASKER_APP_END);

                    }

                    if (usBuff_length > ulProg_length) {

                        usBuff_length = (unsigned short)ulProg_length;

                    }

                    fnWriteBytesFlash(ptrFlashAddress, KBOOT_packet.ucData, usBuff_length); // program flash

                    ptrFlashAddress += usBuff_length;

                    ulProg_length -= usBuff_length;

                    if (ulProg_length == 0) {                            // complete code has been received

                        KBOOT_response.ucCommandType = KBOOT_REPORT_ID_COMMAND_IN;

                        KBOOT_response.ucLengh[0] = 12;                  // generic response

                        KBOOT_response.ucData[0] = 0xa0;

                        KBOOT_response.ucData[2] = 2;

                        KBOOT_response.ucData[8] = KBOOT_COMMAND_TAG_WRITE_MEMORY;

        #if defined FLASH_ROW_SIZE && FLASH_ROW_SIZE > 0

                        fnWriteBytesFlash(0, 0, 0);                      // close any outstanding FLASH buffer

        #endif

                        fnWrite(USBPortID_comms, (unsigned char *)&KBOOT_response, sizeof(KBOOT_response)); // send response to inform that all data has been programmed

                    }

                }

            }

            break

0 Kudos

962 Views
DerekLau
Contributor IV

Hello Mark,

I have tried the VendorID of 0x0425 and ProductID of 0x03fd. The HIDBootloader program works fine in my notebook. Please make sure the VendorID is 0x0425 but not 0x2504. I have added a warning message in the program when the device cannot be found.

HIDBootloader_device_not_found.jpg
Here I attached the updated HIDBootloader.exe and my modified winupdater.exe KBOOT program.

BTW, please don't use the VendorID of 0x0425

0 Kudos

962 Views
mjbcswitzerland
Specialist V

Hi Derek

HIDBootloader.exe: There must be some computer dependency because the new version still doesn't work on my PC, but it "does" now show what the problem is.

In the .imp file I have

VendorID=0x0425

ProductID=0x03fe

but the error message shows:

pid.png

This shows that the tool has understood the productID as 0x3 and not 0x3fe.

If I use 0x0312 or 0x0400 etc. it works, so I think that the problem with the tool is the conversion of the hex input from the .imp file.

Therefore I have decided to use PID of 0x0400 instead of 0x03fe so that it works with the original HIDBootloader.exe.

winupdater.exe: This version now launches on my Win 7 PC so I loaded the loader binary file to my FRDM-K64F board and could confirm connection via the UART (VirtualCOM - mbed serial port). The download of the example application looked to work (no errors) but the application didn't actually start - it looks like the board is always in the loader.

The USB device interface enumerates as a Human intrerface device (VID/PID = 0x15a2/0x0073) - "Kinetis Bootloader - but there doesn't look to be support for this interface in the Kinetis Updater. The Transport options that are available are UART, I2C using BusPal and SPI using BusPal. Supposedly BusPal is an adapter for connecting the PC to such an interface but I couldn't find any reference to a device of this name (is it something that Freescale will offer?).

Is it therefore true that the Kinetis Uploader in the FSL_Kinetis_Bootloader V1.0.1 package only supports UART loading?

On the KBOOT page there is a note that V1.0.2 will be available Mid-June with support for K24F, K63F and K64F but will USB-HID then be included?

Regards

Mark

0 Kudos

962 Views
DerekLau
Contributor IV

Hello Mark,

Thanks for your great effort and contributions. You are correct that the PC software will not be further developed due to the introduciton of KBOOT.

Regarding the changes of the VID and PID, the VID/PID in the firmware must match the values in the imp file, and can be changed. Please let me know if you still find issues on it.

Best Regards,

Derek

962 Views
mjbcswitzerland
Specialist V

Hi Derek

I knew that the PID/VID can be set in the .imp file but this is not working correct always.

For example, if I slightly modify the values from

VendorID=0x15A2

ProductID=0xFF03

to

VendorID=0x15A3

ProductID=0xFF04

It works.

But if I try other values, such as the ones that I would like to use:

VendorID=0x0425

ProductID=0x03fd

the loader will crash when I try to erase the device.

Therefore it seems as though there is a problem with the code used to convert the values from the .imp to the ones used by the program. I monitor the PID/VID sent by using a USB analyser and also I see the HID device with the correct PID/VID in the device manager on the PC so I can only see HIDBootloader.exe at fault in this case.

Therefore I was asking whether this problem could be corrected?

I would like to test KBOOT but the program in V1.0.1 won't launch on my PC although I have installed Microsoft.NET Framework 4.5. Therefore I am hoping that the next release may be operational so that I can check out whether it would be best to generally move to this solution and then avoid HIDBootloader.exe.

Regards

Mark

0 Kudos

962 Views
Jorge_Gonzalez
NXP Employee
NXP Employee

Hello Mark:

Thanks a lot for your valuable contributions and feedback.

I contacted the developer of AN4764 about your comments. If I receive response I will let you know about his feedback.

Regards!

Jorge Gonzalez

0 Kudos

962 Views
mjbcswitzerland
Specialist V

Hi Al

Note that I have uploaded a HID loader for the FRDM-K64F board, which can be found in this thread: New Freedom FRDM-K64F board

The interesting thing about this board is that it was possible to practically demonstrate the HID loader running "alongside" an SD card loader and also an Ethernet Web Server loader. With the SREC UART loader also enabled for debug output on the UART and a menu allowing command line based application code checking and deleting the loader fits in 32k of space (for the K64 on the FRDM board and its 1Meg Flash this is 3.13% of the available flash) and gives a very flexible loading choice.

Regards

Mark

0 Kudos