- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Everyone
I've a problem: I have to store periodically some parameters in the Non Volatile Memory. I use MKE02Z32VLC2 MCU. In previous revision of my application software I've used EEPROM space to store data, and all worked fine. Now I need to use free flash space because of the speed needed to store parameters: I need to create two separated copies of parameters so if user switch off the device while a write sequence is in progress, corrupted data will affect only one of the copy, and software can use the second one. In EEPROM this is not possible because I can only erase block (256 Bytes) or sector (2 bytes). But if I delete sector by sector in EEPROM the time needed is too much for the application.
If I use EEPROM commands I've no problem, the algorithm works fine.
The problem is when I use FLASH commands, such as ERASE SECTOR. I'm sure to use a sector that is not used by application. I've disabled interrupts, but there's still a problem, and the core goes in the lockup state and MCU resets.
I've tried to insert some delay but the problem is still present. I can't understand where's the matter.
Can anyone help me?
Thank you a lot!
Here the software I wrote:
...
...
DisableInterrupts;
Error = FALSE;
do {
Error = Flash_EraseSector(FLASH_DATA_START );
} while (Error != FLASH_ERR_SUCCESS);
...
...
And here the function Flash_EraseSector:
uint16_t Flash_EraseSector(uint16_t FLASH_Address)
{
uint16_t Error = FLASH_ERR_SUCCESS;
// Check address to see if it is aligned to 4 bytes
// Global address [1:0] must be 00.
if (FLASH_Address & 0x03)
{
Error = FLASH_ERR_INVALID_PARAM;
return (Error);
}
FTMRH_FSTAT = 0x30; // Clear error flags
FTMRH_FCCOBIX = 0x0; // Write index to specify the command code to be loaded ed first part of Global address
FTMRH_FCCOBHI = FLASH_CMD_ERASE_SECTOR; // FLASH command 0x0A
FTMRH_FCCOBLO = 0x0; // Global Address[23:16] = 0x0
FTMRH_FCCOBIX = 0x1; // Write index to specify the Global Address
FTMRH_FCCOBHI = (uint8_t) (FLASH_Address >> 8); // Global Address[15:8]
FTMRH_FCCOBLO = (uint8_t) (FLASH_Address); // Global Address[7:0]
FTMRH_FSTAT = 0x80; // Launch the command
while (!(FTMRH_FSTAT & FTMRH_FSTAT_CCIF_MASK)){ }; // Wait till command is completed
if(FTMRH_FSTAT & FTMRH_FSTAT_ACCERR_MASK) // Check error status
{
Error |= FLASH_ERR_ACCESS;
}
if(FTMRH_FSTAT & FTMRH_FSTAT_FPVIOL_MASK)
{
Error |= FLASH_ERR_PROTECTION;
}
if(FTMRH_FSTAT & FTMRH_FSTAT_MGSTAT0_MASK)
{
Error |= FLASH_ERR_MGSTAT0;
}
if(FTMRH_FSTAT & FTMRH_FSTAT_MGSTAT1_MASK)
{
Error |= FLASH_ERR_MGSTAT1;
}
return (Error);
}
Roberto
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Giovinetti Roberto wrote:
Hi
I found a solution.
I added the simple DisableInterrupts instruction in the RAM function, and now it works. I can't understand why, because the DisableInterrupts instruction was present in the calling function, and so interrupts was disabled yet. But now it works fine.
__attribute__( ( long_call, section(".data") ) ) void FlashLaunchCommand (void)
{
DisableInterrupts;
FTMRH_FSTAT = 0x80; // Launch the command
// Wait till command is completed
while (!(FTMRH_FSTAT & FTMRH_FSTAT_CCIF_MASK)){
}
}
There are two issues that may be going on. First the while() loop has no side effects so the compiler may optimize it away. To prevent this add this, GCC format need to match your own compiler format if not using GCC:
while (!(FTMRH_FSTAT & FTMRH_FSTAT_CCIF_MASK))
{
__asm__ __volatile__ ("nop");
}
Marking the nop as volatile will make sure the loop happens.
On some ARM processors a nop may not actually consume any time due to cache.
That is not really an issue here. This should also fix the problem seen with the caller containing the disable IRQ, as the 'volatile' will prevent the compiler from reordering the code across sequence points.
I use the code below for GCC, which this form editor is going to mess up. :-(
Example that solves the above problems:
ATOMIC_BLOCK( ATOMIC_RESTORESTATE )
{
while (!(FTMRH_FSTAT & FTMRH_FSTAT_CCIF_MASK))
{
__asm__ __volatile__ ("nop");
}
}
/** @(#)atomic.h <18-Aug-2014 13:31:09 bob p>
* Last Time-stamp: <19-Jan-2016 09:02:58 bob p>
*
* \file atomic.h
* \brief Port of Dean Camera's ATOMIC_BLOCK macros for AVR to ARM Cortex M3.
*
*/
/*lint -save -e755 -e756 Disable warning(s), this file only, global macro/typedef 'Symbol' (Location) not referenced */
#ifndef _ATOMIC_H_
#define _ATOMIC_H_ (1)
#ifdef DEFINE_SPACE_ATOMIC_H
#define EXTERN_ATOMIC
#else
#define EXTERN_ATOMIC extern
#endif
#if defined(__cplusplus) && __cplusplus
extern "C" {
#endif
/*
* This is port of Dean Camera's ATOMIC_BLOCK macros for AVR to ARM Cortex M3
* v1.0
* Mark Pendrith, Nov 27, 2012.
*
* From Mark:
* >When I ported the macros I emailed Dean to ask what attribution would be
* >appropriate, and here is his response:
* >
* >>Mark,
* >>I think it's great that you've ported the macros; consider them
* >>public domain, to do with whatever you wish. I hope you find them useful .
* >>
* >>Cheers!
* >>- Dean
*/
#ifdef __arm__
#ifndef _CORTEX_M3_ATOMIC_H_
#define _CORTEX_M3_ATOMIC_H_
static __inline__ uint32_t __get_primask(void) \
{ uint32_t primask = 0; \
__asm__ volatile ("MRS %[result], PRIMASK\n\t":[result]"=r"(primask)::); \
return primask; } // returns 0 if interrupts enabled, 1 if disabled
static __inline__ void __set_primask(uint32_t setval) \
{ __asm__ volatile ("MSR PRIMASK, %[value]\n\t""dmb\n\t""dsb\n\t""isb\n\t"::[value]"r"(setval):);
__asm__ volatile ("" ::: "memory");}
static __inline__ uint32_t __iSeiRetVal(void) \
{ __asm__ volatile ("CPSIE i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \
__asm__ volatile ("" ::: "memory"); return 1; }
static __inline__ uint32_t __iCliRetVal(void) \
{ __asm__ volatile ("CPSID i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \
__asm__ volatile ("" ::: "memory"); return 1; }
static __inline__ void __iSeiParam(const uint32_t *__s) \
{ __asm__ volatile ("CPSIE i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \
__asm__ volatile ("" ::: "memory"); (void)__s; }
static __inline__ void __iCliParam(const uint32_t *__s) \
{ __asm__ volatile ("CPSID i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \
__asm__ volatile ("" ::: "memory"); (void)__s; }
static __inline__ void __iRestore(const uint32_t *__s) \
{ __set_primask(*__s); __asm__ volatile ("dmb\n\t""dsb\n\t""isb\n\t"); \
__asm__ volatile ("" ::: "memory"); }
#define ATOMIC_BLOCK(type) \
for ( type, __ToDo = __iCliRetVal(); __ToDo ; __ToDo = 0 )
#define ATOMIC_RESTORESTATE \
uint32_t primask_save __attribute__((__cleanup__(__iRestore))) = __get_primask()
#define ATOMIC_FORCEON \
uint32_t primask_save __attribute__((__cleanup__(__iSeiParam))) = 0
#define NONATOMIC_BLOCK(type) \
for ( type, __ToDo = __iSeiRetVal(); __ToDo ; __ToDo = 0 )
#define NONATOMIC_RESTORESTATE \
uint32_t primask_save __attribute__((__cleanup__(__iRestore))) = __get_primask()
#define NONATOMIC_FORCEOFF \
uint32_t primask_save __attribute__((__cleanup__(__iCliParam))) = 0
#endif
#endif
#if defined(__cplusplus) && __cplusplus
}
#endif
#endif /* _ATOMIC_H_ */
/*lint -restore */
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi
I found a solution.
I added the simple DisableInterrupts instruction in the RAM function, and now it works. I can't understand why, because the DisableInterrupts instruction was present in the calling function, and so interrupts was disabled yet. But now it works fine.
__attribute__( ( long_call, section(".data") ) ) void FlashLaunchCommand (void)
{
DisableInterrupts;
FTMRH_FSTAT = 0x80; // Launch the command
// Wait till command is completed
while (!(FTMRH_FSTAT & FTMRH_FSTAT_CCIF_MASK)){
}
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Giovinetti Roberto wrote:
Hi
I found a solution.
I added the simple DisableInterrupts instruction in the RAM function, and now it works. I can't understand why, because the DisableInterrupts instruction was present in the calling function, and so interrupts was disabled yet. But now it works fine.
__attribute__( ( long_call, section(".data") ) ) void FlashLaunchCommand (void)
{
DisableInterrupts;
FTMRH_FSTAT = 0x80; // Launch the command
// Wait till command is completed
while (!(FTMRH_FSTAT & FTMRH_FSTAT_CCIF_MASK)){
}
}
There are two issues that may be going on. First the while() loop has no side effects so the compiler may optimize it away. To prevent this add this, GCC format need to match your own compiler format if not using GCC:
while (!(FTMRH_FSTAT & FTMRH_FSTAT_CCIF_MASK))
{
__asm__ __volatile__ ("nop");
}
Marking the nop as volatile will make sure the loop happens.
On some ARM processors a nop may not actually consume any time due to cache.
That is not really an issue here. This should also fix the problem seen with the caller containing the disable IRQ, as the 'volatile' will prevent the compiler from reordering the code across sequence points.
I use the code below for GCC, which this form editor is going to mess up. :-(
Example that solves the above problems:
ATOMIC_BLOCK( ATOMIC_RESTORESTATE )
{
while (!(FTMRH_FSTAT & FTMRH_FSTAT_CCIF_MASK))
{
__asm__ __volatile__ ("nop");
}
}
/** @(#)atomic.h <18-Aug-2014 13:31:09 bob p>
* Last Time-stamp: <19-Jan-2016 09:02:58 bob p>
*
* \file atomic.h
* \brief Port of Dean Camera's ATOMIC_BLOCK macros for AVR to ARM Cortex M3.
*
*/
/*lint -save -e755 -e756 Disable warning(s), this file only, global macro/typedef 'Symbol' (Location) not referenced */
#ifndef _ATOMIC_H_
#define _ATOMIC_H_ (1)
#ifdef DEFINE_SPACE_ATOMIC_H
#define EXTERN_ATOMIC
#else
#define EXTERN_ATOMIC extern
#endif
#if defined(__cplusplus) && __cplusplus
extern "C" {
#endif
/*
* This is port of Dean Camera's ATOMIC_BLOCK macros for AVR to ARM Cortex M3
* v1.0
* Mark Pendrith, Nov 27, 2012.
*
* From Mark:
* >When I ported the macros I emailed Dean to ask what attribution would be
* >appropriate, and here is his response:
* >
* >>Mark,
* >>I think it's great that you've ported the macros; consider them
* >>public domain, to do with whatever you wish. I hope you find them useful .
* >>
* >>Cheers!
* >>- Dean
*/
#ifdef __arm__
#ifndef _CORTEX_M3_ATOMIC_H_
#define _CORTEX_M3_ATOMIC_H_
static __inline__ uint32_t __get_primask(void) \
{ uint32_t primask = 0; \
__asm__ volatile ("MRS %[result], PRIMASK\n\t":[result]"=r"(primask)::); \
return primask; } // returns 0 if interrupts enabled, 1 if disabled
static __inline__ void __set_primask(uint32_t setval) \
{ __asm__ volatile ("MSR PRIMASK, %[value]\n\t""dmb\n\t""dsb\n\t""isb\n\t"::[value]"r"(setval):);
__asm__ volatile ("" ::: "memory");}
static __inline__ uint32_t __iSeiRetVal(void) \
{ __asm__ volatile ("CPSIE i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \
__asm__ volatile ("" ::: "memory"); return 1; }
static __inline__ uint32_t __iCliRetVal(void) \
{ __asm__ volatile ("CPSID i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \
__asm__ volatile ("" ::: "memory"); return 1; }
static __inline__ void __iSeiParam(const uint32_t *__s) \
{ __asm__ volatile ("CPSIE i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \
__asm__ volatile ("" ::: "memory"); (void)__s; }
static __inline__ void __iCliParam(const uint32_t *__s) \
{ __asm__ volatile ("CPSID i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \
__asm__ volatile ("" ::: "memory"); (void)__s; }
static __inline__ void __iRestore(const uint32_t *__s) \
{ __set_primask(*__s); __asm__ volatile ("dmb\n\t""dsb\n\t""isb\n\t"); \
__asm__ volatile ("" ::: "memory"); }
#define ATOMIC_BLOCK(type) \
for ( type, __ToDo = __iCliRetVal(); __ToDo ; __ToDo = 0 )
#define ATOMIC_RESTORESTATE \
uint32_t primask_save __attribute__((__cleanup__(__iRestore))) = __get_primask()
#define ATOMIC_FORCEON \
uint32_t primask_save __attribute__((__cleanup__(__iSeiParam))) = 0
#define NONATOMIC_BLOCK(type) \
for ( type, __ToDo = __iSeiRetVal(); __ToDo ; __ToDo = 0 )
#define NONATOMIC_RESTORESTATE \
uint32_t primask_save __attribute__((__cleanup__(__iRestore))) = __get_primask()
#define NONATOMIC_FORCEOFF \
uint32_t primask_save __attribute__((__cleanup__(__iCliParam))) = 0
#endif
#endif
#if defined(__cplusplus) && __cplusplus
}
#endif
#endif /* _ATOMIC_H_ */
/*lint -restore */
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi
I recommend studying the assembler code generated in both cases. It sounds as though you have some compiler intervention/optimisation and it is probably best to understand because it may start failing again in the future (small program changes, different compiler version etc.).
Having a potential race-state or such in the code is a very dangerous situation and the original probem needs to be understood in order to be sure that your product will remain reliable in the future - the position of the disable-interrupt call (or in-lined code) shouldn't have any effect so there must be something else modified through it....
Regards
Mark
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi
I modified Flash driver so a part of the ERASE and PROGRAM functions resides in RAM. I used the function listed below:
__attribute__( ( long_call, section(".data") ) ) void FlashLaunchCommand (void)
{
FTMRH_FSTAT = 0x80; // Launch the command
// Wait till command is completed
while (!(FTMRH_FSTAT & FTMRH_FSTAT_CCIF_MASK)){
}
}
Now the method works but not everytime! Some times I've the same problem with LOCKUP bit that causes a reset.
Does anybody Know a solution?
Regards
Thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi
I have attached the Flash driver from the uTasker project, which includes a swap-block which allows parameter storage without risk of loss or corruption due to resets or power cycles. It is documented at http://www.utasker.com/docs/uTasker/uTaskerFileSystem_3.PDF
You can load a binary to reference boards to test its operation (using commands on the UART command line interface) or to test reading, writing and erasing specific addresses in EEPROM and/or Flash.
- http://www.utasker.com/kinetis/FRDM-KE02Z.html
- http://www.utasker.com/kinetis/FRDM-KE02Z40M.html
See http://www.utasker.com/kinetis/KE_EEPROM.html for EEPROM and Flash details, whereby both can be tested.
You can either use it as comparison to solve your problems or else simply use the uTasker project to enable this and enable you to solve your complete project requirements.
The operation (peripherals, including Flash and EEPROM) is accurately simulated in the uTasker KE simulator in case you need to be able to increase your overall developement efficiency over traditional load/debug cycling.
Regards
Mark