Arm Community
Arm Community
  • Site
  • User
  • Site
  • Search
  • User
Arm Community blogs
Arm Community blogs
Embedded and Microcontrollers blog Writing Data To Flash During Program Execution With The Freescale KL25z Series.
  • Blogs
  • Mentions
  • Sub-Groups
  • Tags
  • Jump...
  • Cancel
More blogs in Arm Community blogs
  • AI blog

  • Announcements

  • Architectures and Processors blog

  • Automotive blog

  • Embedded and Microcontrollers blog

  • Internet of Things (IoT) blog

  • Laptops and Desktops blog

  • Mobile, Graphics, and Gaming blog

  • Operating Systems blog

  • Servers and Cloud Computing blog

  • SoC Design and Simulation blog

  • Tools, Software and IDEs blog

Tags
  • Flash Technology
Actions
  • RSS
  • More
  • Cancel
Related blog posts
Related forum threads

Writing Data To Flash During Program Execution With The Freescale KL25z Series.

Elliott Smith
Elliott Smith
December 2, 2013

This article explains how we wrote data to flash during program execution when developing the batteryless energy harvesting remote control. This remote control used an MCU from the Freescale KL25z series. The MkL25Z128VLK4 was used. Please be aware that, if done incorrectly, this can kill your MCU.

Defining a region in memory to store the data

The starting point for flashing data is to define a memory region to store the data in. At this point it is necessary to look at the memory map for the device to see where the flash is located and if there are any protected/reserved regions in it. If we look at the Freescale MkL25z series reference manual we can see that the regions specified in the example code below are suitable to store the data.

/*------------------------------------------------------------------------------
  Data stores for eink frame buffer and IR codes. 
    Volatile to prevent compiler optimisation
 *------------------------------------------------------------------------------*/
volatile ir_command device_1[45] __attribute__((at(0x09000)));
volatile ir_command device_2[45] __attribute__((at(0x0A000)));
volatile ir_command device_3[45] __attribute__((at(0x0B000)));
volatile ir_command device_4[45] __attribute__((at(0x0C000)));
volatile char frame_buff_store[176][33] __attribute__((at(0x0D000)));
volatile int page __attribute__((at(0x0C500)));
volatile int device __attribute__((at(0x0C504)));
volatile int signed tv_locat[6] __attribute__((at(0x0C800)));
volatile int signed dvd_locat[6] __attribute__((at(0x0CF00)));


These regions have been defined as global variables. The regions usually have to be long word aligned.

In the energy harvesting remote control example we defined regions for the infra-red commands that the remote control could “learn”. We also defined regions for the frame buffer, for the page and for the device so that the e-ink display could be altered accordingly. We added regions for the Television and the DVD player locations, these used accelerometer and magnetometer values to determine where the remote was pointing. If pointing at the television, the device would automatically switch to the Television User Interface.

Using Memory View in Keil Debugger

The next stage of the process is to test whether it is safe to flash the regions chosen. Memory View in Keil Debugger is excellent for this. Look at the 1 KB after the region defined for the data. This region should be blank and unchanging. If it is not it may be necessary to look at the scatter file to see what is next to it.

Once you are happy that you are not going to corrupt something by erasing the block of flash, it is time to erase the flash. For a successful erase to occur, and to ensure that the core does not lockup and reset, it is essential that nothing else is going to use the flash during these operations.

Erasing the block of Flash

This is achieved by placing the code to execute the flash commands into the on-board RAM for execution. To do this you need to right-hand click on the file you are using to write data to flash, and selecting options.  You then need to look at the memory assignment section at the bottom of the page and change the ‘Code / Const’ to a RAM region on your MCU. This will ensure that every time your application starts this section of code is copied into the RAM for execution.

The important registers for the MkL25Z series are the FCCOB registers and, as can be seen in the reference manual, these are numbered 0-B. The FSTAT register is needed to determine if the FCCOB registers are free to use.

/*------------------------------------------------------------------------------
  Erase the flash block containing the sector
 *------------------------------------------------------------------------------*/
int flash_EraseSector(long int sector)
{
    int temp1,temp2,temp3;

    //Dividing the sector address into the 3 bytes before starting to fill the FCCOB
  //registers reduces the risk of the operation being corrupted:

            temp1 = (sector << 8);
            temp1 = temp1 >> 24;
    
            temp2 = (sector << 16);
            temp2 = temp2 >> 24;
    
            temp3 = (sector << 24);
            temp3 = temp3 >> 24;
    
    //Wait until the command complete instruction is cleared indicate the FCCOB registers
  //are available:

            while(((FTFA->FSTAT)&(1UL << 7))==0x00);
    
    //Clear any previous errors from the last operation:
    
            if(!((FTFA->FSTAT)==0x80))
                    {FTFA->FSTAT = 0x30;}

            FTFA->FCCOB0 = 0x09;     // 0x09 is the instruction code for erase
            FTFA->FCCOB1 = temp1;    // Load the segment address into registers
            FTFA->FCCOB2 = temp2;
            FTFA->FCCOB3 = temp3;

            FTFA->FSTAT = 0x80;         // Writing a 1 to bit 7 of the FSTAT register launches 

            // Wait for command completion:

            while(((FTFA->FSTAT)&(1UL << 7))==0x00);

    return 1;

}


The example code above shows exactly how we did the erase for the MkL25Z series. This function is called from another handler function also running directly from RAM to reduce the risk of core lockup. The handler function is shown below. A delay is required between calling the handler function and carrying out flash commands to prevent core lockup. In the example code below this was achieved with a simple for loop.

/*------------------------------------------------------------------------------
  Write a page and device to flash memory.
 *------------------------------------------------------------------------------*/
void flash_memory_tv_loc(signed int ax,signed int ay,signed int az,signed int hx,signed int hy,signed int hz)
{
    int j;
    for(j=0;j<10000;j++); //delay
    flash_EraseSector((int)&tv_locat);
    for(j=0;j<100;j++);
    flash_writeLongWord((int)&tv_locat[0],ax);
    flash_writeLongWord((int)&tv_locat[1],ay);
    flash_writeLongWord((int)&tv_locat[2],az);
    flash_writeLongWord((int)&tv_locat[3],hx);
    flash_writeLongWord((int)&tv_locat[4],hy);
    flash_writeLongWord((int)&tv_locat[5],hz);

}


Writing data to Flash

The final part of writing data to flash is the write itself. This is very similar to erasing but with a different instruction code. The example code shows how this is achieved for the MkL25Z series.

/*------------------------------------------------------------------------------
  Write a long word to an erased flash block
 *------------------------------------------------------------------------------*/
int flash_writeLongWord(long int locat,long int value)
{
        int temp1,temp2,temp3,temp4,temp5,temp6,temp7;

            temp1 = (locat << 8);
            temp1 = temp1 >> 24;
            temp2 = (locat << 16);
            temp2 = temp2 >> 24;
            temp3 = (locat << 24);
            temp3 = temp3 >> 24;
            temp4 = value >> 24;
            temp5 = (value << 8);
            temp5 = temp5 >> 24;
            temp6 = (value << 16);
            temp6 = temp6 >> 24;
            temp7 = (value << 24);
            temp7 = temp7 >> 24;


            while(((FTFA->FSTAT)&(1UL << 7))==0x00);    

            if(!((FTFA->FSTAT)==0x80))
                    {FTFA->FSTAT = 0x30;}

            FTFA->FCCOB0 = 0x06;    //0x06 is instruction code for write long word.

            FTFA->FCCOB1 = temp1;
            FTFA->FCCOB2 = temp2;
            FTFA->FCCOB3 = temp3;
            FTFA->FCCOB4 = temp4;
            FTFA->FCCOB5 = temp5;
            FTFA->FCCOB6 = temp6;
            FTFA->FCCOB7 = temp7;

            FTFA->FSTAT = 0x80;

            while(((FTFA->FSTAT)&(1UL << 7))==0x00);

        return 1;
}


As can be seen, more of the FCCOB registers are required, when compared with an erase, because the location and the value must be specified.The instruction code for writing a long word is 0x06. The instruction code for an erase is 0x09. These can be looked up in the reference manual.

If you have problems with core lockup, check all the pointers for the functions/data you’re using to make sure they’re in RAM.

The next development step is available in the blog below.

Read next development step on infra-red code learning and repeating

Anonymous
Parents
  • emanuele.marraccini
    emanuele.marraccini over 8 years ago

    Dear All,

    In the above article I read that "A delay is required between calling the handler function and carrying out flash commands to prevent core lockup."

    Caould You better explain what is the cause of the core lockup when no delay is added?

    I'm working with Kinetis  MK66FN2M0VMD18 on a custom board, could You confirm that this workaround is needed also for my target?

    Could You estimate the value of the delay to add before the Erase Sector Command and before Write Long Word Command?

    Thanks for Your support.

    Best Regards

    Emanuele

    • Cancel
    • Up 0 Down
    • Reply
    • More
    • Cancel
Comment
  • emanuele.marraccini
    emanuele.marraccini over 8 years ago

    Dear All,

    In the above article I read that "A delay is required between calling the handler function and carrying out flash commands to prevent core lockup."

    Caould You better explain what is the cause of the core lockup when no delay is added?

    I'm working with Kinetis  MK66FN2M0VMD18 on a custom board, could You confirm that this workaround is needed also for my target?

    Could You estimate the value of the delay to add before the Erase Sector Command and before Write Long Word Command?

    Thanks for Your support.

    Best Regards

    Emanuele

    • Cancel
    • Up 0 Down
    • Reply
    • More
    • Cancel
Children
No Data
Embedded and Microcontrollers blog
  • Formally verifying a floating-point division routine with Gappa – part 2

    Simon Tatham
    Simon Tatham
    A method of testing whether a numerical error analysis using Gappa really matches the code it is intended to describe.
    • September 4, 2025
  • Formally verifying a floating-point division routine with Gappa – part 1

    Simon Tatham
    Simon Tatham
    Learn the basics of using Gappa for numerical error analysis, using floating-point division in Arm machine code as a case study.
    • September 4, 2025
  • Adapting Kubernetes for high-performance IoT Edge deployments

    Alexandre Peixoto Ferreira
    Alexandre Peixoto Ferreira
    In this blog post, we address heterogeneity in IoT edge deployments using Kubernetes.
    • August 21, 2024