kboot k24f using flash

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

kboot k24f using flash

1,951 Views
kurtjordan
Contributor I

I am migrating from a k22 to a k24 due to supply chain constraints.

I have the latest 2.4 SDK up and running on my k22 based project.

I am unable to get the k24 to boot from the user application in flash. I get a constant "user config" area of all 0xff for the entire block.

Is there a way to get this to work since it uses a different memory structure than the k22 ( FTFE vs FTFA ) ?

Is there a way to validate that the Flash is being initialized in the bootloader code?

Thanks for any help,

-Kurt

0 Kudos
Reply
8 Replies

1,662 Views
kurtjordan
Contributor I

Something I am noticing with the SDK 2.4.0 and the KBOOT2 files.

Upon download of the SDK for the MK24FN1M0512 the MK64FN family of parts was included.

When looking at the KBOOT targets there is the MK24FN256 and the MK64F12 potentials.

The clock config for the MK64 has the clock_mode_switch function check for :

// Note: here only implements clock switch between FEI and FEE,
// The other modes are not supported.
assert(currentMode == kClockMode_FEE || currentMode == kClockMode_FEI);
assert(expectedMode == kClockMode_FEE || expectedMode == kClockMode_FEI);

when the enums above :

// Clock mode types
typedef enum _target_clock_mode
{
kClockMode_FEI_48MHz = 0,
kClockMode_FEI_21MHz = 1,
kClockMode_Default = kClockMode_FEI_21MHz,
} target_clock_mode_t;

Is this an error in the KBOOT files? should the MK64 boot code be used in the MK24FN1M0 parts and not the MK24FN256 boot code?

0 Kudos
Reply

1,662 Views
jingpan
NXP TechSupport
NXP TechSupport

Hi,

yes, it seems kClockMode_FEE and kClockMode_FEI is useless. I guess they are inherit from some old version. I find even KBOOT 1.2.0 has this tail.

Yes, you can use MK64 boot code to MK24FM1M0. MK64 has the same platform with MK24. But it not means that MK64 boot code is more suitable. I'd rather use MK24FN256 boot code.

Regards,

Jing

0 Kudos
Reply

1,662 Views
kurtjordan
Contributor I

Also,

I am unable to get the UART to work and connect to the kboot windows application. it is not responding the the initial ping. I have not had any issues using the k22 in this way it is only with the k24.

-Kurt

0 Kudos
Reply

1,662 Views
mjbcswitzerland
Specialist V

Hi Kurt

If you don't find a quick solution remember that the uTasker project includes a turn-key and optimised KBOOT solution for most processors (including K22 and K24) which doesn't need porting since it adapts itself to the processor in question.
It also allows KBOOT operation on a simulated K22 / K24 to allow for testing and debugging if needed in Visual Studio to avoid typical embedded debugging complications and inefficiencies.

Regards

Mark


Kinetis: http://www.utasker.com/kinetis.html
Kinetis K22:
- http://www.utasker.com/kinetis/FRDM-K22F.html
- http://www.utasker.com/kinetis/TWR-K22F120M.html
- http://www.utasker.com/kinetis/BLAZE_K22.html
- http://www.utasker.com/kinetis/tinyK22.html
Kinetis K24:
- http://www.utasker.com/kinetis/TWR-K24F120M.html

Free Open Source solution: https://github.com/uTasker/uTasker-Kinetis (includes Kboot V2.0.0 compatibility on USB HID and UARTs)
Working project in 15 minutes video: https://youtu.be/K8ScSgpgQ6M

uTasker developer and supporter (+5'000 hours experience on +60 Kinetis derivatives in +80 product developments)
Kinetis: http://www.utasker.com/kinetis.html

1,662 Views
kurtjordan
Contributor I

Mark,

Thanks for pointing this out to me. I am unfortunately unable to use this as I have so custom code modifications from the basic kboot source for backup imaging of our application. I am not sure how easy if at all it would be to modify uTasker to incorporate these necessary changes.

-Kurt

0 Kudos
Reply

1,662 Views
mjbcswitzerland
Specialist V

Kurt

Should be easy since the uTasker solution has a parameter and file systems that can be used by the serial loaders on top of the Flash API, as well as the fact that it allows complete simulation.
Below I have copied the complete Kboot 2.0.0 code to show how simple it is, whereby inserting new commands and such is a case of adding new switch cases, so easy to maintain.
The Flash interface used calls fnEraseFlashSector() and fnWriteBytesFlash()  for its work, which are low level flash commands [as described alongside higher level ones in http://www.utasker.com/docs/uTasker/uTaskerFileSystem_3.PDF]


Regards

Mark

static void fnHandlePropertyGet(unsigned long ulPropertyTag, unsigned long ulMemoryID, KBOOT_PACKET *ptrKBOOT_response)
{
    #define BOOT_LOADER_NAME                    'K'
    #define BOOT_LOADER_MAJOR_VERSION            2
    #define BOOT_LOADER_MINOR_VERSION            0
    #define BOOT_LOADER_BUGFIX                   0
    #define kStatus_Success                      0
    #define kStatus_Fail                         1
    #define kStatus_ReadOnly                     2
    #define kStatus_OutOfRange                   3
    #define kStatus_UnknownProperty              10300
    #define kStatus_ReadOnlyProperty             10301
    #define kStatus_InvalidPropertyValue         10302
    #define KB_SUPPORTS_FLASH_ERASE_ALL          0x00000001
    #define KB_SUPPORTS_FLASH_ERASE_REGION       0x00000002
    #define KB_SUPPORTS_READ_MEMORY              0x00000004
    #define KB_SUPPORTS_WRITE_MEMORY             0x00000008
    #define KB_SUPPORTS_FILL_MEMORY              0x00000010
    #define KB_SUPPORTS_FLASH_SECURITY_DISABLE   0x00000020
    #define KB_SUPPORTS_GET_PROPERTY             0x00000040
    #define KB_SUPPORTS_RECEIVE_SB_FILE          0x00000080
    #define KB_SUPPORTS_EXECUTE                  0x00000100
    #define KB_SUPPORTS_CALL                     0x00000200
    #define KB_SUPPORTS_RESET                    0x00000400
    #define KB_SUPPORTS_SET_PROPERTY             0x00000800
    #define KB_SUPPORTS_FLASH_ERASE_ALL_UNSECURE 0x00001000
    #define KB_SUPPORTS_FLASH_PROGRAM_ONCE       0x00002000
    #define KB_SUPPORTS_FLASH_READ_ONCE          0x00004000
    #define KB_SUPPORTS_FLASH_READ_RESOURCE      0x00008000
    #define KB_SUPPORTS_CONFIGURE_QUAD_SPI       0x00010000
    #define KB_SUPPORTS_RELIABLE_UPDATE          0x00100000
    #define SUPPORTED_KBOOT_COMMANDS            (KB_SUPPORTS_FLASH_ERASE_REGION | KB_SUPPORTS_WRITE_MEMORY | KB_SUPPORTS_GET_PROPERTY | KB_SUPPORTS_RESET)
    const unsigned long version_info = ((BOOT_LOADER_NAME << 24) | (BOOT_LOADER_MAJOR_VERSION << 16) | (BOOT_LOADER_MINOR_VERSION << 8) | (BOOT_LOADER_BUGFIX));
    unsigned long ulStatus = kStatus_Success;
    unsigned long ulResponseData[4];
    int iDataLength = 1;                                                 // most responses return one data value
    int iNoStatus = 0;
    int iDataIndex = 4;
    int iDataRef = 0;
    int iDataPairs = 0;
    switch (ulPropertyTag) {
    case PROPERTY_VERSION:                                               // 1
        ulResponseData[0] = (unsigned long)version_info;
        break;
    case PROPERTY_FLASH_START_ADD:                                       // 3
        ulResponseData[0] = FLASH_START_ADDRESS;
        break;
    case PROPERTY_FLASH_SIZE_BYTES:                                      // 4
        ulResponseData[0] = SIZE_OF_FLASH;
        break;
    case PROPERTY_FLASH_SECTOR_SIZE:                                     // 5
        ulResponseData[0] = FLASH_GRANULARITY;
        break;
    case PROPERTY_AVAILABLE_CMDS:                                        // 7
        ulResponseData[0] = SUPPORTED_KBOOT_COMMANDS;
        break;
    case PROPERTY_RESERVED_REGIONS:                                      // 12 (0x0c)
        iNoStatus = 0;
        iDataLength = 4;                                                 // the number of data values
        iDataPairs = 0;                                                  // the number of data pairs
        ulResponseData[0] = FLASH_START_ADDRESS;                         // reserved region
        ulResponseData[1] = (_UTASKER_APP_START_ - 1);
        ulResponseData[2] = RAM_START_ADDRESS;
        ulResponseData[3] = (RAM_START_ADDRESS + (SIZE_OF_RAM/2));
        break;
    case PROPERTY_RAM_SIZE_BYTES:                                        // 15 (0x0f)
        ulResponseData[0] = SIZE_OF_RAM;
        break;
    case PROPERTY_FLASH_SEC_STATE:                                       // 17 (0x11)
    #if defined FLASH_CONTROLLER_FTMRE
        ulResponseData[0] = ((FTMRH_FSEC & FTMRH_FSEC_SEC_UNSECURE_FLAG) == 0);
    #else
        ulResponseData[0] = ((FTFL_FSEC & FTFL_FSEC_SEC_UNSECURE) == 0);
    #endif
        break;
    default:
        iDataLength = 0;
        ulStatus = kStatus_UnknownProperty;                              // returning this causes an error message to be displayed at the host but further operation is OK
        break;
    }
    if (iNoStatus == 0) {                                                // insert the status if not explicitly not required
        ptrKBOOT_response->ucData[iDataIndex++] = (unsigned char)ulStatus;
        ptrKBOOT_response->ucData[iDataIndex++] = (unsigned char)(ulStatus >> 8);
        ptrKBOOT_response->ucData[iDataIndex++] = (unsigned char)(ulStatus >> 16);
        ptrKBOOT_response->ucData[iDataIndex++] = (unsigned char)(ulStatus >> 24);
        ptrKBOOT_response->ucData[3]++;                                  // parameter count
    }
    while (iDataLength-- != 0) {                                         // insert data
        ptrKBOOT_response->ucData[iDataIndex++] = (unsigned char)ulResponseData[iDataRef];
        ptrKBOOT_response->ucData[iDataIndex++] = (unsigned char)(ulResponseData[iDataRef] >> 8);
        ptrKBOOT_response->ucData[iDataIndex++] = (unsigned char)(ulResponseData[iDataRef] >> 16);
        ptrKBOOT_response->ucData[iDataIndex++] = (unsigned char)(ulResponseData[iDataRef] >> 24);
        ptrKBOOT_response->ucData[3]++;                                  // parameter count
        iDataRef++;
    }
    while (iDataPairs-- != 0) {
        ptrKBOOT_response->ucData[3]--;
    }
    ptrKBOOT_response->ucLength[0] = (unsigned char)iDataIndex;
}

static void fnReturnResponse(QUEUE_HANDLE hInterface, int iInterfaceType, KBOOT_PACKET *ptrKBOOT_response)
{
    #if (defined SERIAL_INTERFACE && defined KBOOT_LOADER)
    if (iInterfaceType == KBOOT_UART) {
        unsigned char ucSerialHeader[6];
        unsigned short usCRC;
        ucSerialHeader[0] = KBOOT_SERIAL_START_BYTE;
        ucSerialHeader[1] = KBOOT_SERIAL_COMMAND;
        ucSerialHeader[2] = ptrKBOOT_response->ucLength[0];
        ucSerialHeader[3] = 0;
        usCRC = fnCRC16(fnCRC16(0, ucSerialHeader, (sizeof(ucSerialHeader) - 2)), ptrKBOOT_response->ucData, ptrKBOOT_response->ucLength[0]); // calculate CRC
        ucSerialHeader[4] = (unsigned char)usCRC;
        ucSerialHeader[5] = (unsigned char)(usCRC >> 8);
        fnWrite(hInterface, ucSerialHeader, sizeof(ucSerialHeader));     // send serial header
        fnWrite(hInterface, ptrKBOOT_response->ucData, ptrKBOOT_response->ucLength[0]); // send the response body
    }
    else {                                                               // HID
    #endif
    #if (defined USB_INTERFACE && defined HID_LOADER && defined KBOOT_HID_LOADER)
        fnWrite(hInterface, (unsigned char *)ptrKBOOT_response, sizeof(KBOOT_PACKET));
    #endif
    #if (defined SERIAL_INTERFACE && defined KBOOT_LOADER)
    }
    #endif
}


extern int fnHandleKboot(QUEUE_HANDLE hInterface, int iInterfaceType, KBOOT_PACKET *ptrKBOOT_packet)
{
    int iReturn = 0;
    KBOOT_PACKET KBOOT_response;
    uMemset(&KBOOT_response, 0, sizeof(KBOOT_response));
    switch (ptrKBOOT_packet->ucCommandType) {                            // the command
    case KBOOT_REPORT_ID_COMMAND_OUT:
        KBOOT_response.ucCommandType = KBOOT_REPORT_ID_COMMAND_IN;
        switch (ptrKBOOT_packet->ucData[0]) {
        case KBOOT_COMMAND_TAG_GET_PROPERTY:                             // 0x07
            {
    #if defined _WINDOWS
                unsigned char ucParameterCount = ptrKBOOT_packet->ucData[3]; // parameter count
    #endif
                unsigned long ulPropertyTag = (ptrKBOOT_packet->ucData[4] | (ptrKBOOT_packet->ucData[5] << 8) | (ptrKBOOT_packet->ucData[6] << 16) | (ptrKBOOT_packet->ucData[7] << 24));
                unsigned long ulMemoryID = (ptrKBOOT_packet->ucData[8] | (ptrKBOOT_packet->ucData[9] << 8) | (ptrKBOOT_packet->ucData[10] << 16) | (ptrKBOOT_packet->ucData[11] << 24));
    #if defined _WINDOWS
                if (ucParameterCount != 2) {
                    _EXCEPTION("Expecting the parameter count to be always 2 - investigate if this exception occurs");
                }
    #endif
                KBOOT_response.ucData[0] = (ptrKBOOT_packet->ucData[0] | 0xa0); // response tag
                fnHandlePropertyGet(ulPropertyTag, ulMemoryID, &KBOOT_response);
            }
            break;
        case KBOOT_COMMAND_TAG_WRITE_MEMORY:                             // 0x04
        case KBOOT_COMMAND_TAG_ERASE_REGION:                             // 0x02
            {
                unsigned long ulStartAddress;
                unsigned long ulLength;
                ulStartAddress = (ptrKBOOT_packet->ucData[4] | (ptrKBOOT_packet->ucData[5] << 8) | (ptrKBOOT_packet->ucData[6] << 16) | (ptrKBOOT_packet->ucData[7] << 24));
                ulLength = (ptrKBOOT_packet->ucData[8] | (ptrKBOOT_packet->ucData[9] << 8) | (ptrKBOOT_packet->ucData[10] << 16) | (ptrKBOOT_packet->ucData[11] << 24));
                if (KBOOT_COMMAND_TAG_ERASE_REGION == ptrKBOOT_packet->ucData[0]) { // command to delete an area in flash
                    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);
    #if defined ADD_FILE_OBJECT_AFTER_LOADING
                        fileObjInfo.ptrLastAddress = 0;
    #endif
    #if defined DEBUG_CODE
                        fnDebugMsg("ERASING: ");
                        fnDebugHex(ulStartAddress, (sizeof(ulStartAddress) | WITH_LEADIN));
                        fnDebugHex(ulLength, (sizeof(ulLength) | WITH_SPACE | WITH_LEADIN | WITH_CR_LF));
    #endif
                    }
                }
                else {                                                   // command to write following data to flash
                    ptrFlashAddress = (unsigned char *)ulStartAddress;
                    ulProg_length = ulLength;
    #if defined ADD_FILE_OBJECT_AFTER_LOADING
                    if ((ptrFlashAddress + ulLength) > fileObjInfo.ptrLastAddress) {
                        fileObjInfo.ptrLastAddress = (ptrFlashAddress + ulLength); // keep a track of the highest program address
                    }
    #endif
    #if defined DEBUG_CODE
                    fnDebugMsg("PROGRAMMING: ");
                    fnDebugHex(ulProg_length, (sizeof(ulLength) | WITH_LEADIN | WITH_CR_LF));
    #endif
                }
                KBOOT_response.ucLength[0] = 12;                         // generic response
                KBOOT_response.ucData[0] = 0xa0;
                if (iInterfaceType == KBOOT_UART) {
                    KBOOT_response.ucData[3] = 2;
                }
                else {
                    KBOOT_response.ucData[2] = 2;
                }
                KBOOT_response.ucData[8] = ptrKBOOT_packet->ucData[0];
            }
            break;
        case KBOOT_COMMAND_TAG_RESET:                                    // 0x0b
            iReturn = 1;                                                 // reset is required
            KBOOT_response.ucLength[0] = 12;                             // generic response
            KBOOT_response.ucData[0] = 0xa0;
            if (iInterfaceType == KBOOT_UART) {
                KBOOT_response.ucData[3] = 2;
                fnDriver(hInterface, (RX_OFF), 0);                       // disable rx since we are resetting (to stop the host's ack triggering receive timer and losing reset timer)
    #if defined ADD_FILE_OBJECT_AFTER_LOADING
                fileObjInfo.ptrShortFileName = "KBOOTSERBIN";            // define a name for the file (with default time/date)
    #endif
            }
            else {
                KBOOT_response.ucData[2] = 2;
    #if defined ADD_FILE_OBJECT_AFTER_LOADING
                fileObjInfo.ptrShortFileName = "KBOOTUSBBIN";            // define a name for the file (with default time/date)
    #endif
            }
            KBOOT_response.ucData[8] = ptrKBOOT_packet->ucData[0];
    #if defined ADD_FILE_OBJECT_AFTER_LOADING
            if (fileObjInfo.ptrLastAddress != 0) {
                fnAddSREC_file(&fileObjInfo);                            // add a file object wit name and size
            }
    #endif
    #if defined DEBUG_CODE
            fnDebugMsg("RESETTING\r\n");
    #endif
            break;

        case KBOOT_COMMAND_TAG_ERASE_ALL:                                // the following are not yet used by KBOOT
        case KBOOT_COMMAND_TAG_READ_MEMORY:
        case KBOOT_COMMAND_TAG_FILL_MEMORY:
        case KBOOT_COMMAND_TAG_FLASH_SECURITY_DISABLE:
        case KBOOT_COMMAND_TAG_RECEIVE_SBFILE:
        case KBOOT_COMMAND_TAG_EXECUTE:
        case KBOOT_COMMAND_TAG_CALL:
        case KBOOT_COMMAND_TAG_SET_PROPERTY:
        case KBOOT_COMMAND_TAG_MASS_ERASE:
            _EXCEPTION("Use detected - investigate....");
            break;
        }
        fnReturnResponse(hInterface, iInterfaceType, &KBOOT_response);
        break;

    case KBOOT_REPORT_ID_DATA_OUT:                                       // data to be written
        {
            unsigned short usBuff_length = ptrKBOOT_packet->ucLength[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, ptrKBOOT_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.ucLength[0] = 12;                     // generic response
                    KBOOT_response.ucData[0] = 0xa0;
                    if (iInterfaceType == KBOOT_UART) {
                        KBOOT_response.ucData[3] = 2;
                    }
                    else {
                        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
                    fnReturnResponse(hInterface, iInterfaceType, &KBOOT_response); // send response to inform that all data has been programmed
    #if defined DEBUG_CODE
                    fnDebugMsg("*");
    #endif
                }
    #if defined DEBUG_CODE
                fnDebugMsg(".");
    #endif
            }
    #if defined DEBUG_CODE
            else {
                 fnDebugMsg("x");
            }
    #endif
        }
        break;
    }
    return iReturn;
}
0 Kudos
Reply

1,662 Views
kurtjordan
Contributor I

Mark,

Thanks again for the great help.

I think I was unclear about some of what I need to accomplish and my reservations on how to get it accomplished in uTasker.

I am on a tight deadline and require the ability to modify the user application start address ( should be simple if I can find where to do that ), allow for crc checks to be run to validate images on external memory to be validated in case of a bad/corrupt flash to restore to a known good image, and a few other things.

The main things I need are pinmux changes ( maybe our stuff is based on the tower kits ), uart flashing, user application mapping, and external image loading / verification.

Any way that you could lead me in the right direction in uTasker  ( or its documentation ) to help facilitate this would be greatly appreciated even more so than what you have already done.

-Kurt

0 Kudos
Reply

1,662 Views
mjbcswitzerland
Specialist V

Kurt

Start address is a define, eg.

#define UTASKER_APP_START 0x0002000

CRCs in external memory (presumably on FlexBus) doesn't need porting. It works with whatever C code you have.

Port Muxing is designed to be simple in the uTasker environment and the problem seems that people get afraid of this after working in the traditional ones where one needs to get into the register and bit details. Eg. of a couple of pin configurations:

_CONFIG_PERIPHERAL(B, 2, (PB_2_UART0_RTS | UART_PULL_UPS)); // UART0_RX on PB16 (alt. function 3)
_CONFIG_PERIPHERAL(E, 2, (PE_2_SDHC0_DCLK | PORT_DSE_HIGH));         // SDHC_DCLK on PE.2 (alt. function 4)
_CONFIG_PERIPHERAL(C, 9,  (PC_9_FB_AD6   | PORT_DSE_HIGH | PORT_PS_DOWN_ENABLE));
 _CONFIG_PERIPHERAL(C, 10, (PC_10_FB_AD5  | PORT_DSE_HIGH | PORT_PS_DOWN_ENABLE));

and complete inputs/output and general interface is shown at http://www.utasker.com/forum/index.php?topic=1875.0

All port clocking and such details are taken care of and the simulator shows you the pin's function that has really been set when it runs.

This means that a project setup can be done and verified in a few minutes.

The project includes various loaders (including fail-safe external memory to internal methods - see "Bare-Minimum" loader), Kboot plus Modbus, SREC, iHEX (on UART or USB-HID, USB-CDC) so you may also find a more convenient method if it is not yet fixed.

If you are on a tight deadline where you need guarantied results there is a professional version that is personally supported and the porting work will also be done for your, which will cost about the equivalent of a day's engineer work but includes several months of support/guarantee on top.

You can also do it using the open source version but you will need to do some homework to get to know the details.

Finally there is a service to help solve the incompatibility issues in the original code which is know to complicate moving between parts if you prefer to stay fully in your original environment: See services below.

Good luck

Regards

Mark

http://www.utasker.com/services.html

0 Kudos
Reply