Writing to flash works in debug but not in run mode

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

Writing to flash works in debug but not in run mode

Jump to solution
3,423 Views
abdullahkahrama
Contributor IV

Hello,

I am working with a MKE04Z8M4 microcontroller. I am trying to use FLASH area to store some configuration values. I have a routine to write to a certain FLASH memory address but it works only when I do step by step debug. It doesn't work in run mode. Also, when I debug it and click run, it doesn't work that way, either. There is no compiler optimization. Here is my code:

void FLASH_program(void)

{

    // Read FCLKDIV register

    if (FTMRE_FCLKDIV != 0x17)

    {

        // If FCLKDIV register not correct,

        // Wait for any flash command in progress.

        while ((FTMRE_FSTAT & FTMRE_FSTAT_CCIF_MASK) == 0x00)

            ;

        // Write FLCKDIV register

        FTMRE_FCLKDIV = FTMRE_FCLKDIV_FDIV(0x17);

    }

    else

    {

        // If FCLKDIV register is correct,

        // Wait for any flash command in progress.

        while ((FTMRE_FSTAT & FTMRE_FSTAT_CCIF_MASK) == 0x00)

            ;

    }

    // Access Error and or Protection Violation Check

    if (((FTMRE_FSTAT & FTMRE_FSTAT_ACCERR_MASK) == 1)

            || ((FTMRE_FSTAT & FTMRE_FSTAT_FPVIOL_MASK) == 1))

    {

        // Write: FSTAT register: Clear ACCERR and FPVIOL

        FTMRE_FSTAT = 0x30;

    }

    // Write to FCCOBIX register to identify specific command parameter to load

    FTMRE_FCCOBIX = 0x00;

    // Write to FCCOB register to load required command parameter

    FTMRE_FCCOBHI = 0x06; // Program flash command code

    FTMRE_FCCOBLO = 0x00; // Global address [23:16] to identify flash block

    FTMRE_FCCOBIX = 0x01;

    FTMRE_FCCOBHI = 0x1D; // Global address [15:0] of longwords location to be programmed

    FTMRE_FCCOBLO = 0xFC; // Global address [1:0] must be 0x00

    FTMRE_FCCOBIX = 0x02;

    FTMRE_FCCOBHI = 0x00; // Word 0 (longword 0) program value

    FTMRE_FCCOBLO = 0x00; // (unsigned char) (PWM_duty_H1);

    FTMRE_FCCOBIX = 0x03;

    FTMRE_FCCOBHI = 0x00; // Word 1 (longword 0) program value

    FTMRE_FCCOBLO = 0x00; // (unsigned char) (PWM_duty_H2);

    FTMRE_FCCOBIX = 0x04;

    FTMRE_FCCOBHI = 0x00; // (unsigned char) (current_limit_FW >> 8); // Word 2 (long3word 1) program value

    FTMRE_FCCOBLO = 0x00; // (unsigned char) (current_limit_FW);

    FTMRE_FCCOBIX = 0x05;

    FTMRE_FCCOBHI = 0x00; // (unsigned char) (current_limit_BW >> 8); // Word 3 (longword 1) program value

    FTMRE_FCCOBLO = 0x00; // (unsigned char) (current_limit_BW);

    // Write: FSTAT register to launch command

    FTMRE_FSTAT = 0x80;

    // Wait for the flash command in progress.

    while ((FTMRE_FSTAT & FTMRE_FSTAT_CCIF_MASK) == 0x00)

        ;

}

Here is how my memory configured in the Processor Expert:

addr.png

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

Hi Abdullah

You are calling the routine incorrectly for the KE devices

fnRAM_code((volatile unsigned char *) FTFL_BLOCK); will work for for K and KL devices because the status register is the first entry and so is equal to the block address.


For the KE family you can use

fnRAM_code((volatile unsigned char *) FLASH_STATUS_REGISTER);


where FLASH_STATUS_REGISTER is either (FTFL_BLOCK + 5) or directly

#define FLASH_STATUS_REGISTER    0x40020005                // Flash Memory Module  Status Register Address


Regards


Mark


View solution in original post

12 Replies
2,123 Views
mjbcswitzerland
Specialist V

Hi Abdullah

You need to run the programming part (the bit below) in SRAM (it can't run in Flash since it causes the program to fail when executing it). It is also advisable to disable interrupt while programming too.

  1.     // Write: FSTAT register to launch command 
  2.     FTMRE_FSTAT = 0x80; 
  3.  
  4.     // Wait for the flash command in progress. 
  5.     while ((FTMRE_FSTAT & FTMRE_FSTAT_CCIF_MASK) == 0x00
  6.         ; 

There are quite an number of forum threads on the topic - for example: Re: Serial number programming in production - Kinetis K10 (the basics are the same for KE, KL and K devices).

Regards

Mark

P.S. Carefully check that the register FTMRH_FCLKDIV is set correctly for the bus clock when using the KE. If it isn't it may be under or over programnming which can result in unreliability or potential damage. PE probably does it for you but I wouldn't blindly trust it because such tools also can make mistakes.

2,123 Views
abdullahkahrama
Contributor IV

Hello Mark,

Thank you for your answer.

I have done a little research on this subject and when I was trying to change the linker file, I have noticed that it is maintained by Processor Expert. I am trying to write my routines for writing to flash and erasing it. I am only using "Init_FTMR" component to initialize it.

I have found AN4497 and also some other threads on this forum but their pragma directives doesn't work and also linker file is altered all the time by processor expert.

I have also found out this tutorial. Quoted from this tutorial is below. I didn't understand where I will right click and do the instructions he mentioned.

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.

Do you have any idea how can I put a function to RAM when I am using Processor Expert?

0 Kudos
2,123 Views
mjbcswitzerland
Specialist V

Hi Abdullah

I don't use PE so don't know details.

However the link that I gave gives code to do it very simply without needing to do any linker script changes.

Regards

Mark

µTasker Kinetis support

2,123 Views
abdullahkahrama
Contributor IV

Hello Mark,

Yes, I am aware of the code that you have written and I can see that it was helpful to many people. Thank you for your contribution to the community Smiley Happy

However, I cannot implement your code. When I write below code, in debugger it goes into an endless loop.

#define PROG_WORD_SIZE 30  // adequate space for the small program

#define CAST_POINTER_ARITHMETIC unsigned long   // Kinetis uses 32 bit pointers

#define FTFL_BLOCK    0x40020000                // Flash Memory Module

static unsigned short fnFlashRoutine[] =

{ 0x2180, 0x7001, 0x7801, 0x0609, 0xd5fc, 0x4770 };

void FLASH_program(void)

{

    static void (*fnRAM_code)(volatile unsigned char *) = 0;

    if (!fnRAM_code)

    {

        // the first time this is used it will load the program to SRAM

        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);

    }

    // Read FCLKDIV register

    if (FTMRE_FCLKDIV != 0x17)

    {

        // If FCLKDIV register not correct,

        // Wait for any flash command in progress.

        while ((FTMRE_FSTAT & FTMRE_FSTAT_CCIF_MASK) == 0x00)

            ;

        // Write FLCKDIV register

        FTMRE_FCLKDIV = FTMRE_FCLKDIV_FDIV(0x17);

    }

    else

    {

        // If FCLKDIV register is correct,

        // Wait for any flash command in progress.

        while ((FTMRE_FSTAT & FTMRE_FSTAT_CCIF_MASK) == 0x00)

            ;

    }

    // Access Error and or Protection Violation Check

    if (((FTMRE_FSTAT & FTMRE_FSTAT_ACCERR_MASK) == 1)

            || ((FTMRE_FSTAT & FTMRE_FSTAT_FPVIOL_MASK) == 1))

    {

        // Write: FSTAT register: Clear ACCERR and FPVIOL

        FTMRE_FSTAT = 0x30;

    }

    // Write to FCCOBIX register to identify specific command parameter to load

    FTMRE_FCCOBIX = 0x00;

    // Write to FCCOB register to load required command parameter

    FTMRE_FCCOBHI = 0x06; // Program flash command code

    FTMRE_FCCOBLO = 0x00; // Global address [23:16] to identify flash block

    FTMRE_FCCOBIX = 0x01;

    FTMRE_FCCOBHI = 0x1E; // Global address [15:0] of longwords location to be programmed

    FTMRE_FCCOBLO = 0x00; // Global address [1:0] must be 0x00

    FTMRE_FCCOBIX = 0x02;

    FTMRE_FCCOBHI = 0x00; // Word 0 (longword 0) program value

    FTMRE_FCCOBLO = 0x00; // (unsigned char) (PWM_duty_H1);

    FTMRE_FCCOBIX = 0x03;

    FTMRE_FCCOBHI = 0x00; // Word 1 (longword 0) program value

    FTMRE_FCCOBLO = 0x00; // (unsigned char) (PWM_duty_H2);

    FTMRE_FCCOBIX = 0x04;

    FTMRE_FCCOBHI = 0x00; // (unsigned char) (current_limit_FW >> 8); // Word 2 (long3word 1) program value

    FTMRE_FCCOBLO = 0x00; // (unsigned char) (current_limit_FW);

    FTMRE_FCCOBIX = 0x05;

    FTMRE_FCCOBHI = 0x00; // (unsigned char) (current_limit_BW >> 8); // Word 3 (longword 1) program value

    FTMRE_FCCOBLO = 0x00; // (unsigned char) (current_limit_BW);

    // Write: FSTAT register to launch command

    //FTMRE_FSTAT = 0x80;

    fnRAM_code((volatile unsigned char *) FTFL_BLOCK); // execute the command from SRAM

    // Wait for the flash command in progress.

    while ((FTMRE_FSTAT & FTMRE_FSTAT_CCIF_MASK) == 0x00);

}

In the debugger, it loops between these marked lines:

addr.png

0 Kudos
2,124 Views
mjbcswitzerland
Specialist V

Hi Abdullah

You are calling the routine incorrectly for the KE devices

fnRAM_code((volatile unsigned char *) FTFL_BLOCK); will work for for K and KL devices because the status register is the first entry and so is equal to the block address.


For the KE family you can use

fnRAM_code((volatile unsigned char *) FLASH_STATUS_REGISTER);


where FLASH_STATUS_REGISTER is either (FTFL_BLOCK + 5) or directly

#define FLASH_STATUS_REGISTER    0x40020005                // Flash Memory Module  Status Register Address


Regards


Mark


2,123 Views
abdullahkahrama
Contributor IV

YAY! Thank you very much, it worked :smileyhappy:

However, I cannot do an "Erase Flash Block" command. The debugger says "ARM transaction fault". Here is my code:

#define PROG_WORD_SIZE    10  // adequate space for the small program
#define CAST_POINTER_ARITHMETIC   unsigned long   // Kinetis uses 32 bit pointers
#define FLASH_STATUS_REGISTER   0x40020005            // Flash Memory Module

static unsigned short fnFlashRoutine[] =

{ 0x2180, 0x7001, 0x7801, 0x0609, 0xd5fc, 0x4770 };

void FLASH_erase(void)

{

    static void (*fnRAM_code)(volatile unsigned char *) = 0;

    if (!fnRAM_code)

    { // the first time this is used it will load the program to SRAM

   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);

    }

    // Read FCLKDIV register

    if (FTMRE_FCLKDIV != 0x17)

    {

   // If FCLKDIV register not correct,
   // Wait for any flash command in progress.
   while ((FTMRE_FSTAT & FTMRE_FSTAT_CCIF_MASK) == 0x00)
   ;
   // Write FLCKDIV register
   FTMRE_FCLKDIV = FTMRE_FCLKDIV_FDIV(0x17);

    }

    else

    {

   // If FCLKDIV register is correct,
   // Wait for any flash command in progress.
   while ((FTMRE_FSTAT & FTMRE_FSTAT_CCIF_MASK) == 0x00)
   ;

    }

    // Access Error and or Protection Violation Check

    if (((FTMRE_FSTAT & FTMRE_FSTAT_ACCERR_MASK) == 1)

   || ((FTMRE_FSTAT & FTMRE_FSTAT_FPVIOL_MASK) == 1))

    {

   // Write: FSTAT register: Clear ACCERR and FPVIOL
   FTMRE_FSTAT = 0x30;

    }

    // Write to FCCOBIX register to identify specific command parameter to load

    FTMRE_FCCOBIX = 0x00;

    // Write to FCCOB register to load required command parameter

    FTMRE_FCCOBHI = 0x09; // Erase flash block command code

    FTMRE_FCCOBLO = 0x00; // Global address [23:16] to identify flash block

    FTMRE_FCCOBIX = 0x01;

    FTMRE_FCCOBHI = 0x1E; // Global address [15:0] of longwords location to be programmed

    FTMRE_FCCOBLO = 0x00; // Global address [1:0] must be 0x00

    // Write: FSTAT register to launch command

    //FTMRE_FSTAT = 0x80;

    fnRAM_code((volatile unsigned char *) FLASH_STATUS_REGISTER); // execute the command from SRAM

    // Wait for the flash command in progress.

    while ((FTMRE_FSTAT & FTMRE_FSTAT_CCIF_MASK) == 0x00)

   ;

}

0 Kudos
2,123 Views
mjbcswitzerland
Specialist V

Hi Abdullah

Please could you try the command

FTMRE_FCCOBHI = 0x0a;

instead of 0x09?

Note also that you don't need the following code after the flashing operation since it is already performed in the RAM routine:

    // Wait for the flash command in progress.

    while ((FTMRE_FSTAT & FTMRE_FSTAT_CCIF_MASK) == 0x00)

  

;

Regards

Mark

2,123 Views
abdullahkahrama
Contributor IV

Hello Mark,

Thank you :smileyhappy:

I have tried it with command 0x0A instead of 0x09 and it didn't work either, but then I have disabled the interrupts and 0x0A (Erase Flash Sector) command worked :smileyhappy:

However, 0x09 (Erase Flash Block) command doesn't still work. I am puzzled why this happens.

0 Kudos
2,123 Views
mjbcswitzerland
Specialist V

Hi Abdullah

The erase flash block command will erase the complete Flash block (128k) and is not very useful unless you want to completely destroy the code that is operating (it will of course crash once it has deleted itself).

If you however still need this command you can look at the status that it returns because it give details as to why it couldn't be executed:

pastedImage_0.png

Regards

Mark

µTasker Kinetis support

2,123 Views
abdullahkahrama
Contributor IV

I see, Mark. However, when I try to launch 0x09 command, the CPU goes into a stage and crashes and I cannot even program it without mass erasing, it doesn't accept RESET. The last instruction before it goes mad is "cpy sp,r7". I have added a "while(1)" just after launching the command and just before exiting function, and checked the debugger and FSTAT register is 0x80, meaning the command is completed with success.

Anyways, I will use 0x0A and it will do the trick. Thank you very much for your help.

0 Kudos
2,123 Views
mjbcswitzerland
Specialist V

Abdullah

As I wrote, the block erase command is not useful for normal programs since it destroys the complete software that is loaded and will immediately crash after the erase.

It is also normal that after a block erase the processor is in the secure state (because the FSEC byte in Flash is set to 0xff). It is then necessary to unlock the processorbefore it can be worked with again (the FSEC byte in a new Fash is not 0xff but 0xfe).

The mass erase that the debuggers do is in fact a block erase (or a mass erase if the chip has more than 2 block - although the erase command actually used is not important) followed by writing the FSEC byte to 0xfe before the chip is reset - this avoids the secure state - or recovers from a secured state, depending on how you look at it.

Regards

Mark

2,123 Views
abdullahkahrama
Contributor IV

Hello Mark,

Oh, I understand now. Then, as you say, the block erase command is useless for me.

Thank you for all your help, I can now read and write to FLASH :smileyhappy:

0 Kudos