Serial number programming in production - Kinetis K10

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

Serial number programming in production - Kinetis K10

Jump to solution
5,915 Views
kaitav
Contributor III

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".

Labels (1)
1 Solution
2,265 Views
mjbcswitzerland
Specialist V

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

View solution in original post

0 Kudos
15 Replies
2,265 Views
mjbcswitzerland
Specialist V

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

2,265 Views
kaitav
Contributor III

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

0 Kudos
2,265 Views
mjbcswitzerland
Specialist V

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

}

2,265 Views
kaitav
Contributor III

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

0 Kudos
2,265 Views
mjbcswitzerland
Specialist V

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

0 Kudos
2,265 Views
kaitav
Contributor III

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

0 Kudos
2,265 Views
mjbcswitzerland
Specialist V

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

}

2,265 Views
kaitav
Contributor III

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.

0 Kudos
2,265 Views
mjbcswitzerland
Specialist V

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

0 Kudos
2,264 Views
kaitav
Contributor III

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

0 Kudos
2,266 Views
mjbcswitzerland
Specialist V

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

0 Kudos
2,265 Views
kaitav
Contributor III

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

0 Kudos
2,265 Views
kaitav
Contributor III

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

0 Kudos
2,265 Views
Wlodek_D_
Senior Contributor II

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.

0 Kudos
2,265 Views
kaitav
Contributor III

Hi,

Okay, thanks for bringing this to my notice. I have moved the topic to "Kinetis Microcontrollers" community now.

0 Kudos