Hi,
We have developed a product using Kinetis K10 and there is a requirement to program serial numbers/order codes in the flash memory of K10 as a part of programming process. While browsing, I came across "Program Once Field" which seems useful. However, I am not able to understand its usage properly.
Is this "Program Once Field" useful in production programming of the K10? If so, how (i.e. through which interface/tool) can we program the serial number in this field?
Any help would be highly appreciable.
Thank you.
Message was edited by: Kaitav Sapre Moved to right community place "Kinetis Microcontrollers".
Solved! Go to Solution.
Kaitav
>>I have to at least set the clock divider for and enable to clock gate to Flash/FTFL module before calling the flash program
I am assuming that your code is configuring the Flash clock speed to that allowed by the processor. This is required generally to run from Flash and has nothing to do with Flash programming.
The clock is gated by default to the FTFL and so doesn't need to be enabled.
>>fnFlashNow(0x06, last_sector, program_data );
The use is not correct. You need to pass a pointer to the data and not directly a value. You will be getting compiler warnings (at least) due to this incorrect parameter. The reason for this is that not all Kinetis types program a long word at a time - some program a phrase and so by passing a pointer to the data block to be programmed keeps the routine essentially compatible.
These are defines for the commands available on the K10:
#define FCMD_READ_1S_BLOCK | 0x00 |
#define FCMD_READ_1S_SECTION | 0x01 |
#define FCMD_PROGRAM_CHECK | 0x02 |
#define FCMD_READ_RESOURCE | 0x03 |
#define FCMD_PROGRAM_LONG_WORD | 0x06 |
#define FCMD_ERASE_FLASH_BLOCK | 0x08 |
#define FCMD_ERASE_FLASH_SECTOR | 0x09 |
#define FCMD_PROGRAM_SECTOR | 0x0b |
#define FCMD_READ_1S_ALL_BLOCKS | 0x40 |
#define FCMD_READ_ONCE | 0x41 |
#define FCMD_PROGRAM_ONCE | 0x43 |
#define FCMD_ERASE_ALL_BLOCKS | 0x44 |
#define FCMD_VERIFY_BACKDOOR_ACCESS_KEY 0x45
#define FCMD_PROGRAM_PARTITION | 0x80 |
#define FCMD_SET_FLEXRAM_FUNCTION | 0x81 |
Therefor your call could do:
fnFlashNow(FCMD_PROGRAM_LONG_WORD, (unsigned long *)last_sector, &program_data );
Regards
Mark
Hi
The program once field can be programmed by the processor using Flash commands therefore your interface (and one can be used) needs a small command line mode so that such a value can be eneterd and then it can store it to the Flash (it can never be changed once programmed in this area).
Regards
Mark
Hi Mark,
Thank you for your suggestion.
What I am confused with is the "interface" to be used. Currently we have provision for JTAG and EzPort on our board, and we use either Flasher-ARM or Dediprog SF100 to program our boards. Now that we have this requirement to program serial numbers/order codes in the product manually, we need to provide an easy to use tool/interface for production people to do this task.
We do not have any bootloader in our software. Can we use JTAG or EzPort interface to do this serial number programming task? Or can we do this through a UART interface and a serial utility like Hyperterminal?
Not sure if it is exactly what we want, but I am currently looking at the "Production" settings of J-flash utility for Flasher-ARM which has something of this sort.
Regards,
Kaitav
Kaitav
I don't think that this area can be assessed by EZPORT and whether JTAG works depends on what support th eprogramming tool has so you will need to contact the supplier fo the tool (with JTAG everything is possible but needs SW to handle the specific operation, which may or may not be available).
What I use is the UART and a terminal emulator. The programming doesn't need to take place in a boot loader since the application can also provide the programming utility. For example I use a command which can program the MAC address of a device to the program once area. Once the value has been set (FLASH is no longer 0xffffffff) the command blocks itself so that it is no longer "visible".
To read and write the program once are the Flash interface is used. Below is an example.
Regards
Mark
// Read and write data from the program once area (64 bytes available which can only be programmed once in 4/8 byte blocks)
// The length is the number of long words to be copied to/from the buffer - FPU devices write 8 bytes at a time other 4 bytes at a time
//
extern int fnProgramOnce(int iCommand, unsigned long *ptrBuffer, unsigned char ucBlockNumber, unsigned char ucLength)
{
#if defined KINETIS_K_FPU
unsigned long ulBuffer[2]; // the devices with FPU read/write always 8 bytes at a time
unsigned char ucIndex8;
#endif
unsigned char ucMax = (ucLength + ucBlockNumber); // finishing block
unsigned char ucIndex = ucBlockNumber; // starting block
unsigned char ucCommandType;
if (iCommand == PROGRAM_ONCE_READ) { // read data from the program once area
ucCommandType = FCMD_READ_ONCE;
}
else { // program (one time programmable)
ucCommandType = FCMD_PROGRAM_ONCE;
}
for (; ucIndex < ucMax; ) {
#if defined KINETIS_K_FPU
ucIndex8 = (ucIndex/2);
if (ucCommandType == FCMD_PROGRAM_ONCE) { // writing
if (ucIndex & 1) { // uneven
ulBuffer[0] = 0xffffffff;
ulBuffer[1] = *ptrBuffer++;
ucIndex++;
}
else {
ulBuffer[0] = *ptrBuffer++;
if (++ucIndex >= ucMax) {
ulBuffer[1] = 0xffffffff;
}
else {
ulBuffer[1] = *ptrBuffer++;
}
ucIndex++;
}
}
if (fnFlashNow(ucCommandType, (unsigned long *)&ucIndex8, ulBuffer) != 0) { // read/write 2 long words at a time
return -1; // error
}
if (ucCommandType == FCMD_READ_ONCE) { // reading
if (ucIndex & 1) { // uneven
*ptrBuffer++ = ulBuffer[1];
}
else {
*ptrBuffer++ = ulBuffer[0];
ucIndex++;
if (ucIndex >= ucMax) {
break;
}
*ptrBuffer++ = ulBuffer[1];
}
ucIndex++;
}
#else
if (fnFlashNow(ucCommandType, (unsigned long *)&ucIndex, ptrBuffer) != 0) { // read/write 1 long word at a time
return -1; // error
}
ucIndex++;
ptrBuffer++;
#endif
}
return 0; // success
}
Hi Mark,
Thank you so much for the information and code. I appreciate it.
I just discussed about the interface with a colleague and he said that we need to use UART interface only. So, I think we can forget about EzPort or JTAG for this task.
One question regarding the code you have provided: Can this code be used to write and store the data in any Flash memory location? I mean the example you have given is for Program Once Field, but can this be taken as a "how to write/read to/from flash memory" reference by modifying it as required? I checked with my colleague and he said that we would not want to use Program Once Field since it can never be erased. The requirement is to actually do a write to Flash such that it can be erased when the board is reprogrammed again.
Something like this:
1) Give a command to send "order code" to the product via UART
2) Check if "order code flag" is '0' (just for example, indicating flash memory is empty)
2a) If '0', accept and store the order code in a flash memory location (which can be read/written/erased) AND change the flag to '1'
2b) If it is '1' (that is for previously configured product), do NOT accept the command and give a message, for example, "Relay already configured."
3) Repeat from 1).
The flag bit is basically for security purposes so that no once can change the order code by any means. The product has to be reprogrammed to be able to be configurable with the order code again. So, basically we need some information and code reference of how to work (read, write) with K10's flash memory. We need a few bytes to store the order code (which can be read later via a command) and one flag bit.
Is this possible? Could you please link me to an example code if there is one for K10?
I hope I have described the question good enough.
Thanks,
Kaitav
Kaitav
The flash interface is used to program any flash location, whereby the FCMD_PROGRAM_ONCE command (0x43) was used in the previous example. The rest of the code was formatting the data. The FCMD_PROGRAM (0x06) on K10 is used to program to general internal Flash locations, which are memory mapped (unlike the PO locations) and so can be read without using a special interface.
The Flash interace is available in Freescale code examples or included in the uTasker project (as uParameterSystem or low-level access - http://www.utasker.com/docs/uTasker/uTaskerFileSystem_3.PDF )
Regards
Mark
Hi Mark,
Thanks again for your help. I will check the document. Is the topic (uParameterSystem) you are referring a good starting point to understand working with K10's flash memory?
Meanwhile, I checked some code examples and more information on internet/forum about this and I came across two types of flash drivers. One is "C90TFS_FLASH_DRIVER" and the other, "flash_FTFL.c", found in one of demo projects (DFU in USB Device in the Freescale USB stack). Now, I am feeling a bit overwhelmed by these. Could you guide me as to which of two drivers should be better/simple to use? Also, if there is any example project for Keil which involves all the basic operations of working with program flash memory with "copy to RAM" function, that would be ideal.
Regards,
Kaitav
Kaitav
I don't have experience with the two drivers that you mentioned so can't saw which would be more suitable or easiest to use. It is also quite simple to develop a Flash driver based on the details in the user's manual.
Below I have copied the complete low level Flash driver code from the uTasker project (used as lowest level driver for Program Once, parameter and file system). This is compiler independent and is also used with Keil. You can probably work out the details to use it for storing your data. As noted above, the operation is described in the user's manual and I expect that all implementations will be more or less the same.
Regards
Mark
// This routine runs from SRAM - the reason why the pointer is passed is to avoid the routine taking it from a const value in FLASH, which is then not code location dependent
//
static unsigned short fnFlashRoutine[] = { // to avoid potential compiler in-lining of the routine (removing position independency) the machine code is used directly
0x2180, // MOVS r1,#0x80 load the value 0x80 (command complete interrupt flag) to register r1
0x7001, // STRB r1,[r0,#0x00] write r1 (0x80) to the passed pointer location (r0)
0x7801, // LDRB r1,[r0,#0x00] read back from the same location to r1
0x0609, // LSLS r1,r1,#24 shift the register content by 24 bits to the left so that the command complete interrupt flag is at bit 31
0xd5fc, // BPL -4 if the command complete interrupt flag bit is '0' (register content is not negative value) branch back to read its value again
0x4770 // BX lr return from sub-routine
};
static int fnFlashNow(unsigned char ucCommand, unsigned long *ptrWord, unsigned long *ptr_ulWord)
{
static void (*fnRAM_code)(volatile unsigned char *) = 0;
if (!fnRAM_code) { // the first time this is used it will load the program to SRAM
#define PROG_WORD_SIZE 30 // adequate space for the small program
int i = 0;
unsigned char *ptrThumb2 = (unsigned char *)fnFlashRoutine;
static unsigned short usProgSpace[PROG_WORD_SIZE]; // make space for the routine on stack (this will have an even boundary)
ptrThumb2 = (unsigned char *)(((CAST_POINTER_ARITHMETIC)ptrThumb2) & ~0x1); // thumb 2 address
while (i < PROG_WORD_SIZE) { // copy program to SRAM
usProgSpace[i++] = *(unsigned short *)ptrThumb2;
ptrThumb2 += sizeof (unsigned short);
}
ptrThumb2 = (unsigned char *)usProgSpace;
ptrThumb2++; // create a thumb 2 call
fnRAM_code = (void(*)(volatile unsigned char *))(ptrThumb2);
}
while (!(FTFL_FSTAT & FTFL_STAT_CCIF)) {} // wait for previous commands to complete
if (FTFL_FSTAT & (FTFL_STAT_ACCERR | FTFL_STAT_FPVIOL)) { // check for errors in previous command
FTFL_FSTAT = (FTFL_STAT_ACCERR | FTFL_STAT_FPVIOL); // clear old errors
}
switch (FTFL_FCCOB0 = ucCommand) { // enter the command sequence
case FCMD_ERASE_FLASH_SECTOR:
case FCMD_PROGRAM:
FTFL_FCCOB1 = (unsigned char)(((CAST_POINTER_ARITHMETIC)ptrWord) >> 16); // set address in flash
FTFL_FCCOB2 = (unsigned char)(((CAST_POINTER_ARITHMETIC)ptrWord) >> 8);
FTFL_FCCOB3 = (unsigned char)((CAST_POINTER_ARITHMETIC)ptrWord);
if (ucCommand == FCMD_PROGRAM) { // program long-word aligned value
FTFL_FCCOB4 = (unsigned char)(*ptr_ulWord >> 24); // enter the long word to be programmed
FTFL_FCCOB5 = (unsigned char)(*ptr_ulWord >> 16);
FTFL_FCCOB6 = (unsigned char)(*ptr_ulWord >> 8);
FTFL_FCCOB7 = (unsigned char)(*ptr_ulWord);
#if defined KINETIS_K_FPU // write second long word
ptr_ulWord++;
FTFL_FCCOB8 = (unsigned char)(*ptr_ulWord >> 24); // enter the second long word to be programmed
FTFL_FCCOB9 = (unsigned char)(*ptr_ulWord >> 16);
FTFL_FCCOBA = (unsigned char)(*ptr_ulWord >> 8);
FTFL_FCCOBB = (unsigned char)(*ptr_ulWord);
#endif
}
break;
#if defined SUPPORT_PROGRAM_ONCE
case FCMD_READ_ONCE:
FTFL_FCCOB1 = (unsigned char)(*ptrWord); // record index (0..7) for FPU types or (0..15)
break;
case FCMD_PROGRAM_ONCE:
FTFL_FCCOB1 = (unsigned char)(*ptrWord); // record index (0..7) for FPU types or (0..15)
FTFL_FCCOB4 = (unsigned char)(*ptr_ulWord >> 24);
FTFL_FCCOB5 = (unsigned char)(*ptr_ulWord >> 16);
FTFL_FCCOB6 = (unsigned char)(*ptr_ulWord >> 8);
FTFL_FCCOB7 = (unsigned char)(*ptr_ulWord);
#if defined KINETIS_K_FPU
ptr_ulWord++;
FTFL_FCCOB8 = (unsigned char)(*ptr_ulWord >> 24);
FTFL_FCCOB9 = (unsigned char)(*ptr_ulWord >> 16);
FTFL_FCCOBA = (unsigned char)(*ptr_ulWord >> 8);
FTFL_FCCOBB = (unsigned char)(*ptr_ulWord);
#endif
break;
#endif
}
uDisable_Interrupt(); // protect this region from interrupts
fnRAM_code((volatile unsigned char *)FTFL_BLOCK); // execute the command from SRAM
uEnable_Interrupt(); // safe to accept interrupts again
#if defined SUPPORT_PROGRAM_ONCE
if (FCMD_READ_ONCE == ucCommand) { // the result (8 bytes) is in FTFL_FCCOB2/FTFL_FCCOB3
*ptr_ulWord++ = ((FTFL_FCCOB4 << 24) | (FTFL_FCCOB5 << 16) | (FTFL_FCCOB6 << 8) | FTFL_FCCOB7);
#if defined KINETIS_K_FPU
*ptr_ulWord = ((FTFL_FCCOB8 << 24) | (FTFL_FCCOB9 << 16) | (FTFL_FCCOBA << 8) | FTFL_FCCOBB);
#endif
}
#endif
return (FTFL_FSTAT & (FTFL_STAT_ACCERR | FTFL_STAT_FPVIOL | FTFL_STAT_MGSTAT0)); // if there was an error this will be non-zero
}
Hi Mark,
I am trying to integrate the code you have given, but I am facing problems with the following undeclared identifiers:
CAST_POINTER_ARITHMETIC
FTFL_BLOCK
Could you please help me with it?
Also, I have to initialize the flash before this program. Will the flash init be related to the code you have given, or I can just init it by referring the K10 user manual?
Thanks.
Kaitav
The two defines are:
#define CAST_POINTER_ARITHMETIC unsigned long // Kinetis uses 32 bit pointers
#define FTFL_BLOCK 0x40020000 // Flash Memory Module
There is no further flash initialisation required.
Complete code is available as linked in uTasker V1.4.4 for Kinetis K / KL
Regards
Mark
Hi Mark,
Thanks for that. I am struggling a bit to get it to work though. I am not really a software guy and perhaps that's the reason why I am not being able to able to run your program successfully.
By the way, why is Flash init not required? I mean I have to at least set the clock divider for and enable to clock gate to Flash/FTFL module before calling the flash program, isn't it?
As far as the main function is concerned, I need to call only "fnFlashNow" function in my main program and pass the parameters: Command, Address, Data. So, I am doing it as follows:
.................
unsigned long last_sector = 0x0007F800; //address of last sector of flash memory I want to use
unsigned long program_data = 0x5A5A5A5A; //random pattern of one long word I want to write at the last sector
fnFlashNow(0x06, last_sector, program_data ); //0x06 to program one long word
........
Does it make sense, or am I doing it wrong?
Regards,
Kaitav
Kaitav
>>I have to at least set the clock divider for and enable to clock gate to Flash/FTFL module before calling the flash program
I am assuming that your code is configuring the Flash clock speed to that allowed by the processor. This is required generally to run from Flash and has nothing to do with Flash programming.
The clock is gated by default to the FTFL and so doesn't need to be enabled.
>>fnFlashNow(0x06, last_sector, program_data );
The use is not correct. You need to pass a pointer to the data and not directly a value. You will be getting compiler warnings (at least) due to this incorrect parameter. The reason for this is that not all Kinetis types program a long word at a time - some program a phrase and so by passing a pointer to the data block to be programmed keeps the routine essentially compatible.
These are defines for the commands available on the K10:
#define FCMD_READ_1S_BLOCK | 0x00 |
#define FCMD_READ_1S_SECTION | 0x01 |
#define FCMD_PROGRAM_CHECK | 0x02 |
#define FCMD_READ_RESOURCE | 0x03 |
#define FCMD_PROGRAM_LONG_WORD | 0x06 |
#define FCMD_ERASE_FLASH_BLOCK | 0x08 |
#define FCMD_ERASE_FLASH_SECTOR | 0x09 |
#define FCMD_PROGRAM_SECTOR | 0x0b |
#define FCMD_READ_1S_ALL_BLOCKS | 0x40 |
#define FCMD_READ_ONCE | 0x41 |
#define FCMD_PROGRAM_ONCE | 0x43 |
#define FCMD_ERASE_ALL_BLOCKS | 0x44 |
#define FCMD_VERIFY_BACKDOOR_ACCESS_KEY 0x45
#define FCMD_PROGRAM_PARTITION | 0x80 |
#define FCMD_SET_FLEXRAM_FUNCTION | 0x81 |
Therefor your call could do:
fnFlashNow(FCMD_PROGRAM_LONG_WORD, (unsigned long *)last_sector, &program_data );
Regards
Mark
Hi Mark,
Ahh, that was silly of me. Thanks for clearing the flash init confusion.
fnFlashNow(FCMD_PROGRAM_LONG_WORD, (unsigned long *)last_sector, &program_data );
Yes, that worked! I was able to do run the program successfully. Thanks a lot for your explanation and code. I added a mechanism to read the data from the programmed flash location with the help of memcpy and printed the result on the terminal for verification. I still might need to do so more modifications as per the requirement, but the erase, read, write functions are now working fine. Also, I need to understand some of the things in the code I have not really understood yet.
Thanks again. Have a nice day!
Regards,
Kaitav
Hi Mark,
Once again, thanks a lot for your help.
No problems, I will refer the user manual of K10 and the code you have posted, and see if I can get it to work.
I will get back with the progress/queries/results.
Regards,
Kaitav
Hello,
Thank you for your post, however please consider moving it to the right community place (e.g. Kinetis Microcontrollers ) to get it visible for active members.
For details please see general advice Where to post a Discussion?
Thank you for using Freescale Community.
Hi,
Okay, thanks for bringing this to my notice. I have moved the topic to "Kinetis Microcontrollers" community now.