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:
Solved! Go to Solution.
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
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.
- // Write: FSTAT register to launch command
- FTMRE_FSTAT = 0x80;
- // Wait for the flash command in progress.
- while ((FTMRE_FSTAT & FTMRE_FSTAT_CCIF_MASK) == 0x00)
- ;
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.
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?
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
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
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:
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
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)
; |
}
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
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.
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:
Regards
Mark
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.
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
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: