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
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?
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
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
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
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
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;
}
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
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