KW21Z Flash Memory usage rules

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

KW21Z Flash Memory usage rules

1,898 Views
neal_jackson
Contributor II

I'm trying to port the Openthread KW41Z 512/128 implementation to the KW21Z 256/64. Part of Openthread requires having a nonvolatile settings section. This section is 2 "pages" of 2KB each. The Openthread library uses the flash drivers provided in the SDK to read/write to this section. Here are links to an  example of the linker script, a config file that defines the flash region and base address for the settings section, as well as code that uses the flash SDK functions to manipulate flash. With the KW41Z, this section is at 0x4000. For the KW21Z 256/64, this location is out of bounds for the available flash storage, so I obviously needed to move it.

I've tried relocating this settings section to just before the end of flash at 0x3F000 (or even 0x3E000), which should provide enough room for the 4KB required. However, my application is hardfaulting when attempting to read/write to this section regardless of where I place it. It's not immediately clear to me why writing to this location in flash is causing a hard fault. Is there any information that exists during a hard fault that can help me debug this?

I can't find any mention of the flash page sizes on the KW21Z in the reference manual, and I've just assumed them to be 2KB. Is this correct? Additionally, are there constraints on page boundaries that make 0x3F000 invalid?

Thanks!

Labels (1)
Tags (3)
0 Kudos
12 Replies

1,474 Views
chris_brown
NXP Employee
NXP Employee

Hi neal.jackson@berkeley.edu‌,

There are no errata on KW21Z that wouldn't also appear on KW41Z.  Also, KW41Z and KW21Z share a reference manual, so I'm confused how you would be able to find the page size for KW41Z and not KW21Z (or am I misunderstanding something)?

I'm not that familiar with the OpenThread software. Do you know what the size of the package is?  Do you know why they chose 0x40000 for the address of the config base?  

Regards,

Chris 

0 Kudos

1,474 Views
neal_jackson
Contributor II

Hi Chris,

What I am saying is that there is some kind of bug with either the flash driver as it exists or with the flash controller on the KW21Z. This bug is not documented in the official errata. I had to manually place a delay before all flash commands for them to execute without causing a hardfault.

The size of the binary is just under 0x3C000, so using 0x40000 makes sense.

If I choose a location above 0x3C000 and have the delay for flash commands, the flash part of the application works.

0 Kudos

1,474 Views
chris_brown
NXP Employee
NXP Employee

Hi neal.jackson@berkeley.edu‌,

Firstly I want to say that what I'm about to say I mean with the utmost respect. 

What I am saying is that I really don't believe that KW21Z would behave differently from KW41Z in any way.  So if there are any differences in the KW21Z flash drivers and the KW41Z drivers, then yes, there would be a bug in the driver.  If not, then there is still something we don't quite understand about the port and how it is working on a smaller memory device.  Have you tried your port on the original KW41Z device?  I would be interested to hear those results.  

Best regards,

Chris 

0 Kudos

1,474 Views
neal_jackson
Contributor II

I'm operating under the same assumption - that the KW21Z and KW41Z should behave identically. I agree that the difference is likely due to the smaller memory, as I've found one demonstrable difference between the 256/64KB KW21Z and the 512/128KB KW41Z that I mentioned in a different question. The 256/64KB KW21Z must have its RAM section start at 0x1FFFC000 instead of the 0x1FFF8000 mentioned in the reference manual (pg 147) and used by the 512/128KB KW41Z linker script. Whether this is a difference between the sizes of memory (more likely) or the KW21Z and the KW41Z, I'm not sure. This difference is not documented anywhere I was able to find.

The flash drivers between the KW41Z and KW21Z are identical. I have ordered both the 512/128KB and 256/64KB versions of the KW41Z to do a comparison on my board, and can update when I have those.

I do have a FRDM-KW41Z board, and I'll flash my port onto it and reply back with results. 

0 Kudos

1,474 Views
neal_jackson
Contributor II

Ok, so I'm going to try to more clearly define what conditions are required to get my port to work.

I am using the linker script for the smaller memory KW21Z on the KW41Z, in order to artificially constrain memory sizes.

This defines sections as follows:

/* Specify the memory areas */
MEMORY
{
  m_interrupts          (RX)  : ORIGIN = 0x00000000, LENGTH = 0x00000200
  m_flash_config        (RX)  : ORIGIN = 0x00000400, LENGTH = 0x00000010
  m_text                (RX)  : ORIGIN = 0x00000410, LENGTH = 0x0003FBF0
  m_data                (RW)  : ORIGIN = 0x1FFFB000, LENGTH = 0x00010000
‍‍‍‍‍‍‍}

The only difference here is moving the ram section down to 0x1FFFB000 from the 0x1FFFC000 used by the smaller memory MCU.

I have defined the location to save Openthread settings (2 2kB pages) as 0x3F000.

When the KW21Z port is flashed to the KW41Z, and there is no delay in `flash_command_sequence`, the KW41Z hardfaults immediately. When I include the aforementioned delay, the port works flawlessly on the KW41Z. Additionally, if I select 0x40000 as the Openthread settings location, the port also works. I've also tried 0x30000, as the binary is under 0x30000 in size, but that hardfaults in the same manner as 0x3F000. While changing the settings location, I have also changed the size of the text section in the linker script to not overlap the settings.

When flashing the port to the KW21Z, I see similar behavior. Although not immediately, the application hardfaults eventually if there is no delay. When there is a delay, the port does not hardfault on flash access. The radio doesn't appear to function, but I would imagine that's a separate issue.

Any ideas as to why I can't write to flash below 0x40000 without a delay?

0 Kudos

1,474 Views
chris_brown
NXP Employee
NXP Employee

Hi neal.jackson@berkeley.edu‌,

I was just about to write something similar to what Mark just posted.  This just sounds like a read-while-write problem.  You may be trying to execute code out of the Flash while a flash operation is occurring in that flash array.  So you could try enabling the stalling feature (MCM_PLACR[ESFC] = 1).  This may fix the problem without having the delay.  This bit is described on page 384 of the reference manual.  

You must also know that even with this feature, I don't believe you can perform flash operations on the same SECTOR from which code is executing.  

Best regards,

Chris 

0 Kudos

1,474 Views
neal_jackson
Contributor II

Mark and Chris,

Thanks for the insight. This would make sense based on the errors I am seeing. I'll try setting the bit that Chris mentioned and reply back with results. The sector size on the KW41Z/KW21Z is 2kB, correct? My program does not occupy the last two sectors in the flash plane, so I don't think I will be performing a flash operation on the same sector that my code resides.

Thanks!

0 Kudos

1,474 Views
chris_brown
NXP Employee
NXP Employee

Hi neal.jackson@berkeley.edu‌,

Awesome.  I look forward to hearing the results of your trials.  

Yes, the sector size on KW41Z / KW21Z is 2 KB.  

Regards,

Chris 

0 Kudos

1,474 Views
mjbcswitzerland
Specialist V

Neal

Assuming you have a 512k Flash device, 0x40000 is in the second half of the Flash (usually there are two flash blocks or planes). This would mean that if you write/ease in the second plane you don't seem to have difficulties but if your do it in the first plane you do.

Since code can't run in the plane that is being written/erased it sounds as though the flash driver (running in SRAM / first plane) can't be waiting correctly for operations to terminate, which would result in a hard fault in the first plane but be acceptable in the second plane. Adding delays may cause the code to spin (in SRAM or maybe even in cache) and allow the operations to complete.

Although I don't yet use the KW41, I have used more that 60 other Kinetis parts and never needed a delay so expect it is masking a basic error of this sort rather than being a requirement for the operation.

Regards

Mark

0 Kudos

1,474 Views
neal_jackson
Contributor II

Chris,

I flashed the port to the FRDM-KW41Z board, and it also hardfaults if there is not a delay before issuing flash commands. So it does look like this is an issue with the smaller memory/flash size.

0 Kudos

1,474 Views
neal_jackson
Contributor II

It seems like erasing and writing to flash succeeds when the commands are stepped through using GDB. Is there some kind of delay that is required when performing these flash operations that isn't performed within the driver?

0 Kudos

1,474 Views
neal_jackson
Contributor II

Turns out the flash controller on the kw21z has some errata that requires a delay before operations. I'm using 10000 nop instructions currently at the beginning of 'flash_command_sequence' in 'fsl_flash.c', and it seems to fix it. Less nop instructions probably could be used.

static status_t flash_command_sequence(flash_config_t *config)
{
uint8_t registerValue;

// Add in delay as to not break things
volatile uint32_t i = 0;
for (i = 0; i < 10000; ++i)
{
__asm("NOP"); /* delay */
}

#if FLASH_DRIVER_IS_FLASH_RESIDENT
/* clear RDCOLERR & ACCERR & FPVIOL flag in flash status register */
FTFx->FSTAT = FTFx_FSTAT_RDCOLERR_MASK | FTFx_FSTAT_ACCERR_MASK | FTFx_FSTAT_FPVIOL_MASK;

status_t returnCode = flash_check_execute_in_ram_function_info(config);
if (kStatus_FLASH_Success != returnCode)
{
return returnCode;
}

/* We pass the ftfx_fstat address as a parameter to flash_run_comamnd() instead of using
* pre-processed MICRO sentences or operating global variable in flash_run_comamnd()
* to make sure that flash_run_command() will be compiled into position-independent code (PIC). */
callFlashRunCommand((FTFx_REG8_ACCESS_TYPE)(&FTFx->FSTAT));
#else
/* clear RDCOLERR & ACCERR & FPVIOL flag in flash status register */
FTFx->FSTAT = FTFx_FSTAT_RDCOLERR_MASK | FTFx_FSTAT_ACCERR_MASK | FTFx_FSTAT_FPVIOL_MASK;

/* clear CCIF bit */
FTFx->FSTAT = FTFx_FSTAT_CCIF_MASK;

/* Check CCIF bit of the flash status register, wait till it is set.
* IP team indicates that this loop will always complete. */
while (!(FTFx->FSTAT & FTFx_FSTAT_CCIF_MASK))
{
}
#endif /* FLASH_DRIVER_IS_FLASH_RESIDENT */

/* Check error bits */
/* Get flash status register value */
registerValue = FTFx->FSTAT;

/* checking access error */
if (registerValue & FTFx_FSTAT_ACCERR_MASK)
{
return kStatus_FLASH_AccessError;
}
/* checking protection error */
else if (registerValue & FTFx_FSTAT_FPVIOL_MASK)
{
return kStatus_FLASH_ProtectionViolation;
}
/* checking MGSTAT0 non-correctable error */
else if (registerValue & FTFx_FSTAT_MGSTAT0_MASK)
{
return kStatus_FLASH_CommandFailure;
}
else
{
return kStatus_FLASH_Success;
}
}

0 Kudos