Flash write always fails with -Os optimization

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

Flash write always fails with -Os optimization

Jump to solution
5,391 Views
PabloRY42
Contributor II

Hi guys,

Happy New Year!, a little bit later jaja...

I'm using a KE04 microcontroller on MCUXpresso (SDK v2.8.0) and since I have the 8kb microcontroller I use the Optimization for size (-Os) but also I want to write the flash memory. The thing is that my program fails when I try to write the memory and I'm using the -Os, with others optimization options works fine.

Does anybody know how to fix this?

Best Regards.

Pablo.

Labels (1)
Tags (3)
0 Kudos
Reply
1 Solution
5,340 Views
myke_predko
Senior Contributor III

Hi @PabloRY42 

I think I have a clue as to what's happening - I'm not sure you've properly set up your "nonVolatileVars" and using it correctly.  As a personal comment, I think you've made things more complicated than they need to be.  

First off, you're treating a Flash block as if it is 16 bytes - the actual Flash block size for the KE04 is 512bytes (KE04 Sub-Family Reference Manual) and this is the minimum size that you can erase/write.  The "FLASH_Erase" and "FLASH_Program" methods will try to figure this out for you, but they're only programs and I've seen them have problems with figuring out arbitrary addresses.  I recommend always explicitly doing Flash operations on sector boundaries and performing the operations on the full sector - this means that you should be erasing/programming the entire last sector (you're going to do it anways when you do 16 bytes if the methods work properly).  

Secondly, I'm very sure that splitting up the FLASH the way you have (with no driver on the second block) will not work properly.  I haven't seen Flash broken up that way before - where did you get that code?  

I suggest that you look at what's returned from "FLASH_Erase" and "FLASH_Program" when the -Os flag is active and missing?  

If I were doing your application, I would use code that looks like:

 

uint32_t* flashSize;
                        FLASH_GetProperty(&s_flashDriver
                                        , kFLASH_PropertyPflash0TotalSize
                                        , flashSize);
uint32_t  lastSector  = *flashSize - FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE;
uint8_t   SystemNonVolatileVars[16]


//todo: Load the SystemNonVolatileVars array with the required data to save

                        __disable_irq();
status_t  eraseStatus = FLASH_Erase(&s_flashDriver
                                   , lastSector
                                   , FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE
                                   , kFLASH_ApiEraseKey);  //erase the sector
status_t  ProgmStatus = FLASH_Program(&s_flashDriver
                                    , lastSector
                                    , SystemNonVolatileVars
                                    , FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE);  // Program the sector with the nonVolatileVars
                        __enable_irq();

 


I can't think of any reason why you would want to have a separate Flash area defined in your MCU settings and when I look at your screen shot, it doesn't have a driver assigned to it (which could also be your problem).  

Could you:

  1. Remove the explict "NonVolatileVars" block in your "MCU settings" - just have a single, contiguous Flash area that goes to 0x2000 and uses the default driver. 
  2. Try my code above with -Os active and missing.  Note the values of eraseStatus and ProgmStatus upon the erase/program methods' return. 

Let me know how you make out.

Good luck,

myke 

View solution in original post

0 Kudos
Reply
24 Replies
5,179 Views
bobpaddock
Senior Contributor III

This is almost always a sign that there is a 'volatile' missing someplace where it needs to be.

Are you doing something with a variable both inside and outside of an interrupt?

It can also be a sign of a 'used' attribute being missing, usual on interrupt related functions.

Make sure that you do not have Link Time Optimization (LTO) enabled which is very aggressive about causing these problems.

 

5,153 Views
PabloRY42
Contributor II

Hi @bobpaddock and thaks for answer me.

I made a minimal version of my original code (without interrupts) to verify of there was a problem with a volatile variable I'm using, but the problem persist.

I have the LTO disabled.

PabloRY42_0-1610679373021.png

Also append my code:

uint8_t FLASHVars[16];
__attribute__ ((section(".MyNonVolatileVars"))) uint8_t SystemNonVolatileVars[16] = {
		[0] = 1,
		[1] = 2,
		[2] = 3,
		[3] = 4,
		[4] = 5,
};

flash_config_t s_flashDriver;			///<Variable que contiene la estructura de configuración del dirver para grabar en la memoria FLASH
uint16_t save = 0;
uint32_t cnt;

int main(void) {
	/* Init board hardware. */
    BOARD_InitBootPins();
    BOARD_InitBootClocks();

    uint8_t *ptrFLASH = &FLASHVars[0];					//create pointer of the info in ram
	uint8_t *FlashAddress = &SystemNonVolatileVars[0];	//create pointer of the info in flash
	uint32_t primaskValue = 0U;

	memset(&s_flashDriver, 0, sizeof(flash_config_t));
	FLASH_SetProperty(&s_flashDriver, kFLASH_PropertyFlashClockFrequency, CLOCK_GetFlashClkFreq());
	FLASH_Init(&s_flashDriver);

	for(uint8_t i = 0; i<16; i++)	*ptrFLASH++ = *FlashAddress++;			//copy the info in flash to RAM

    while(1) {
    	if (save == 1) {
    		primaskValue = DisableGlobalIRQ();					//Disable interrupts
    			uint32_t FlashAddress = (uint32_t) (&SystemNonVolatileVars[0]);			//get the direction of the first byte where the info is gonna be placed
				FLASH_Erase(&s_flashDriver, FlashAddress, 16, kFLASH_ApiEraseKey);		//erase the sector
				uint8_t *dataPtr = (uint8_t *) (FLASHVars);								//Get the direction of the first byte of info to save
				FLASH_Program(&s_flashDriver, FlashAddress, (uint32_t *)dataPtr, 16);	//save 16 bytes on FlashAdrres
			EnableGlobalIRQ(primaskValue);						//Enaable interrupts
			save = 0;
		}
		cnt++;		//dummy
	}
    return 0;
}

The idea of my code is refresh the "FLASHVars" array and when certain action ocurrs save that info into de the flash.

To set the memory area where the info is gonna be saved I used the MCU Settings to split the memory.

PabloRY42_1-1610679626018.png

And in the Debug.if file added this lines:

    .myNonVolatileVarsBlock 0x00001FF0 :
	{
	    KEEP(*(.MyNonVolatileVars)) /* keep my variable even if not referenced */
	} > NonVolatileVars

 

 

Best Regards.

 

0 Kudos
Reply
5,129 Views
bobpaddock
Senior Contributor III

Does doing this:

uint16_t volatile save = 0;

Change the results?

Nothing in the code that was posted ever changes the value of 'save' so the compiler

is likely to remove all the if( save == 1 ){} code as unused with the -Os setting.


Things can be marked as used without changing the linker script with the 'used' attribute directive,

IRQ function example I had at had, it can be applied to vars too:

static void i2c_irq_handler( volatile I2C_Tx_Rx_Channel *i2c_chnl_v_ptr ) __attribute__( ( used ) );
static void i2c_irq_handler( volatile I2C_Tx_Rx_Channel *i2c_chnl_v_ptr )
{
}

 

 

5,136 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi PabloRY42,

  Thanks for your updated information.

  comment all the flash related code, whether your project still enter the hardfault or not?

  Do you run the official SDK code:

SDK_2.8.0_MKE04Z128xxx4\boards\frdmke06z\driver_examples\flash\pflash

Whether this code has issues on your side or not?

 

Best Regards,

Kerry

0 Kudos
Reply
5,064 Views
PabloRY42
Contributor II

Hi @kerryzhou 

If i comment all the flash related code, everything is fine.

When i tried the flash example code runs perfectly, i tried to adapt that source code to mine and it works. However I notice the things:

1. If I had the buffer I want to save in the main, like a local variable, the code breaks; so I had to made it global and in that way the code runs correctly.
2. If I wanted to have my variable as local (in the main), it has to be "static", other way the HardFault appears, however I stiil don't know why is that.
 
Do you have a clue?
 
Thank you for your help and time.
 
Best Regards.
Pablo
0 Kudos
Reply
5,190 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi PabloRY42,

  If you just use the SDK code, when you build whether you have issues?

  If you don't have the build issues, you can download the code directly.

  If you have the build issues, as the KE04 is small flash, you can use the uart as the console instead of the semihost method. Then you should can download the code.

  You can try it on your side, if you still have issues, you also can give us some screenshot, that will helpful to the detail question analysis.

 

Best Regards,

Kerry

0 Kudos
Reply
5,159 Views
PabloRY42
Contributor II

Hi @kerryzhou, thanks for answer me and sorry for the late response.

I don't have any errors when the project is built, the problem is when I'm debugging.

The problem is when I try to write the info in the flash.

PabloRY42_2-1610680179877.png

 

Also append my code:

uint8_t FLASHVars[16];
__attribute__ ((section(".MyNonVolatileVars"))) uint8_t SystemNonVolatileVars[16] = {
		[0] = 1,
		[1] = 2,
		[2] = 3,
		[3] = 4,
		[4] = 5,
};

flash_config_t s_flashDriver;			///<Variable que contiene la estructura de configuración del dirver para grabar en la memoria FLASH
uint16_t save = 0;
uint32_t cnt;

int main(void) {
	/* Init board hardware. */
    BOARD_InitBootPins();
    BOARD_InitBootClocks();

    uint8_t *ptrFLASH = &FLASHVars[0];					//create pointer of the info in ram
	uint8_t *FlashAddress = &SystemNonVolatileVars[0];	//create pointer of the info in flash
	uint32_t primaskValue = 0U;

	memset(&s_flashDriver, 0, sizeof(flash_config_t));
	FLASH_SetProperty(&s_flashDriver, kFLASH_PropertyFlashClockFrequency, CLOCK_GetFlashClkFreq());
	FLASH_Init(&s_flashDriver);

	for(uint8_t i = 0; i<16; i++)	*ptrFLASH++ = *FlashAddress++;			//copy the info in flash to RAM

    while(1) {
    	if (save == 1) {
    		primaskValue = DisableGlobalIRQ();					//Disable interrupts
    			uint32_t FlashAddress = (uint32_t) (&SystemNonVolatileVars[0]);			//get the direction of the first byte where the info is gonna be placed
				FLASH_Erase(&s_flashDriver, FlashAddress, 16, kFLASH_ApiEraseKey);		//erase the sector
				uint8_t *dataPtr = (uint8_t *) (FLASHVars);								//Get the direction of the first byte of info to save
				FLASH_Program(&s_flashDriver, FlashAddress, (uint32_t *)dataPtr, 16);	//save 16 bytes on FlashAdrres
			EnableGlobalIRQ(primaskValue);						//Enaable interrupts
			save = 0;
		}
		cnt++;		//dummy
	}
    return 0;
}

The idea of my code is refresh the "FLASHVars" array and when certain action ocurrs save that info into de the flash.

To set the memory area where the info is gonna be saved I used the MCU Settings to split the memory.

PabloRY42_1-1610679882121.png

And in the Debug.if file added this lines:

    .myNonVolatileVarsBlock 0x00001FF0 :
	{
	    KEEP(*(.MyNonVolatileVars)) /* keep my variable even if not referenced */
	} > NonVolatileVars

 

Thanks.

Best Regards.

0 Kudos
Reply
5,199 Views
myke_predko
Senior Contributor III

Hi @PabloRY42 

Can you give us a bit more information?  What is the code that you're using to erase and write to the sectors of Flash and how are you selecting the sector to erase/write to?  What is your application size with and without the -Os optimization - I would ask for Flash and RAM usage?  

You said that your code fails on write, what is the failure?  

myke

0 Kudos
Reply
5,155 Views
PabloRY42
Contributor II

Hi @myke_predko, thanks and sorry for the late response.

This is the memory with the -Os optimization

PabloRY42_0-1610681830584.png

And without the -Os

PabloRY42_1-1610681941289.png

To set the memory area where the info is gonna be saved I used the MCU Settings to split the memory.

PabloRY42_3-1610682383111.png

And in the Debug.if file added this lines:

    .myNonVolatileVarsBlock 0x00001FF0 :
	{
	    KEEP(*(.MyNonVolatileVars)) /* keep my variable even if not referenced */
	} > NonVolatileVars

Also append my code:

uint8_t FLASHVars[16];
__attribute__ ((section(".MyNonVolatileVars"))) uint8_t SystemNonVolatileVars[16] = {
		[0] = 1,
		[1] = 2,
		[2] = 3,
		[3] = 4,
		[4] = 5,
};

flash_config_t s_flashDriver;			///<Variable que contiene la estructura de configuración del dirver para grabar en la memoria FLASH
uint16_t save = 0;
uint32_t cnt;

int main(void) {
	/* Init board hardware. */
    BOARD_InitBootPins();
    BOARD_InitBootClocks();

    uint8_t *ptrFLASH = &FLASHVars[0];					//create pointer of the info in ram
	uint8_t *FlashAddress = &SystemNonVolatileVars[0];	//create pointer of the info in flash
	uint32_t primaskValue = 0U;

	memset(&s_flashDriver, 0, sizeof(flash_config_t));
	FLASH_SetProperty(&s_flashDriver, kFLASH_PropertyFlashClockFrequency, CLOCK_GetFlashClkFreq());
	FLASH_Init(&s_flashDriver);

	for(uint8_t i = 0; i<16; i++)	*ptrFLASH++ = *FlashAddress++;			//copy the info in flash to RAM

    while(1) {
    	if (save == 1) {
    		primaskValue = DisableGlobalIRQ();					//Disable interrupts
    			uint32_t FlashAddress = (uint32_t) (&SystemNonVolatileVars[0]);			//get the direction of the first byte where the info is gonna be placed
				FLASH_Erase(&s_flashDriver, FlashAddress, 16, kFLASH_ApiEraseKey);		//erase the sector
				uint8_t *dataPtr = (uint8_t *) (FLASHVars);								//Get the direction of the first byte of info to save
				FLASH_Program(&s_flashDriver, FlashAddress, (uint32_t *)dataPtr, 16);	//save 16 bytes on FlashAdrres
			EnableGlobalIRQ(primaskValue);						//Enaable interrupts
			save = 0;
		}
		cnt++;		//dummy
	}
    return 0;
}

The idea of my code is refresh the "FLASHVars" array and when certain action ocurrs save that info into de the flash.

 

Thanks.

Best Regards.

0 Kudos
Reply
5,341 Views
myke_predko
Senior Contributor III

Hi @PabloRY42 

I think I have a clue as to what's happening - I'm not sure you've properly set up your "nonVolatileVars" and using it correctly.  As a personal comment, I think you've made things more complicated than they need to be.  

First off, you're treating a Flash block as if it is 16 bytes - the actual Flash block size for the KE04 is 512bytes (KE04 Sub-Family Reference Manual) and this is the minimum size that you can erase/write.  The "FLASH_Erase" and "FLASH_Program" methods will try to figure this out for you, but they're only programs and I've seen them have problems with figuring out arbitrary addresses.  I recommend always explicitly doing Flash operations on sector boundaries and performing the operations on the full sector - this means that you should be erasing/programming the entire last sector (you're going to do it anways when you do 16 bytes if the methods work properly).  

Secondly, I'm very sure that splitting up the FLASH the way you have (with no driver on the second block) will not work properly.  I haven't seen Flash broken up that way before - where did you get that code?  

I suggest that you look at what's returned from "FLASH_Erase" and "FLASH_Program" when the -Os flag is active and missing?  

If I were doing your application, I would use code that looks like:

 

uint32_t* flashSize;
                        FLASH_GetProperty(&s_flashDriver
                                        , kFLASH_PropertyPflash0TotalSize
                                        , flashSize);
uint32_t  lastSector  = *flashSize - FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE;
uint8_t   SystemNonVolatileVars[16]


//todo: Load the SystemNonVolatileVars array with the required data to save

                        __disable_irq();
status_t  eraseStatus = FLASH_Erase(&s_flashDriver
                                   , lastSector
                                   , FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE
                                   , kFLASH_ApiEraseKey);  //erase the sector
status_t  ProgmStatus = FLASH_Program(&s_flashDriver
                                    , lastSector
                                    , SystemNonVolatileVars
                                    , FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE);  // Program the sector with the nonVolatileVars
                        __enable_irq();

 


I can't think of any reason why you would want to have a separate Flash area defined in your MCU settings and when I look at your screen shot, it doesn't have a driver assigned to it (which could also be your problem).  

Could you:

  1. Remove the explict "NonVolatileVars" block in your "MCU settings" - just have a single, contiguous Flash area that goes to 0x2000 and uses the default driver. 
  2. Try my code above with -Os active and missing.  Note the values of eraseStatus and ProgmStatus upon the erase/program methods' return. 

Let me know how you make out.

Good luck,

myke 

0 Kudos
Reply
5,083 Views
PabloRY42
Contributor II

Hi, @myke_predko 

Sorry for the late response but I was busy with other things.

I thought that it was necessary to split the FLASH in order to have an specific area for this variables and other to the code, I really don't remember where I got the idea to split the memory that way.
 
I did remove the "NonVolatileVars" block and tried your code, but I still have the same problem, so I compared my code with the example, run some test and noticed two things:
 
1. I had my "SystemNonVolatileVars" in the main, like a local variable, so I made it global and then the code works correctly with and without the -Os optimization. The functions return success.
2. If I wanted to have my variable as local (in the main), it has to be "static", other way the HardFault appears, however I stiil don't know why is that, Do you have a clue?
 
Thank you for your time and help!
 
Best Regards. 
Pablo!
 
 
 
 
0 Kudos
Reply
5,069 Views
myke_predko
Senior Contributor III

Hey @PabloRY42 ,

You've peaked my interest with this one.  

Can you confirm that the problem is in the "FLASH_Program" call?  Is it a compile or runtime problem?  I believe it will be in FLASH_Program and will be runtime, but I want to confirm.  

When you are in a method (subroutine/function like "main") any variables you declare within the method are, by default, "local" which means they can only be accessed within the method (ie you can use the same variable name in multiple methods and the ones accessed will be the ones "local" to the method) and *usually* are located on the execution stack.

Locating local variables on the execution stack means that the memory required is dynamically allocated when the method is called and freed when the execution returns from the method.  This minimizes the amount of variable memory allocated to just what's required at that instant of execution. 

But there are exceptions to how local variable are located (see below).  

Now, in C, if you add "static" to the variable declaration, it places the variable in a defined unique address in the MCU's memory (which is the same as a "global" variable which is defined outside a method) BUT it is only accessible within the method like a "local" variable.    

This is all well and good, but I think when you specify -Os some of these rules are thrown out.  I would expect that if you don't write to the nonVolatileVars variable, but initialize it (as you've done in the original code) I suspect that an area in the Flash contains the variable as a block of bytes set as you've initialized it and a pointer is returned to the value in Flash.  Without the -Os specified or if the variable's values are changed, the variable is stored in SRAM (addressed dependent on the stack) and has code statements writting values into the variable. 

I'm saying all this becuase I'm fairly sure that you can't write a block of Flash using a block of Flash as source - I would ask somebody like @mjbcswitzerland or @kerryzhou to confirm if this is the case. 

If it is the case, then I think I've explained the issue - the initialized but not updated local variable "nonVolatileVars" is stored in Flash when the -Os option is selected for and when the "FLASH_Program" is called there is a problem because you are trying to write to Flash with data that is located in Flash (iFlash writes only work with source data stored in SRAM).  The solution is to either make "nonVolatileVars" global or add the "static" keyword to their declaration or (maybe) write a value into it to force the compiler to put the variable in SRAM.  

Questions to confirm:

  1. Can you confirm that the problem is with the "FLASH_Program" call and it is a run time problem?
    1. What is the problem with "FLASH_Program"?  Does it return an error code or does execution hang up there?
  2. Do you write to your nonVolatileVars variable or do you define it and leave it as is for this program?  
  3. If you don't write to it, could you write to it algorithmically and then build with -Os to see if the problem persists?  See above for the reasons why.  

I'm interested in hearing how this works out for you.

myke

0 Kudos
Reply
5,046 Views
PabloRY42
Contributor II

Hi @myke_predko 

Yes, the problem is in "FLASH_Program" and in runtime. I've running some test and I have the following answers to your questions.

  1. Can you confirm that the problem is with the "FLASH_Program" call and it is a run time problem? Yes, that's it.
    1. What is the problem with "FLASH_Program"?  Does it return an error code or does execution hang up there? It hangs up in "FLASH_Program"

I've tried many combinatios with the -Os:

  1. Do you write to your nonVolatileVars variable or do you define it and leave it as is for this program? I define it and leave as it is, but i've tried many combinations
    1. if my variable is defined global and initialized, it works
    2. if my variable is defined global and non-initialized, it does not work
    3. if my variable is defined local (initialized and non-initialized), it does not work
    4. if my variable is defined local, static and initialized, it works
    5. if my variable is defined local, static and non-initialized, it does not work
  2. If you don't write to it, could you write to it algorithmically and then build with -Os to see if the problem persists?
    1. If I write in the variable, I got the same results I mentioned before.

Best Regards.

Pablo.

 

0 Kudos
Reply
5,024 Views
myke_predko
Senior Contributor III

Hi @PabloRY42 ,

If I was to put your results in a table, it would look something like:

GlobalLocalLocal+StaticInitializedWritten to in CodeWorks Properly
X  XY & NYes
X   Y & NNo
 X XY & NNo
 X  Y & NNo
  XXY & NYes
  X Y & NNo

 

Is this correct?  

Doing a bit of research I found AN4695: Avoiding Read While Write Errors When Developing In-Software Flash Programming Applications ... and I suspect that this is the problem you're experiencing.  Previously, I indicated that I thought you couldn't program from Flash and that's on the right track but to be more accurate you cannot program the same block of Flash as you're executing in/have data.  This is why the basic Flash write code is written into SRAM and executed from there.  

Could I ask you to follow up on a two more things?  For the table above, could you:

  1. Confirm that I put in your information correctly?  This also includes noting that you wrote to the "nonVolitileVars" variable after it was declared and optionally initialized.  
  2. If the table is correct, could you copy in the address of "nonVolatileVars" (ie &nonVolatileVars[0], which is the same thing)?   

If my hypothesis is correct, "nonVolatileVars" will be located in the Flash address space (0x0000 to 0x2000) and not SRAM (0x1FFFFF00 to 0x20000300 if I'm reading the reference manual correctly) when the program hangs up in FLASH_Program.  

myke

0 Kudos
Reply
4,995 Views
myke_predko
Senior Contributor III

Hi @PabloRY42 

Just looking over the comments from @mjbcswitzerland and if you have any optimized code where "nonVolatileVars" is in SRAM, could you provide a copy of the .map file (found in the Debug/Release folder)?   

That could further explain what is happening here if I'm wrong about the Flash Read While Writing Error.  

Thanx,

myke

0 Kudos
Reply
5,010 Views
mjbcswitzerland
Specialist V

Hi

From the table it looks like having the variable in .bss or stack space is not working but in variable space it is.

As I noted, there is very little RAM in this chip and if variables are getting corrupted due to limited stack, RAM code being overloaded to space with variables, etc. where certain variables are in the memory map may have a dependence on whether they get clobbered in the process or or not, and whether one "gets away" with it or not.

That is why an analysis of the RAM utilisation is so important. One can get around such things with trial-and-error and experimenting with optimisation (which also move memory around a bit) until it works but the chances it will fail again when additional changes are made to the project is high and getting away with some corrupted memory on a random/chance basis is not a good engineering strategy.

Do a RAM utilisation analysis and you will know how it is being used, what the problem is and subsequently know what to do to solve it as well.

Whatever happens don't ignore such details as Toyota did in their well and documented case when they didn't correctly ensure that stack overflow could not happen, which lead to at least 21 known deaths and billions of dollars of law suits and compensation - https://www.edn.com/toyotas-killer-firmware-bad-design-and-its-consequences/ - just for the sake of not checking a few bytes of RAM....

Regards

Mark

 

0 Kudos
Reply
5,059 Views
mjbcswitzerland
Specialist V

Hi

I doubt that the issue will be related to the optimisation setting and this may be a red herring. If it worked when this optimisation was not used but didn't when it was it would point to something in that direction but as I have been able to understand this reference is always compiled with -Os so this comparison doesn't actually exist.

The KE04Z8 is a really small part in terms of memory with only 8k Flash, but more importantly only 1k of RAM. An overview of Flash usage is simple but it tends to be RAM that causes bottle-necks and so one needs to keep an account of the memory being used to ensure that there is adequate stack available when executing each function used.

I expect that the example functions in the SDK are not specifically designed for restraining their RAM usage to ensure that they can always operate together with other parts of other examples.

I just built the uTasker project for a FRDM-KE04Z board (with the same chip) with the following test code [binary attached that can be loaded to the board]:

 

 

    while ((Length = fnRead(SerialPortID, ucInputMessage, MEDIUM_MESSAGE)) != 0) { // handle UART input
        fnEchoInput(ucInputMessage, Length);
        if (ucInputMessage[0] == CARRIAGE_RETURN) { // show memory utilisation
            fnDisplayMemoryUsage();
        }
        else if (ucInputMessage[0] == 'r') {
            int iCnt = 0;
            unsigned char *ptrFlash = fnGetFlashAdd((unsigned char *)0x1e00);
            while (iCnt++ < 16) {
                fnDebugHex(*ptrFlash++, (WITH_SPACE | WITH_LEADIN | sizeof(*ptrFlash)));
            }
            fnDebugMsg("\r\n");
        }
        else if (ucInputMessage[0] == 'w') {
            static unsigned char ucTest[16] = { 0 };
            unsigned char ucCnt = 0;
            while (ucCnt < 16) {
                ucTest[ucCnt] += (ucCnt);
                ucCnt++;
            }
            fnEraseFlashSector((unsigned char *)0x1e00, 0);
            fnWriteBytesFlash((unsigned char *)0x1e00, ucTest, 16);
            fnDebugMsg("Flash written\r\n");
        }
    }

 

This will display memory usage when the ENTER key is pressed (UART VCOM at 115kBaud) and print out the value of 16 bytes in the last flash sector (0x1e00) when the 'r' key is pressed.
When 'w' is entered it will erase the last flash sector and write some values to the first 16 bytes of the flash area.
Repeating will increment these values and erase/write so that it can be checked that each time the write is performed (using 'r') that the values are correctly store.
After a reset/power cycle 'r' confirm that the values the values are still correct in flash.
Below I have added a typical test session output.

This shows that nothing special is required for the flash operation on this chip and I also use -Os.
But RAM is seriously restricted and so needs to be watched almost down to the byte being used.

 

Regards

Mark
[uTasker project developer for Kinetis and i.MX RT]
Contact me by personal message or on the uTasker web site to discuss professional training, solutions to problems or rapid product development requirements

For professionals searching for faster, problem-free Kinetis and i.MX RT 10xx developments the uTasker project holds the key: https://www.utasker.com/kinetis/FRDM-KE04Z.html

 

 

Hello, world... FRDM_KE04Z [External]
Kinetis Unique ID: 0x39334532000e63010000003b
Static memory = 0x000000b0
OS Heap use = 0x00c9 from 0x01e0
Initial stack margin 0x00000010

System memory use:
==================
Free heap = 0x0038 from 0x01e0
Unused stack = 0x00000008 (0x00000157)

System memory use:
==================
Free heap = 0x0038 from 0x01e0
Unused stack = 0x00000008 (0x00000157)
r 0x00 0x08 0x10 0x18 0x20 0x28 0x30 0x38 0x40 0x48 0x50 0x58 0x60 0x68 0x70 0x78
wFlash written
r 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f
wFlash written
r 0x00 0x02 0x04 0x06 0x08 0x0a 0x0c 0x0e 0x10 0x12 0x14 0x16 0x18 0x1a 0x1c 0x1e
wFlash written
r 0x00 0x03 0x06 0x09 0x0c 0x0f 0x12 0x15 0x18 0x1b 0x1e 0x21 0x24 0x27 0x2a 0x2d
wFlash written
r 0x00 0x04 0x08 0x0c 0x10 0x14 0x18 0x1c 0x20 0x24 0x28 0x2c 0x30 0x34 0x38 0x3c


Hello, world... FRDM_KE04Z [External]
Kinetis Unique ID: 0x39334532000e63010000003b
Static memory = 0x000000b0
OS Heap use = 0x00c9 from 0x01e0
Initial stack margin 0x00000010
r 0x00 0x04 0x08 0x0c 0x10 0x14 0x18 0x1c 0x20 0x24 0x28 0x2c 0x30 0x34 0x38 0x3c

System memory use:
==================
Free heap = 0x0038 from 0x01e0
Unused stack = 0x00000010 (0x0000014f)

0 Kudos
Reply
5,055 Views
myke_predko
Senior Contributor III

Hey @mjbcswitzerland 

Thanx for chiming in.  

First question - are there any differences in the compilers/device parameters used by the compiler between MCUXpresso and uTasker?  

Also, you called the SDC methods "example functions".  Is this a fair characterization?  They might not be optimized for each part they are used in the SDK but when I have gone through them they're pretty solid.  

Finally, any comments on trying to program Flash from Flash source?  That was really the thesis of my previous post.

myke

0 Kudos
Reply
5,040 Views
mjbcswitzerland
Specialist V

Myke

I have to correct myself about the optimisation comparison. I see now that it was explicitly stated that it worked with other optimisation settings and it is thus presumably really due to that.

However it also brings back the question of examples which run when using the tested optimisation setting (which will almost always be with disabled optimisation since the idea is to make it as easy as possible for the tester to use). Whether such examples have ever been tested or can survive optimisation is another question - "examples" remain "starting points" and not necessarily solutions for developments. Sometimes the main work may still lie ahead!

Regards

Mark

 

0 Kudos
Reply
5,041 Views
mjbcswitzerland
Specialist V

Myke

I build either with MCUXpresso or from a make file using the same compiler as MCUXpresso. Therefore I doubt that there are any build/compiler setting differences.
Also I test code with IAR and Keil compilers to ensure consistent behavior and almost always use maximum optimisation for space. In fact I have never understood the practice of using one level for developing and another for release because that means that 99% of the development cycle one is intensively testing the product like that and later it is delivered in a state that has hardly been tested properly (with a small amount of practice one can debug fully optimised code with little difficulty, which is the main reason for developing with different settings).

SDK is generally a collection of examples that show the use of one thing (apart from possibly some more specific demo applications). This means that if one develops a project based on multiple examples one has to put these together (usually by copying pasting parts of one to another) and then one has something that has never necessarily been tested in that configuration before. Therefore when someone has a problem with anything more that a exact reference example, which can be assumed to generally work well as you have pointed out, it is no longer possible to really know the state (they could corrupt each others resources or errors could have been made during the combing process).

Basically I am pointing out that there are a lot of things that could go wrong when using more than one 'good' example in the process of a project development. In the case of the the KE04Z8 the risks are amplified by the fact that there is so little RAM in this part that there is a high risk of running out of it  without necessarily being aware of it since the first effects tend to arise from stack usage overwriting variables and things start failing/not working in unpredictable ways. When I use this part I ensure I always know the exact number of bytes used by variables, heap and stack to be sure that there is adequate safely margin for the operation in hand.

Specifically programing flash from flash (content) - it depends on how it is done. The KE04Z8 has a single 8k bank of flash that cannot be read from when programing. The programming code will be running from SRAM but the value to be programmed will have already be put into the programming register before needing to execute the actually programming command. This means that normally where the data comes from is of no consequence.

I have attached a binary that modifies the write operation to write from flash (address 1 since 0 would be a zero pointer, which is not allowed by the routine):

fnEraseFlashSector((unsigned char *)0x1e00, 0);
fnWriteBytesFlash((unsigned char *)0x1e00, (unsigned char *)1, 16);

 

The result shows that this is no issue:

Hello, world... FRDM_KE04Z [External]
Kinetis Unique ID: 0x39334532000e63010000003b
Static memory = 0x000000a0
OS Heap use = 0x00c9 from 0x01e0
Initial stack margin 0x00000020
r 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
wFlash written
r 0x02 0x00 0x20 0x11 0x04 0x00 0x00 0x5b 0x0b 0x00 0x00 0x4d 0x0b 0x00 0x00 0x4f


but I don't know whether the flash driver being used in the test case has different restrictions or does really try to read from flash when it is not in a readable state (?). Again, examples will almost 100% work when used in the example use case but that doesn't necessarily mean that they will work when used in a different way to the example's use.

Regards

Mark

0 Kudos
Reply