Programming the K32L3A MCU Flash IFR Fields

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

Programming the K32L3A MCU Flash IFR Fields

Programming the K32L3A MCU Flash IFR Fields

Introduction

The K32L3A60VPJ1AT MCU is a next generation Kinetis dual core device.  This device brings processing and multi-tasking capabilities that legacy Kinetis devices did not support.  In addition, the K32L3A60VPJ1AT offers improved power consumption and security features.   Some important aspects of these security features lie in a nonvolatile information register (IFR) memory region and how this region is programmed.  The IFR memory region is a memory space with restricted access separate from the main array and is comprised of an erasable IFR region and a non-erasable IFR region.  The non-erasable IFR region contains the program once identifier and the version identifier.  The erasable IFR region holds the flash security, flash options, mass erase enable, and other such features that governs how the device behaves.  In legacy Kinetis devices, certain fields of the main flash array (flash addresses 0x400 - 0x40F) configured the IFR at boot time.  In the K32L3A60VPJ1AT however, the IFR memory region is no longer controlled in this manner.  This presents challenges when trying to configure these settings.  The purpose of this document is to explain how these settings can be changed and provide some options of how to make these changes.  

IFR Field Programming Process

The first step in configuring the IFR fields is understanding how the these fields are programmed via the hardware. IFR fields are programmed using a special flash command called the Program Index Command. Once programmed, the flash configuration values cannot be reprogrammed without first erasing these fields.  The only way to erase these values is via a mass erase.  This provides security in that the IFR values cannot be changed without erasing the user code as well.  In addition, changes to the user code image cannot affect the bootloader operation, ensuring that a secure boot function can be executed.  The procedure for writing the erasable IFR values is described here:

 

  1. Write FCCOB0 with the Program Index command (0x43).
  2. Write FCCOB1 with the Index to be programmed. The possible Indexes are listed in Erasable IFR Map table (table 16.4.1.2 in the K32L3A6 reference manual).
  3. Write FCCOB2 and FCCOB3 with 0x00 as they are not used with this command. 
  4. Write FCCOB4 - FCCOBB with the desired value.  (Note that not all of the indexes use all of the FCCOB fields.  Be sure to consult the Erasable IFR Map table for which FCCOB fields are used for the index you are programming).
    1. NOTE:  For 2 byte IFR fields that map to 2 bit wide register bit fields (i.e., SEC0, FSLACC, MEEN, and KEYEN fields which map to the FSEC register bit fields), the lower FCCOB register maps to the LSB of the bit field and the upper FCCOB register maps to the MSB of the bit field.  For example, to write 0b'10 to the FSEC field, FCCOB6 should be written to 0xFF and FCCOB7 should be written to 0x00 before executing the Flash command. 
  5. Write 0x70 to the Flash status register (FSTAT) to clear any errors that might have been present from the last flash command. (Note that this command MUST be a byte write.)
  6. Write 0x80 to the Flash status register (FSTAT) to initiate the programmed flash command.
  7. Poll the FSTAT register until the CCIF bit field (bit field 7) is one ('1').  (Note that it may not be possible in your scripting language to do this, or it may just be easier to simply wait for the flash command to finish executing. In these cases, wait significantly longer than the typical Program Index command completion time of 110us.)

 

After the IFR has been programmed, the IFR should be read back to verify that it completed correctly.  The process for this is as follows:

 

  1. Write FCCOB0 with the Read Index command (0x41).
  2. Write FCCOB1 with the Index to be read.  The possible Indexes are listed in Erasable IFR Map table (table 16.4.1.2 in the K32L3A6 reference manual).
  3. Write FCCOB2 - FCCOBB with 0. The results will be stored in FCCOB4 - FCCOBB so, these should be cleared to ensure correct results are received.
  4. Write 0x70 to the Flash status register (FSTAT) to clear any errors that might have been present from the last flash command. Note that this command MUST be a byte write.
  5. Write 0x80 to the Flash status register (FSTAT) to initiate the programmed flash command.
  6. Poll the FSTAT register until the CCIF bit field (bit field 7) is one ('1').  (Note that it may not be possible in your scripting language to do this, or it may just be easier to simply wait for the flash command to finish executing. In these cases, wait significantly longer than the maximum Read Index command completion time of 35us.)

 

When using the Program Index Command, you must know which index you want to modify to create the correct flash commands.  The index list can be found in the IFR descriptions section of the Flash chapter in the K32L3A60VPJ1AT reference manual.  

 

There are several different options for programming the FOPT fields. These options are:

  1. Using the Kinetis Flash Tool 
  2. Using blhost
  3. Debugger script
  4. Subroutine in user software

 

Option #1: Kinetis Flash Tool

Using the Kinetis Flash Tool is likely the most convenient method to change the IFR values.  The Kinetis Flash Tool uses either the UART or USB protocol to interface with the K32L3A6 bootloader and write the IFR fields desired. One of the biggest advantages for the Kinetis Flash Tool is that it provides a graphical interface for users to easily program the IFR fields. The following figure is a picture of the Kinetis Flash Tool and highlights the important input controls and tabs to be used when programming the IFR fields:

 

pastedImage_1.png

 

  1. This field is the Port set box.  It selects the interface (UART or USB) to be used when communicating to the bootloader.  This box also allows for configuration of the interface.  Consult the K32L3A6 reference manual for default configurations.  
  2. This is the Flash Utilities tab.  Select this tab to see the controls shown in this image. 
  3. This is the Index input field.  The Index of the IFR to program should be entered here. 
  4. This is the Hex digits field.  This value will be programmed at the IFR Index indicated in the Index field. The value here should be in hex format WITHOUT the preceding "0x". 
    1. Note that this will write to the FCCOBs in descending order.  For example, to write 0b'10 to the KEYEN field, FFFFFF00 should be written to the Hex digits field. Refer to the programming process outlined in the IFR Field Programming Process in this document for more information.   
  5. This is the Byte Count field.  This tells the utility how many bytes to program and must be the byte count of that IFR field.  Consult the Erasable IFR Map table in the reference manual for the value of the specific IFR index to be programmed.  
  6. This is the Program button.  After all of the fields have been filled out, click this button to program the desired IFR location. 

 

Option #2: BLHOST

The MCUBoot package also includes a command line executable to interface with the bootloader.  This tool, blhost, can be used to program the IFR fields as well.  The "flash-program-once" command should be used to program the desired IFR location.  The syntax of this command is as follows:

 

flash-program-once <index> <byteCount> <data>

 

So for example, if you want to program the FOPT IFR field (record index 0x84) with 0xFFFFF3FF, the correct syntax using this command would be

 

flash-program-once 0x84 4 FFFFF3FF

 

After programming, the "flash-read-once" command can be used to read back and verify the programmed IFR field(s).  Below is an example using the previous IFR locations

 

flash-read-once 0x84 4

 

Below is a full example of erasing the device, programming the FOPT IFR, and reading the FOPT IFR back from the command line using blhost.  

 

pastedImage_2.png

When Programming two byte fields, blhost orders the bytes in descending FCCOBx order (just like the Kinetis Flash Tool).  The blhost utility also requires the input to be 4 or 8 byte aligned, but the flash-program-once command only uses the last 2 bytes.  The upper 4 bytes can be padded with 0's or F's. For example, to write the KEYEN field such that the KEYEN bit field is 0b'10, the command would be as follows:

flash-program-once 0x83 4 FFFFFF00

Below is a full example of using the blhost command line to erase the device, program the KEYEN IFR, read the KEYEN IFR back, and evaluate the FSEC bit field using the Attach to Running Target function in a debugger.

 

chris_brown_0-1708720170969.png

 

After executing a pin reset and attaching to the running target:

chris_brown_1-1708704462376.png

 

 

Option #3: Debugger Script

A simple debugger script is another convenient way to write the IFR values.  Debugger scripts are executed in the background of the debug session initiation process (therefore are hidden operations from the user) and typically can be edited easily using any text editor.  However, it can be cumbersome to change the value because this generally must done manually with each programming by the user. With that in mind, it is a good idea to have different connect scripts for different configurations

 

The first step in using a debugger script is writing a debugger script.  The capabilities and syntax of a debugger script are dependent on your toolchain. For the purposes of this document, we will focus on MCUXpresso IDE.  MCUXpresso IDE uses the PokeXX and PeekXX (where XX is 8, 16, or 32 depending on whether you want to byte access, half-word or word access to the desired register) commands, which are debugger agnostic. So the same commands that work on a device will continue to work whether you are debugging with a JLink or CMSIS-DAP, or whatever other debugger you are using. Below is an example of a MCUXpresso connect script which writes the FOPT register and then reads it back for printing to the debug log. 

 

5140 REM ====================Program FOPT===================================
5150 Poke32 this 0x40023004 0x43840000
5160 REM Stuff FCCOB registers with desired FOPT value
5170 Poke32 this 0x40023008 v%
5171 s% = Peek32 this 0x40023008
5172 Print "New Val ";~s%
5180 Poke32 this 0x4002300c 0x00000000
5180 Poke8 this 0x40023000 0x70
5190 Poke8 this 0x40023000 0x80
5200 wait 1000
6000 REM ================== Read FOPT =====================================
6001 REM Now read the FOPT back
6010 Poke32 this 0x40023004 0x41840000
6020 Poke32 this 0x40023008 0x00000000
6030 Poke32 this 0x4002300c 0x00000000
6040 Poke8 this 0x40023000 0x70
6050 Poke8 this 0x40023000 0x80
6060 wait 1000
6070 s% = Peek32 this 0x40023008
6080 Print "New FOPT Val ";~s%

 

Note in the above script that v% is the desired FOPT value and it has been defined in sections of the script not shown (at line 164). 

 

162 REM This is the value to be written to the FOPT
164 v% = 0xfffff3ff

 

After the script is written, MCUXpresso must be told to use the connect script.  This is done in the Debug Configurations window.  Assuming a debug configuration has already been created, click on the arrow next to the green bug icon and select Debug Configurations.  

 

pastedImage_1.png

 

In the resulting dialog box, select the debug configuration you want to use, and select the Linkserver Debug tab.  In the Connect Script field, point MCUXpresso to the location of your connect script.  

 

pastedImage_2.png

 

That's all that needs to be done in the IDE. The selected debug configuration should now be using the script which was written.  

 

Some debuggers will allow standalone command line running of a script, such as a JLink debugger.  As the JLink is one of the more popular external debuggers that we encounter, an example of programming using this script has been provided below.  

 

// Now Program the FOPT
w4 0x40023004, 0x43840000 // The 43 selects the Program Index command. The 84 selects the FOPT IFR field.
// Stuff the FCCOB registers (4-7) with the FOPT value we want to write.
// ** (Boot Settings) **
w4 0x40023008, 0xfffff3ff // Write 0xFFFF_1FFF to boot the M4 from internal Flash. Asserting the NMI pin will force booting from the ROM.
// Write FCCOB registers 8-B with dummy values.
w4 0x4002300c, 0x00000000
// Write the FSTAT register to clear any errors that could have been present.
w1 0x40023000, 0x70
// Launch the flash command.
w1 0x40023000, 0x80
// Wait for the flash command to finish.
Sleep 1

// Now Read the FOPT back
w4 0x40023004, 0x41840000 // The 43 selects the Program Index command. The 84 selects the FOPT IFR field.

// Stuff the FCCOB registers (4-7) with the FOPT value we want to write.
// ** (Boot Settings) **
w4 0x40023008, 0x00000000 // Write 0xFFFF_F1FF to boot the M0+ from internal Flash. Asserting the NMI pin will force booting from the ROM.

// Write FCCOB registers 8-B with dummy values.
w4 0x4002300c, 0x00000000

// Write the FSTAT register to clear any errors that could have been present.
w1 0x40023000, 0x70

// Launch the flash command.
w1 0x40023000, 0x80

// Wait for the flash command to finish.
Sleep 1
// Read the memory back to verify the FOPT settings that should be present after reset.
mem32 40023000,4

 

 

Option #4: Subroutine in User Software

Occasionally the requirements of your system will prevent implementation of any of the above methods to program the IFR values.  In these cases, you may need to implement your own subroutine to program the IFR.  The procedure to do this is essentially the same as in the debugger script methods, just written in code instead of an external script. 

The flash drivers provided in the SDK aid in this process.  One key to remember is that you likely will need to erase the entire flash.  So this subroutine and flash drivers should be placed in RAM memory.  The SDK flash drivers also operate a little differently from the Kinetis flash tool and blhost.  The FCCOB registers will be loaded in ascending order.  For example, to write 0b'10 to the SEC0 bit field in the FSEC register, the command would be:

result = FLASH_ProgramOnce(&s_flashDriver, 0x80, ifr2write, 0x2);

where ifr2write is an array defined as

uint8_t ifr2write[2] = {0x00, 0xFF};

The above will result in 0x00 being loaded to FCCOB6 and 0xFF being loaded to FCCOB7 and SEC0 will then be 0b'10 on the reset after the command is successfully executed.  

Conclusion

In summary, the IFR registers are nonvolatile information registers that govern certain behaviors of the K32L3A MCU.  The IFR is dividing into an erasable IFR space and non-erasable IFR space, both of which are not a part of the main flash array.  Programming these values requires the use of special flash commands and requires that these values haven't been previously written since the last mass erase.  There are, in general, four different methods of programming the FOPT register settings.  The four methods are:

 

  1. Kinetis Flash Tool
  2. BLhost command line interface
  3. Debugger script 
  4. User software subroutine

 

Each method has its advantages, therefore, you should pick the one that meets your needs and is most convenient. However with any of the methods chosen, the IFR values must not have been programmed before writing erasable IFR fields. It is best to perform a mass erase (which can be done using any of the methods presented in this document) before attempting to program any IFR fields.     

No ratings
Version history
Last update:
‎02-23-2024 01:33 PM
Updated by: