FRDM-KL03Z Reading WriteOnce Special area of 0 IFR fails with reset and LOCKUP bit set in SRS1.
Hello.
I'm using FRDM-KL03Z board and i want to read 64 special bytes (WriteOnce area) located in 0 IFR area.
Following reference maual i wrote code, but it seems to be working very strange.
If I run it under debugger, step by step - everything seems to be ok, but, when it is free running it fails with reset and LOCKUP bit set in SRS1 register (catched in debugger).
commenting line 23 results at program is running fine (but is ofcourse not doing anything).
Here is my code:
main.c
#include "MKL03Z4.h" static unsigned char ifr[64]; int main(void) { #define RDONCE 0x41 //check and evt. wait for flash command to ready. while ((FTFA->FSTAT & FTFA_FSTAT_CCIF_MASK) == 0) { // busy... __asm__ volatile ("nop"); } //reset errors FTFA->FSTAT = FTFA_FSTAT_FPVIOL_MASK | FTFA_FSTAT_ACCERR_MASK | FTFA_FSTAT_RDCOLERR_MASK; // clear errors for (unsigned char i=0; i < 0x10; i++) { FTFA->FCCOB0=RDONCE; FTFA->FCCOB1=i; //FTFA->FCNFG |= FTFA_FCNFG_RDCOLLIE_MASK; //read collision detection //start command FTFA->FSTAT = FTFA_FSTAT_CCIF_MASK; while ((FTFA->FSTAT & FTFA_FSTAT_CCIF_MASK) == 0) { // wait for finish ... __asm__ volatile ("nop"); } if ((FTFA->FSTAT & FTFA_FSTAT_FPVIOL_MASK ) || (FTFA->FSTAT & FTFA_FSTAT_ACCERR_MASK )){ // debug("x",0); FTFA->FSTAT = FTFA_FSTAT_FPVIOL_MASK | FTFA_FSTAT_ACCERR_MASK | FTFA_FSTAT_RDCOLERR_MASK; // clear errors } else { // debug(".",0); } ifr[i*4]=FTFA->FCCOB4; ifr[i*4+1]=FTFA->FCCOB5; ifr[i*4+2]=FTFA->FCCOB6; ifr[i*4+3]=FTFA->FCCOB7; } while (1) { __asm__ volatile ("nop"); } return 0; }
I'am looking for any help, what i'am doing wrong?
Please check attachment, its simple project in KDS3 with this code.
Original Attachment has been moved to: testt.zip
Hi,
I think I find out the root cause of the issue, the Flash command sequence be launched in the RAM instead of Flash.
And I've attached an application note which illustrates how to relocate the code and data in internal RAM.
Hope it helps.
Have a great day,
Ping
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hello.
I think I find out the root cause of the issue, the Flash command sequence be launched in the RAM instead of Flash.
You are right.
When i call the command from RAM it is working as expected.
Because i'm using smallest version of ARM, and i need as much ARM RAM as possible, i did programmed a nice dirty tricky code
It uses only 12 bytes anywhere in RAM to do the job, without any change in linker file etc. I may say Plug'n'Play. I hope somebody will enjoy this code:
#include "MKL03Z4.h"
void read_pr0m (void);
//FTFA code
extern const int FTFA_ramcodesize; // define external const to access it from another section
__attribute__ ((naked)) int FTFA_call(volatile void* vram, volatile void* ftfa); // returns error bits from FTFA_FSTAT. 0 = no errors.
__attribute__ ((naked,used)) void FTFA_ramcode (void); // the movable part of the code
__attribute__ ((naked)) void FTFA_init_ramcode (volatile void* FTFA_ram, unsigned int FTFA_ramcodesize); // prepare code in ARM RAM
static unsigned char pr0m[64];
int main(void)
{
read_pr0m();
while (1) {
// infinite loop.
__asm__ volatile ("nop");
}
return 0;
}
void read_pr0m (void) {
#define RDONCE 0x41
volatile unsigned char vram [FTFA_ramcodesize]; // of course,you can use malloc or whatever to allocate 'FTFA_ramcodesize' bytes of memory in ARM RAM
// but ... compiler can do that ... gratis, and will free that memory when you exit this function :smileywink:
FTFA_init_ramcode (vram , FTFA_ramcodesize); //prepare function in RAM
//clear evt. errors before start
FTFA->FSTAT = FTFA_FSTAT_FPVIOL_MASK | FTFA_FSTAT_ACCERR_MASK | FTFA_FSTAT_RDCOLERR_MASK;
for (unsigned char i=0; i < 0x10; i++) {
FTFA->FCCOB0=RDONCE; //load command to FCCOB0
FTFA->FCCOB1=i; //load Block number to read
if (FTFA_call(vram, &FTFA->FSTAT)) { // START command (call code in ARM RAM)
__asm__ ("mov r0,r0"); //do something if error
} else {
__asm__ ("mov r1,r1"); //do something if OK.
}
pr0m[i*4]=FTFA->FCCOB4;
pr0m[i*4+1]=FTFA->FCCOB5;
pr0m[i*4+2]=FTFA->FCCOB6;
pr0m[i*4+3]=FTFA->FCCOB7;
}
}
//copy code from FLASH to ARM RAM
void FTFA_init_ramcode (volatile void* FTFA_ram, unsigned int size) { // naked // assume EABI, FTFA_ram in r0, FTFA_ramcodesize in r1, r2-r3 are scratch registers
__asm__ volatile ( // move call ruotine to ram
"ldr r2, =FTFA_ramcodestart \n\t" // load start adress of routine
"LOOP1: \n\t" // loop label
"sub r1, r1, #4 \n\t" // decrement by 0x04
"ldr r3, [r2, r1] \n\t" // load source
"str r3, [r0, r1] \n\t" // store destination
"bne LOOP1 \n\t" // loop if there is still some words to move
"bx lr \n\t" // return
);
}
void FTFA_ramcode (void){ // naked // used // may be executed anywhere (i hope)
__asm__ volatile (
".global FTFA_ramcodesize \n\t" // export global variable
".global FTFA_ramcodestart \n\t"
".align \n\t" //align to word boundary. Do not remove
"FTFA_ramcodestart: \n\t" // entry point
"strb r2, [r1] \n\t" // FTFA->FSTAT = FTFA_FSTAT_CCIF_MASK;
"LOOP: \n\t" //loop label.
"ldrb r0, [r1] \n\t" // wait for CCIF set, load FTFA_FSTAT
"tst r2, r0 \n\t" // check if CCIF bit is sef
"beq LOOP \n\t" // loop, jump if r0==0x00
"bx lr \n\t" // at this point we have FTFA_FSTAT value in r0, return from subroutine
".align \n\t" //align to word boundary. Do not remove
"FTFA_ramcodeend: \n\t"
"FTFA_ramcodesize: .word FTFA_ramcodeend-FTFA_ramcodestart \n\t" // size of the code.
);
}
int FTFA_call(volatile void* vram, volatile void* ftfa) { // naked //assume EABI, vram in r0, tfta in r1, r2-r3 are scratch registers //return error bits in r0
__asm__ volatile (
// "push {lr} \n\t"
"mov r3, lr \n\t" // remember return address in r3 (scratch register) instead pushing it on stack.
"mov r2, #0b0000000000000001 \n\t" // load thumb bit mask
"orr r0, r2 \n\t" // set lsb - thumb code flag for blx
"mov r2, %[ftfa_fstat_ccif_mask] \n\t" // load FTFA_FSTAT_CCIF_MASK mask to r2
"cpsid i \n\t" // disable interrupts
"blx r0 \n\t" // jump to ram, on return we got FTFA_FSTAT value in r0
"cpsie i \n\t" // enable interrupts
// "ldrb r0, [r1] \n\t" // not necessary as we already have it in r0
"mov r1, %[ftfa_fstat_err_mask] \n\t" // mask unused bits
"and r0, r0, r1 \n\t" // EABI - return value in r0, 0 no error, !0 error bits
// "pop {pc} \n\t"
"mov pc, r3 \n\t" // return
::
[ftfa_fstat_ccif_mask] "I" (FTFA_FSTAT_CCIF_MASK), //CCIF_MASK
[ftfa_fstat_err_mask] "I" (FTFA_FSTAT_FPVIOL_MASK | FTFA_FSTAT_ACCERR_MASK | FTFA_FSTAT_RDCOLERR_MASK) // error mask
:
);
}
Best Regards
willy.
Hi Willy,
Thanks your reply and sharing!
Have a great day,
Ping
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------