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