Mark,
Thanks for the response.
I'm using the FTFE functions in MQX 4.1 to do the actual writes to flash. The ftfe_flash_command_sequence function (see below) resets the FSTAT errors before writing to flash, and after the RAM function completes, checks the errors and returns 0 if no error or the error if there is one. It does not clear the FSTAT register errors if an error is found. This is what confuses me since it is returning an error even though FSTAT doesn't show one.
I tried setting a breakpoint in the below routine where it checks FTFE_FSTAT_ACCERR_MASK and oddly I hit this when erasing. It hits this every time I erase the sectors and my erase routine returns a failure. The FSTAT register reads 0x80 (no errors) at this time, so I don't understand how it could be hitting it. The FSTAT register is read into a variable to determine the errors and the variable also reads 0x80. If I remove the breakpoint the erase routine works every time. That being said, I couldn't set the breakpoint there for when I write since the erase would fail. I'm not doing any optimization so that shouldn't be causing a problem. The code should be compiled as is.
I'm going to adjust the code so the erase happens at a different time so I can set the breakpoint there, and check it while writing.
I have done flash writes on K60's and K66's and have never had this problem, but I was using a different version of MQX also. That's why I question if the K64 may have a problem. If you say you have never seen a problem with writes on the K64 then I don't think its a K64 problem. What MQX version do you use? (if you use MQX)
I just had another thought. Maybe my stack isn't large enough for the task doing the writes... I've seen many strange things with a corrupt stack.
static uint32_t ftfe_flash_command_sequence
(
/* [IN] Flash specific structure */
volatile FTFE_FLASH_INTERNAL_STRUCT_PTR dev_spec_ptr,
/* [IN] Command byte array */
uint8_t *command_array,
/* [IN] Number of values in the array */
uint8_t count,
/* [IN] The address which will be affected by command */
void *affected_addr,
/* [IN] The address which will be affected by command */
uint32_t affected_size
)
{
uint8_t fstat;
uint32_t result;
void (* RunInRAM)(volatile uint8_t *);
#if PSP_MQX_CPU_IS_KINETIS
void (* RunInvalidateInRAM)(uint32_t);
#endif
#if PSP_MQX_CPU_IS_COLDFIRE
uint32_t temp;
#endif
FTFE_MemMapPtr ftfe_ptr;
ftfe_ptr = (FTFE_MemMapPtr)dev_spec_ptr->ftfe_ptr;
/* get pointer to RunInRAM function */
RunInRAM = (void(*)(volatile uint8_t *))(dev_spec_ptr->flash_execute_code_ptr);
/* set the default return as FTFE_OK */
result = FTFE_OK;
/* check CCIF bit of the flash status register */
while (0 == (ftfe_ptr->FSTAT & FTFE_FSTAT_CCIF_MASK))
{ };
/* clear RDCOLERR & ACCERR & FPVIOL error flags in flash status register */
if (ftfe_ptr->FSTAT & FTFE_FSTAT_RDCOLERR_MASK)
{
ftfe_ptr->FSTAT |= FTFE_FSTAT_RDCOLERR_MASK;
}
if (ftfe_ptr->FSTAT & FTFE_FSTAT_ACCERR_MASK)
{
ftfe_ptr->FSTAT |= FTFE_FSTAT_ACCERR_MASK;
}
if (ftfe_ptr->FSTAT & FTFE_FSTAT_FPVIOL_MASK)
{
ftfe_ptr->FSTAT |= FTFE_FSTAT_FPVIOL_MASK;
}
switch (count)
{
case 12: ftfe_ptr->FCCOBB = command_array[--count];
case 11: ftfe_ptr->FCCOBA = command_array[--count];
case 10: ftfe_ptr->FCCOB9 = command_array[--count];
case 9: ftfe_ptr->FCCOB8 = command_array[--count];
case 8: ftfe_ptr->FCCOB7 = command_array[--count];
case 7: ftfe_ptr->FCCOB6 = command_array[--count];
case 6: ftfe_ptr->FCCOB5 = command_array[--count];
case 5: ftfe_ptr->FCCOB4 = command_array[--count];
case 4: ftfe_ptr->FCCOB3 = command_array[--count];
case 3: ftfe_ptr->FCCOB2 = command_array[--count];
case 2: ftfe_ptr->FCCOB1 = command_array[--count];
case 1: ftfe_ptr->FCCOB0 = command_array[--count];
default: break;
}
#if PSP_MQX_CPU_IS_COLDFIRE
temp = _psp_get_sr();
_psp_set_sr(temp | 0x0700);
#elif PSP_MQX_CPU_IS_KINETIS
__disable_interrupt ();
#endif //PSP_MQX_CPU_IS_KINETIS
/* run command and wait for it to finish (must execute from RAM) */
RunInRAM(&ftfe_ptr->FSTAT);
/* get flash status register value */
fstat = ftfe_ptr->FSTAT;
#if PSP_MQX_CPU_IS_KINETIS
RunInvalidateInRAM = (void(*)(uint32_t))(dev_spec_ptr->flash_invalidate_code_ptr);
RunInvalidateInRAM((uint32_t)FLASHX_INVALIDATE_CACHE_ALL);
#endif
/*
invalidate data cache of 'affected_addr' address and 'affected_size' size
because reading flash through code-bus may show incorrect data
*/
#if defined(_DCACHE_INVALIDATE_MLINES) || defined(_ICACHE_INVALIDATE_MLINES)
if (affected_size)
{
#if defined(_DCACHE_INVALIDATE_MLINES)
_DCACHE_INVALIDATE_MLINES(affected_addr, affected_size);
#endif
#if defined(_ICACHE_INVALIDATE_MLINES)
_ICACHE_INVALIDATE_MLINES(affected_addr, affected_size);
#endif
}
#endif
#if PSP_MQX_CPU_IS_COLDFIRE
_psp_set_sr(temp);
#elif PSP_MQX_CPU_IS_KINETIS
__enable_interrupt();
#endif //PSP_MQX_CPU_IS_KINETIS
/* checking access error */
if (0 != (fstat & FTFE_FSTAT_ACCERR_MASK))
{
/* return an error code FTFE_ERR_ACCERR */
result = FTFE_ERR_ACCERR;
}
/* checking protection error */
else if (0 != (fstat & FTFE_FSTAT_FPVIOL_MASK))
{
/* return an error code FTFE_ERR_PVIOL */
result = FTFE_ERR_PVIOL;
}
/* checking MGSTAT0 non-correctable error */
else if (0 != (fstat & FTFE_FSTAT_MGSTAT0_MASK))
{
/* return an error code FTFE_ERR_MGSTAT0 */
result = FTFE_ERR_MGSTAT0;
}
return result;
}