Hi friends.
I'm working on a kinetis MK70FX512VMJ15 and IAR Embedded workbench for ARM (version 6.30.4). I'm writing a flash driver for this device.
I have a problem with erase flash sector command. When i try to launch this command in debug with J-Link, this command is able to erase only few sectors on Program Flash Memory. With some sectors this command doesn't have success but i have no errors in FTFE_FSTAT register (value 0x80). I can't understand why seems to be not possible to erase some of this sectors.
Notice that i execute command from RAM memory as explained in AN4695 and i have also verified ssd attached to this application note. I have no protection set in FTFE_FPROT (value 0xFF).
I can't understand where i'm wrong, i hope you have any idea.
Many thanks for now, bye.
Solved! Go to Solution.
I've solved this problem. It was a mistake of "view memory" window of IAR Embedded Workbench IDE.
I have tried to read erased memory location copying its content in a variable and i see 0xFF as expected.
Thanks for your help, i have another question but i prefer to open a new topic.
Best regards.
I've solved this problem. It was a mistake of "view memory" window of IAR Embedded Workbench IDE.
I have tried to read erased memory location copying its content in a variable and i see 0xFF as expected.
Thanks for your help, i have another question but i prefer to open a new topic.
Best regards.
Hi
Erasing program flash in all KL and K devices is the same (apart from sector size). A driver should not be compiler dependent (I use one which works with GCC, CW, IAR, Keil and Rowley).
Check how you are setting the sector to be erased and also ensure that the address is phrase aligned ([2:0] = 0), eg:
FTFL_FCCOB1 = (unsigned char)(((CAST_POINTER_ARITHMETIC)ptrWord) >> 16); // set address in flash | |
FTFL_FCCOB2 = (unsigned char)(((CAST_POINTER_ARITHMETIC)ptrWord) >> 8); | |
FTFL_FCCOB3 = (unsigned char)((CAST_POINTER_ARITHMETIC)ptrWord); |
If the problem continues please post the erasing code so that it can be checked.
Regards
Mark
Thank you Mark, here you can find the source code of my driver:
#define FLASH_ERASE_SECTOR_CMD_LEN 4
#define FLASH_CMD_OFFSET 0
#define FLASH_CMD_ADDRESS_23_16_OFFSET 1
#define FLASH_CMD_ADDRESS_15_08_OFFSET 2
#define FLASH_CMD_ADDRESS_07_00_OFFSET 3
#define FTFE_ERASE_SECTOR (UBYTE)0x09
void vFlashInit( void )
{
while( ( FTFE_FSTAT & FTFE_FSTAT_CCIF_MASK ) == 0 )
{
/* Wait until CCIF is set */
}
FTFE_FSTAT |= FTFE_FSTAT_RDCOLERR_MASK | FTFE_FSTAT_ACCERR_MASK | FTFE_FSTAT_FPVIOL_MASK;
}
void vTestEraseFlashSector( void )
{
UBYTE ubCommandArray[ FLASH_ERASE_SECTOR_CMD_LEN ];
ULONG ulDestinationAddress;
UBYTE ubIndex;
ulDestinationAddress = (ULONG)0x00001000;
/* Build command */
ubCommandArray[ FLASH_CMD_OFFSET ] = FTFE_ERASE_SECTOR;
ubCommandArray[ FLASH_CMD_ADDRESS_23_16_OFFSET ] = (UBYTE)( ulDestinationAddress >> 16 );
ubCommandArray[ FLASH_CMD_ADDRESS_15_08_OFFSET ] = (UBYTE)( ulDestinationAddress >> 8 );
ubCommandArray[ FLASH_CMD_ADDRESS_07_00_OFFSET ] = (UBYTE)( ulDestinationAddress );
/* Copy to FCCOBx */
for( ubIndex = 0; ubIndex < FLASH_ERASE_SECTOR_CMD_LEN; ubIndex++ )
{
while( ( FTFE_FSTAT & FTFE_FSTAT_CCIF_MASK ) != FTFE_FSTAT_CCIF_MASK )
{
/* Attende fino a che trova il bit settato */
}
wvSetFCCOBxValue( ubIndex, ubCommandArray[ ubIndex ] );
}
/* Launch command */
wenFlashLaunchCommand();
}
static void wvSetFCCOBxValue( UBYTE ubRegIndex, UBYTE ubRegValue )
{
switch( ubRegIndex )
{
case 0:
FTFE_FCCOB0 = ubRegValue;
break;
case 1:
FTFE_FCCOB1 = ubRegValue;
break;
case 2:
FTFE_FCCOB2 = ubRegValue;
break;
case 3:
FTFE_FCCOB3 = ubRegValue;
break;
case 4:
FTFE_FCCOB4 = ubRegValue;
break;
case 5:
FTFE_FCCOB5 = ubRegValue;
break;
case 6:
FTFE_FCCOB6 = ubRegValue;
break;
case 7:
FTFE_FCCOB7 = ubRegValue;
break;
case 8:
FTFE_FCCOB8 = ubRegValue;
break;
case 9:
FTFE_FCCOB9 = ubRegValue;
break;
case 10:
FTFE_FCCOBA = ubRegValue;
break;
case 11:
FTFE_FCCOBB = ubRegValue;
break;
default:
break;
}
}
static __ramfunc EN_DIAGNCODE wenFlashLaunchCommand( void )
{
FTFE_FSTAT |= FTFE_FSTAT_CCIF_MASK;
/* Check CCIF flag */
while( ( FTFE_FSTAT & FTFE_FSTAT_CCIF_MASK ) != FTFE_FSTAT_CCIF_MASK )
{
/* Wait until CCIF is set */
}
return EN_DIAGNCODE_OK;
}
In main application i call first vFlashInit and then vTestEraseFlashSector. Status register is OK (value 0x80) but flash memory seems to be unchanged.
Many thanks, bye.
Hi
Try
FTFE_FSTAT = FTFE_FSTAT_CCIF_MASK;
instead of
FTFE_FSTAT |= FTFE_FSTAT_CCIF_MASK;
Regards
Mark
P.S As reference I use the following code for deleting a sector. Your code is essentially doing the same but is rather more difficult to read. I don't see any need to check the status after every command write.
Note that I also use protect the flashing code from interrupts and use machien code for the flash routine (since it is so simple and it avoids compiler optimisation difficulties where some compilers want to in-line the routine).
while (!(FTFL_FSTAT & FTFL_STAT_CCIF)) {} | // wait for previous commands to complete |
if (FTFL_FSTAT & (FTFL_STAT_ACCERR | FTFL_STAT_FPVIOL)) { | // check for errors in previous command | |
FTFL_FSTAT = (FTFL_STAT_ACCERR | FTFL_STAT_FPVIOL); | // clear old errors |
}
FTFL_FCCOB0 = FCMD_ERASE_FLASH_SECTOR;
FTFL_FCCOB1 = (unsigned char)(((CAST_POINTER_ARITHMETIC)ptrWord) >> 16); // set address in flash
FTFL_FCCOB2 = (unsigned char)(((CAST_POINTER_ARITHMETIC)ptrWord) >> 8);
FTFL_FCCOB3 = (unsigned char)((CAST_POINTER_ARITHMETIC)ptrWord);
uDisable_Interrupt(); | // protect this region from interrupts |
fnRAM_code((volatile unsigned char *)FTFL_BLOCK); | // execute the command from SRAM |
uEnable_Interrupt(); | // safe to accept interrupts again |
return (FTFL_FSTAT & (FTFL_STAT_ACCERR | FTFL_STAT_FPVIOL | FTFL_STAT_MGSTAT0)); // if there was an error this will be non-zero
static unsigned short fnFlashRoutine[] = { | // to avoid potential compiler in-lining of the routine (removing position independency) the machine code is used directly | |||
0x2180, | // MOVS r1,#0x80 | load the value 0x80 (command complete interrupt flag) to register r1 | ||
0x7001, | // STRB r1,[r0,#0x00] | write r1 (0x80) to the passed pointer location (r0) | ||
0x7801, | // LDRB r1,[r0,#0x00] | read back from the same location to r1 | ||
0x0609, | // LSLS r1,r1,#24 | shift the register content by 24 bits to the left so that the command complete interrupt flag is at bit 31 | ||
0xd5fc, | // BPL | -4 | if the command complete interrupt flag bit is '0' (register content is not negative value) branch back to read its value again | |
0x4770 | // BX | lr | return from sub-routine |
};