MK20DN32VLF : Rewrite flash data issues

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

MK20DN32VLF : Rewrite flash data issues

6,225 Views
TCazala
NXP Employee
NXP Employee

Hi,

I am trying to save datas in flash data emplacement using fonctions generated by the tool (I am using codewarrior). It works fine for the first save but I can not erase et rewrite while I do not reflash the microcontroller. Is there a way to rewrite without reflashing systematically ? 

 

Regards,

Titouan Cazala

Labels (1)
0 Kudos
Reply
13 Replies

6,206 Views
nxf56274
NXP Employee
NXP Employee

Hi,

I also want to know how you operate the flash. Do you disable the global interrupt when you doing flash operation?

Have a great day,
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

- We are following threads for 7 days after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos
Reply

6,184 Views
TCazala
NXP Employee
NXP Employee

Hi,

I do not know the state of global interrupts. There are no trace of any kind of interrupt settings in the whole program. 

It seems like it is drived directly into functions I refered to such as 

/*
** ===================================================================
**     Method      :  FLASH1_Main (component FLASH_LDD)
**
**     Description :
**         This method is used to perform one batch of a flash memory
**         operation operation. This method is used to perform batches
**         of all flash memory operations (Write, Read, Erase,
**         EraseBlock, VerifyErasedBlock) when the component works in
**         the polled mode (interrupt service is disabled - property
**         <Interrupt service>). This method performs batches of the
**         read flash memory operation, when the component works in the
**         interrupt triggered mode (interrupt service is enabled).
**         This method is enabled only if the component works in the
**         polled mode or if the Read method is enabled.
**     Parameters  :
**         NAME            - DESCRIPTION
**       * DeviceDataPtr   - Device data structure
**                           pointer returned by <Init> method.
**     Returns     : Nothing
** ===================================================================
*/
#define UNLIMITED_BATCH_SIZE 0U
#define WRITE_BATCH_SIZE 1U
#define ERASE_BATCH_SIZE 1U
#define READ_BATCH_SIZE UNLIMITED_BATCH_SIZE
#define READ_1S_BLOCK_NORMAL_MARGINE_LEVEL 0U
#define WRITABLE_UNIT_MASK 3U

void FLASH1_Main(LDD_TDeviceData *DeviceDataPtr)
{
  FLASH1_TDeviceDataPtr DeviceDataPrv = (FLASH1_TDeviceDataPtr)DeviceDataPtr; /* Auxiliary variable - pointer to an internal state structure */
  uint32_t DataToPrg = 0xFFFFFFFFLU;   /* Auxiliary variable - current data to be proceeded */
  uint32_t DataToPrgMask = 0U;
  uint32_t CurrentFlashPrgUnitData;    /* Current flash location content */
  uint8_t PrgBytesCount;               /* Auxiliary variable - Current data counter - number of data to be proceeded (in bytes) */
  uint8_t MaxPossiblePrgBytes = 0U;
  uint8_t DstAddrOffset = 0U;          /* Offset of the desired flash location to be written from the begging of the smallest writable unit the desired location belongs to */
  uint8_t i;
  LDD_FLASH_TAddress FlashPrgUnitAddr;
  uint16_t StepsOfBatch = 0U;          /* Number of batch cycles to be proceeded */
  bool NextBatchCycle;                 /* Unlimited batch flag */
  uint8_t CurrentFlags;                /* Auxiliary variable - current hw flags */

  if ((DeviceDataPrv->CurrentOperationStatus != LDD_FLASH_RUNNING) && /* If there is not an operation in progress or pending then end */\
     (DeviceDataPrv->CurrentOperationStatus != LDD_FLASH_START) && \
     (DeviceDataPrv->CurrentOperationStatus != LDD_FLASH_STOP_REQ)) {
    return;
  }
  if ((FTFL_PDD_GetFlags(FTFL_BASE_PTR) & FTFL_PDD_COMMAND_COMPLETE) == 0U){ /* If there is some flash operation in progress then end */
    return;
  }
  if (DeviceDataPrv->CurrentOperationStatus == LDD_FLASH_START) { /* Is this run the first run of the Main method in this operation? */
    FTFL_PDD_ClearFlags(FTFL_BASE_PTR, /* If yes, clear hw flags */
                        FTFL_PDD_READ_COLLISION_ERROR | \
                        FTFL_PDD_ACCESS_ERROR | \
                        FTFL_PDD_PROTECTION_VIOLATION);
    DeviceDataPrv->CurrentErrorFlags = 0U; /* Clear Current SW error flags */
  } else {                             /* If this is not the first run of the operation, checks the error flags */
    CurrentFlags = FTFL_PDD_GetFlags(FTFL_BASE_PTR);
    DeviceDataPrv->CurrentErrorFlags |= CurrentFlags & /* Save current hw flags */\
    (FTFL_PDD_READ_COLLISION_ERROR | \
     FTFL_PDD_ACCESS_ERROR | \
     FTFL_PDD_PROTECTION_VIOLATION);
    if ((DeviceDataPrv->CurrentOperation == LDD_FLASH_VERIFY_ERASED_BLOCK) && (CurrentFlags & FTFL_PDD_COMMAND_COMPLETION_STATUS)) { /* Was the verification of erased block successfull? */
      DeviceDataPrv->CurrentErrorFlags |= LDD_FLASH_ERASE_VERIFICATION_ERROR; /* if no, set the Erase verification error flag */
    }
    if (DeviceDataPrv->CurrentErrorFlags != 0U) { /* Has some error occurred? */
      DeviceDataPrv->CurrentOperationStatus = LDD_FLASH_FAILED; /* If yes, set the operation state to FAILED */
      if (DeviceDataPrv->CurrentOperation != LDD_FLASH_READ) {
        FMC_PDD_InvalidateFlashCache(FMC_BASE_PTR);
        PE_NOP();
        PE_NOP();
        PE_NOP();
      }
      return;                          /* End */
    }
    if (DeviceDataPrv->DataCounter == 0U) { /* If all the data has been successfully proceeded, finish the operation */
      DeviceDataPrv->CurrentOperationStatus = LDD_FLASH_IDLE; /* If yes, change the operation state to IDLE */
      if (DeviceDataPrv->CurrentOperation != LDD_FLASH_READ) {
        FMC_PDD_InvalidateFlashCache(FMC_BASE_PTR);
        PE_NOP();
        PE_NOP();
        PE_NOP();
      }
      FLASH1_OnOperationComplete(DeviceDataPrv->UserDataPtr); /* Invoke the OnOperationComplete event */
      return;                          /* End */
    }
  }
  switch (DeviceDataPrv->CurrentOperation) { /* Define the batch counter's initial value according to the current operation */
    case LDD_FLASH_WRITE:              /* The current operation is Write */
      StepsOfBatch = WRITE_BATCH_SIZE; /* Initialize the batch counter */
      break;                           /* Break of the case */
    case LDD_FLASH_ERASE:              /* The current operation is Erase */
      StepsOfBatch = ERASE_BATCH_SIZE; /* Initialize the batch counter */
      break;                           /* Break of the case */
    case LDD_FLASH_READ:               /* The current operation is Read */
      StepsOfBatch = READ_BATCH_SIZE;  /* Initialize the batch counter */
      break;                           /* Break of the case */
    case LDD_FLASH_ERASE_BLOCK:        /* The current operation is Erase block */
      StepsOfBatch = 1U;               /* Initialize the batch counter */
      break;                           /* Break of the case */
    case LDD_FLASH_VERIFY_ERASED_BLOCK: /* The current operation is Verify erased block */
      StepsOfBatch = 1U;               /* Initialize the batch counter */
      break;                           /* Break of the case */
    default:
      break;
  }
  if (StepsOfBatch == UNLIMITED_BATCH_SIZE) { /* Is the unlimited batch of size selected for the current operation? */
    NextBatchCycle = TRUE;             /* If the unlimited batch of size is used, set the NextCycle force variable to TRUE */
  } else {
    NextBatchCycle = FALSE;            /* If the unlimited batch of size is used, set the NextCycle force variable to FALSE */
  }
  while ((StepsOfBatch > 0U) || (NextBatchCycle)) { /* Should another batch of the current operation be proceeded in this Main method processing? */
    CurrentFlags = FTFL_PDD_GetFlags(FTFL_BASE_PTR); /* Read current hardware flags */
    if ((CurrentFlags & (FTFL_PDD_READ_COLLISION_ERROR /* Check the error flags */\
                     | FTFL_PDD_ACCESS_ERROR \
                     | FTFL_PDD_PROTECTION_VIOLATION)) != 0U) {
      return;                          /* If there has some error occurred then end. The error will be analyzed in the next call of the Main method */
    }
    if (DeviceDataPrv->CurrentOperationStatus == LDD_FLASH_START) { /* Is this step the first step of the operation? */
      DeviceDataPrv->CurrentOperationStatus = LDD_FLASH_RUNNING; /* If yes, change Current operation status to RUNNING */
    } else {
      DeviceDataPrv->CurrentFlashAddress += DeviceDataPrv->CurrentDataSize; /* If no, define of an address of a step of the current operation (address of the first step of the operation is defined by a operational method, which defines the operation */
      if ((DeviceDataPrv->CurrentOperation == LDD_FLASH_READ) || (DeviceDataPrv->CurrentOperation == LDD_FLASH_WRITE)) {
        DeviceDataPrv->CurrentDataPtr += DeviceDataPrv->CurrentDataSize; /* Update of the Current data pointer */
      }
    }
    switch(DeviceDataPrv->CurrentOperation) { /* Perform needed actions for the next step of the operation (for the next flash operation command) according to the current operation type */
      case LDD_FLASH_READ:             /* Read operation */
        *DeviceDataPrv->CurrentDataPtr = *(uint8_t *)DeviceDataPrv->CurrentFlashAddress; /* Read data from flash */
        DeviceDataPrv->DataCounter--;  /* Update of the Data counter */
        break;
      case LDD_FLASH_ERASE:            /* Erase operation */
        DeviceDataPrv->DataCounter -= (uint32_t)(FLASH1_ERASABLE_UNIT_SIZE); /* Update of the Data counter */
        break;
      case LDD_FLASH_ERASE_BLOCK:      /* Erase block operation */
        DeviceDataPrv->DataCounter--;  /* Update of the Data counter (the unit is a block not a byte) */
        break;
      case LDD_FLASH_VERIFY_ERASED_BLOCK:
        DeviceDataPrv->DataCounter--;  /* Update of the Data counter (the unit is a block not a byte) */
        FTFL_PDD_WriteFCCOB4Reg(FTFL_BASE_PTR, READ_1S_BLOCK_NORMAL_MARGINE_LEVEL); /* Set the Read margin level for the Read 1s block operation */
        break;
      case LDD_FLASH_WRITE:
        DstAddrOffset = (uint8_t)DeviceDataPrv->CurrentFlashAddress & WRITABLE_UNIT_MASK; /* Compute the address of the writable unit */
        MaxPossiblePrgBytes = (WRITABLE_UNIT_MASK - DstAddrOffset) + 1U; /* Compute number of bytes from the destination address to the end of the writable unit */
        if (DeviceDataPrv->DataCounter < MaxPossiblePrgBytes) {
          PrgBytesCount = (uint8_t)DeviceDataPrv->DataCounter;
        } else {
          PrgBytesCount = MaxPossiblePrgBytes;
        }
        for (i = 0U; i < PrgBytesCount; i++)  {
          ((uint8_t *)(void *)&DataToPrg)[DstAddrOffset + i] = ((uint8_t *)(void *)(DeviceDataPrv->CurrentDataPtr))[i];
          ((uint8_t *)(void *)&DataToPrgMask)[DstAddrOffset + i] = 0xFFu;
        }
        FlashPrgUnitAddr = DeviceDataPrv->CurrentFlashAddress - DstAddrOffset;
        CurrentFlashPrgUnitData = *(uint32_t *)FlashPrgUnitAddr;
        if(((DataToPrg & DataToPrgMask) & (~CurrentFlashPrgUnitData)) > 0U) {
          DeviceDataPrv->CurrentErrorFlags |= LDD_FLASH_MULTIPLE_WRITE_ERROR;
          return;
        }
        DataToPrg = DataToPrg ^ (~CurrentFlashPrgUnitData);
        DeviceDataPrv->CurrentDataSize = PrgBytesCount;
        DeviceDataPrv->DataCounter -= PrgBytesCount;
        FTFL_PDD_WriteFCCOBLongWordData(FTFL_BASE_PTR, DataToPrg);
        break;
      default:
        break;
    } /* switch(DeviceDataPrv->CurrentOperation) */
    StepsOfBatch -= 1U;
    if (DeviceDataPrv->DataCounter == 0U) {
      NextBatchCycle = FALSE;
      StepsOfBatch = 0U;
    }
    if (DeviceDataPrv->CurrentOperation != LDD_FLASH_READ) {
      FTFL_PDD_SetFCCOBCommand(FTFL_BASE_PTR, DeviceDataPrv->CurrentCommand); /* Set the desired flash operation command */
      FTFL_PDD_SetFCCOBAddress(FTFL_BASE_PTR, ((uint32_t)(DeviceDataPrv->CurrentFlashAddress - DstAddrOffset))); /* Set an address of the flash memory location for the current flash operation command */
      /* {Default RTOS Adapter} Critical section begin, general PE function is used */
      EnterCritical();
      ((LDD_FLASH_TSafeRoutinePtr)((uint32_t)(DeviceDataPrv->SafeRoutinePtr) | 1U))(); /* Run the Safe routine */
      /* {Default RTOS Adapter} Critical section end, general PE function is used */
      ExitCritical();
    }
  }
}

 

Maybe, I did not understood your questions ? If I do, please tell me I will try to find something else which can match.

Thanks for your help.
Regards

0 Kudos
Reply

6,162 Views
ErichStyger
Specialist I

 Hi @TCazala,

About the interrupts: this depends if you are using the interrupt flash driver method or the non-interrupt one. I prefer the non-interrupt on.

You can see in https://mcuoneclipse.com/2014/05/31/configuration-data-using-the-internal-flash-instead-of-an-extern... how I'm using this with KL25Z and Processor Expert. I don't have the MK20DN32, but things worked the same for me for the K20DN128.

I hope this helps,

Erich

0 Kudos
Reply

6,139 Views
TCazala
NXP Employee
NXP Employee

Hi @ErichStyger ,

I am trying to use your solution in my project but I have some type issues like.
Did you encountered something like "illegal implicit conversion from int to void*" when you were using NVMC_GetSumoData() ?


I also had troubles whith "uintX_t", did it happened to you as well ? 

Thanks.

0 Kudos
Reply

6,134 Views
ErichStyger
Specialist I

Hi @TCazala ,

Did you encountered something like "illegal implicit conversion from int to void*" when you were using NVMC_GetSumoData() ?

This sounds like you did not properly use/include the interface/header file.

I also had troubles whith "uintX_t", did it happened to you as well ?

Did you include <stdint.h>?

I hope this helps,

Erich

0 Kudos
Reply

6,107 Views
TCazala
NXP Employee
NXP Employee

Hi @ErichStyger ,

You were right, I feel so dumb !
Thank you.

I will let you know if your method works for me as soon as I retablished the communication with my device.
It seems that all those changement fucked up something, I have to find a way to fix it.

 

Thanks for your time.

6,210 Views
myke_predko
Senior Contributor III

@TCazala 

Could you share your code for writing a sector in Flash?  I'm not sure what you mean by functions generated by CodeWarrior.  When I worked with CodeWarrior, the APIs provided were quite rudimentary although there are some basic Flash IO functions available.  

I have Flash writing code written under CodeWarrior for the MK20DN512VLLL10 and runs with MQX.  I must point out that I had to create my own BSP for CodeWarrior and it was a lot of work which leads me to the question...

Why are you working with CodeWarrior and not MCUXpresso?  CodeWarrior should really be considered out of date.  

0 Kudos
Reply

6,182 Views
TCazala
NXP Employee
NXP Employee

Hi @myke_predko 

Here is an example of the routine i'm using to rewrite a part of the flash.

 

 

do
{
  Error = FLASH1_EraseBlock(MyFLASH_Ptr, CalibrationDataAdress);
   do 
   {	FLASH1_Main(MyFLASH_Ptr);
        OpStatus = FLASH1_GetOperationStatus(MyFLASH_Ptr);						
   } while (!((OpStatus == LDD_FLASH_IDLE) | (OpStatus == LDD_FLASH_FAILED)));
	
   DataWrittenFlg = FALSE;
   Error = FLASH1_Write(MyFLASH_Ptr, InpData, CalibrationDataAdress, 0x15);   	  	
					
   do 
   {	FLASH1_Main(MyFLASH_Ptr);
        OpStatus = FLASH1_GetOperationStatus(MyFLASH_Ptr);
   } while (!((OpStatus == LDD_FLASH_IDLE) | (OpStatus == LDD_FLASH_FAILED)));	
} while(OpStatus == LDD_FLASH_FAILED);
				
HowManyFlashWrites++;
DataWrittenFlg = FALSE;
if (FLASH1_GetOperationStatus(MyFLASH_Ptr) == LDD_FLASH_FAILED) {}
				
Error = FLASH1_Read(MyFLASH_Ptr, CalibrationDataAdress, FlashCopy, 0x15);    
do 
{	FLASH1_Main(MyFLASH_Ptr);
        OpStatus = FLASH1_GetOperationStatus(MyFLASH_Ptr);
} while (!((OpStatus == LDD_FLASH_IDLE) | (OpStatus == LDD_FLASH_FAILED)));
if (OpStatus == LDD_FLASH_FAILED) {};	

 

(I have delays between each operation)

 

Folowing functions are those I were refere to in my initial text.

 

 

FLASH1_EraseBlock (component FLASH_LDD)
FLASH1_Write (component FLASH_LDD)
FLASH1_Read (component FLASH_LDD)
FLASH1_Main (component FLASH_LDD)

 

 


I link to this message the generated file containing function description for using the flash.

Regards

0 Kudos
Reply

6,171 Views
myke_predko
Senior Contributor III

Hi @TCazala 

Sorry, the APIs that I am using are completely different.  Where did you get this code?  

When @nxf56274 is asking about disabling global interrupts, it is calling (in the SDK) "__disable_irq()" before doing the write and "__enable_irq()" after which are defined as:

__attribute__((always_inline)) __STATIC_INLINE void __disable_irq(void)
{
__ASM volatile ("cpsid i" : : : "memory");
}
__attribute__((always_inline)) __STATIC_INLINE void __enable_irq(void)
{
__ASM volatile ("cpsie i" : : : "memory");
}

You may want to try disabling interrupts before calling "FLASH1_Main" and then enabling them upon return.  

Good luck!

 

0 Kudos
Reply

6,164 Views
TCazala
NXP Employee
NXP Employee

Hi @myke_predko,

I am using Codewarrior for MCU version 11.1. I were contrained to use this API because I heritated this project from one of my collegue that can not support me on those issues ...
The code I sent you was directly in the project my collegue gave to me and in the heading, it is written that was "generated by the tool".
Moreover, in the description, lower in heading, there is a settings list where is this line : "Interrupt service : Disabled". I assume that iterrupts are already disabled when calling functions from this library.

It seems like I do not have any functions to enable/disable interrupts or I can not find which are they... Based to overs questions on forums it should be define in ProcessorExpert but there are not any trace of those.

Should I try to define it by myself, following your code ? 

Here is the Project explorer, maybe it can be more usefull to understand my problem... 

TCazala_0-1625496407518.png

 

Thanks for your help !

0 Kudos
Reply

6,149 Views
myke_predko
Senior Contributor III

@TCazala 

Could you try putting the disable_irq before the call to "FLASH1_Main" and enable them afterwards.  

I agree with @ErichStyger that you should use IRQ disabled Flash writes.  

When I read the comment in the source code:

/*
** ===================================================================
**     Method      :  FLASH1_Main (component FLASH_LDD)
**
**     Description :
**         This method is used to perform one batch of a flash memory
**         operation operation. This method is used to perform batches
**         of all flash memory operations (Write, Read, Erase,
**         EraseBlock, VerifyErasedBlock) when the component works in
**         the polled mode (interrupt service is disabled - property
**         <Interrupt service>). This method performs batches of the
**         read flash memory operation, when the component works in the
**         interrupt triggered mode (interrupt service is enabled).
**         This method is enabled only if the component works in the
**         polled mode or if the Read method is enabled.
**     Parameters  :
**         NAME            - DESCRIPTION
**       * DeviceDataPtr   - Device data structure
**                           pointer returned by <Init> method.
**     Returns     : Nothing
** ===================================================================
*/

I take it to mean that interrupts are disabled when this method is called.  It's a bit ambiguous and poorly written.  

Good luck.

0 Kudos
Reply

6,136 Views
TCazala
NXP Employee
NXP Employee

Hi @myke_predko,

It did not work with the FLASH1 component.

I undertook to the @ErichStyger method. I am having some type troubles right now but his tutorial lead me to options I was looking for. I hope when I solved type issues it will work fine.

 

Tanks.

6,126 Views
myke_predko
Senior Contributor III

@TCazala 

Sorry it didn't work out for you.  I never found PE to be able to generate great code - the current SDK is a lot better.  

I'm sure @ErichStyger has the right approach for you.

myke

0 Kudos
Reply