FLASH update using IAP and __RAMFUNC

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

FLASH update using IAP and __RAMFUNC

Jump to solution
5,320 Views
tim99
Contributor III

Hi

I am trying to make a routine for updating my firmware without using ISP. So fare I am downloading my firmware to a free location in FLASH and I am now trying to copy this firmware to the first part of the FLASH memory. I am aware that to do this, the function copying the firmware cannot also be in the FLASH section being written to, so I am trying to place this function in RAM using __RAMFUNC. I have attached the code for my function below. However, I am experiencing that the execution is halted after executing the "Erase sectors" IAP command. So it seems to me that the code is not executed from RAM. Anyone have any idea of what I am doing wrong? (I am using LPC1549)

__RAMFUNC(RAM2) void flashing(uint8_t sectors)
{

     unsigned int command[5];                         // Command
     unsigned int result[4];                              // Result
     typedef void (*IAP)(unsigned int[], unsigned int[]);          // IAP Pointer
     IAP iap_Entry = (IAP) IAP_LOCATION;


     uint8_t ret_code,i;
     uint16_t ii;
     uint8_t data[1024];

     /* Disable interrupt mode */
     __disable_irq();

     /* Prepare to write/erase the sector */
     command[0] = IAP_PREWRRITE_CMD;
     command[1] = 0;                                   // strSector
     command[2] = sectors;                                 // endSector
     iap_entry(command, result);

     /* Erase Sectors */
     command[0] = IAP_ERSSECTOR_CMD;
     command[1] = 0;                                   //strSector;
     command[2] = sectors;                                 //endSector;
     command[3] = SystemCoreClock / 1000;
     iap_entry(command, result);
   
        /* Copy 1024 bytes at a time. Sectors = number of sectors to copy */
     for(i=0;i<sectors*4;i++)
     {
          for(ii=0; ii<1024;ii++)
          {
               /* First read date to RAM before writing to FLASH */
                        data[ii] = *(uint8_t*)(START_ADDR_SECTOR+i*1024+ii);
          }
          /* Prepare sector for write */
          command[0] = IAP_PREWRRITE_CMD;
          command[1] = 0;                              // strSector
          command[2] = sectors;                         // endSector
          iap_entry(command, result);

          /* Write to FLASH */
          command[0] = IAP_WRISECTOR_CMD;
          command[1] = i*1024;
          command[2] = (uint32_t) &data;
          command[3] = 1024;
          command[4] = SystemCoreClock / 1000;
          iap_entry(command, result);
     }
     NVIC_SystemReset();  //#TODO 
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 

Labels (2)
Tags (2)
1 Solution
2,940 Views
tim99
Contributor III

Finally, I managed to get it working. Thank you all for guiding me to the solution.

I found that you don't have to move the vector table, but doing so helped me to find out what was wrong. I moved the vector table by copying the first sector to the last sector and then changed VTOR. I then found that my program ended up in the Hard Fault handler. Before moving the vector table the pointer to the Hard Fault handle would have been erased, but now I could investigate what had happened by looking at the vectpc register. I found that my program counter had tried to execute a line in sector 0 that I had erased. The guilty function was iap_entry. I found that the program was calling iap_entry in romapi_15xx.h and not iap_Entry that I had declared. I was not aware that there existed a function with almost the same name as I had used. This function was of course erased when I erased the sector and hence the error. Changing the name of my declaration in RAM and updating the function calls to the new name solved my problem.

View solution in original post

0 Kudos
24 Replies
2,721 Views
juanabelaira
Contributor III

I'm having problem when writing to flash using the IAP functions, I end up in a hard fault...

Just a question, is it really a must to be in RAM to write the flash? I'm writing to areas where there is no code.

0 Kudos
2,720 Views
Ray_V
Contributor V

Most Flash can't be read while it's being erased or written to, even if it is to a different sector.

So all the code and data needed for the operation must to be in RAM.

You should also disable all interrupts.

0 Kudos
2,720 Views
juanabelaira
Contributor III

Keep in mind the IAP functions reside in ROM, not flash, and as long as the interrupts are disabled, no other code or operation is done over the flash during an erase or write operation. I base myself on this to erase flash areas from code in flash (as I said before, the flash operations are not done from flash)

0 Kudos
2,719 Views
Ray_V
Contributor V

Exactly. As I said you can't run from Flash.

This includes any code that calls the IAP functions, so it needs to be placed in RAM.

Remember Flash Erase/Write is not instantaneous, the function could return before Flash is available for reading.

So your function that calls IAP function to Erase or Write is in RAM. Then after calling IAP function check that the operation is done before continuing.

0 Kudos
2,721 Views
juanabelaira
Contributor III

Correct, it's possible to erase and write flash from flash

0 Kudos
2,941 Views
tim99
Contributor III

Finally, I managed to get it working. Thank you all for guiding me to the solution.

I found that you don't have to move the vector table, but doing so helped me to find out what was wrong. I moved the vector table by copying the first sector to the last sector and then changed VTOR. I then found that my program ended up in the Hard Fault handler. Before moving the vector table the pointer to the Hard Fault handle would have been erased, but now I could investigate what had happened by looking at the vectpc register. I found that my program counter had tried to execute a line in sector 0 that I had erased. The guilty function was iap_entry. I found that the program was calling iap_entry in romapi_15xx.h and not iap_Entry that I had declared. I was not aware that there existed a function with almost the same name as I had used. This function was of course erased when I erased the sector and hence the error. Changing the name of my declaration in RAM and updating the function calls to the new name solved my problem.

0 Kudos
2,730 Views
Ray_V
Contributor V

Good to hear you solved it.

We all missed that you declared "iap_Entry" but called "iap_entry"

0 Kudos
2,730 Views
Ray_V
Contributor V

The __RAMFUNC  macro should place the function in RAM. You can verify this by looking in the .map file.

I don't believe you need to place other code In RAM since the function does not return.

You say that it stops executing after the IAP "Erase Sectors" command.  How did you determine this?

The next thing you do after erasing flash is to copy 1024 bytes into the data array. I don't know how your system is configured, but if the stack is also placed in RAM2, what could be happening is that, since the data array is placed in the stack it could overflow into your function and when you copy from flash into the array you overwrite some of the function.

You can try one of the following.

  1. Make sure that the stack is in not in RAM2 area.
  2. Allocate the data array as a global variable in a different RAM area.
  3. Change the array size and copy only a few bytes at a time just to see if this is the case.
0 Kudos
2,730 Views
tim99
Contributor III

Hi Raymundo,

Looking at the address in the disassembly I can see that the function is executed from RAM. I determine that the program is stopped by experiencing that the debugger goes blank and the disassembly returns error. I have also tried to turn on a LED after the call to see if it is something with the debugger, but the LED is not turned on. If I change to any other sector then 0, the function works as expected.

I have tried to move the interrupt vector as Peter suggested, but still no luck. Do you know if that should be necessary?

0 Kudos
2,730 Views
Ray_V
Contributor V

Sorry, I missed the first time I read your reply that it works when you don't try writing to sector 0.

You don't mention if you are using an OS, but if you are, you need to shut it down before attempting to update your program. The OS will use the SVC_Handler and PendSV_Handler which are in flash.

0 Kudos
2,730 Views
Ray_V
Contributor V

Terje,

What I meant is not "how do you determine the program is stopped?"

How do you determine the last code that was executed?

Are you running the debugger one instruction at a time and it never returns from _iap_entry "erase sectors" command?

In other words, are you sure it never entered the loop to copy the 1024 bytes to data array?

You can create and place in RAM the following:

NMI_Handler, // The NMI handler

HardFault_Handler, // The hard fault handler

MemManage_Handler, // The MPU fault handler

BusFault_Handler, // The bus fault handler

UsageFault_Handler,

Just have them stay in an infinite loop. Then you can determine if any of these exceptions occurred.

And yes, moving the vector table to RAM is a good idea. You need to do it anyway for this test.

hope this helps

2,730 Views
petervanhoomiss
Contributor III

Can a similar result be achieved by disabling interrupts before the IAP call untill after the IAP function? Using the "CPS" thumb instruction to set the PRIMASK and FAULT mask should disable any exception (except NMI) from being triggered. I believe this is the underling behavior of the __disable_irq(); and __enable_irq(); functions.

0 Kudos
2,730 Views
Ray_V
Contributor V

Exceptions are not interrupts and occur regardless of the interrupt enable status. Which exception occurs could give you a clue as to what could be going wrong or needs to be done differently.

0 Kudos
2,730 Views
tim99
Contributor III

Hi Ping and thanks for your reply.

What do you mean by the whole bootloader? I was thinking of my function flashing(uint8_t sectors) as my whole bootloader. Is this function missing something to do the job? There are other parts of my code that is storing the new user code to a free area in the FLASH memory, but I do not understand why that part should also be run from RAM. I would think it would be a benefit not to waste too much RAM on this or is the function only stored in RAM when called? I validate that the downloaded user code is correct and then call flashing(uint8_t sectors) that I was hoping would copy the user code from the free area in FLASH to the first flash sector. I have not yet tried to reallocate the interrupt vector as Peter is mentioning. Can you verify that this must be done even if I have disabled interrupts?

0 Kudos
2,730 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Terje Mugaas,

I know the __RAMFUNC execute in the RAM, however the main() function still reside in the Flash.

The correct sequence is the device boots from flash memory and loads the bootloader into RAM. Running from RAM, the
bootloader has accessed to the entire flash array for placement of the user application.
Hope this is clear.
Have a great day,
Ping

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

0 Kudos
2,730 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Terje Mugaas,

Thank you for your interest in NXP Semiconductor products and for the opportunity to serve you.

I think I need the more information about the issue and hope you share.

According to your statement, I think the implementation is the bootloader which allows the the firmware to be downloaded to the targeted flash area, so I'd like to know what flash sectors the bootloader resides in.

Have a great day,
Ping

 

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

0 Kudos
2,730 Views
tim99
Contributor III

Hi Ping,

Yes, I guess that the function I have added in my first post functions as a bootloader, and as I am using __RAMFUNC I was hoping that the function would reside in RAM.

I have not made any changes in the memory map so the rest of the application would start from section 0

0 Kudos
2,730 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Terje Mugaas,

Thanks for the your reply.

I think you should copy the whole bootloader to the RAM besides the flashing(uint8_t sectors), then program the firmware to the targeted flash area which start from the first flash sector.
Have a great day,
Ping

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

0 Kudos
2,730 Views
petervanhoomiss
Contributor III

Hey there Terje,

I had/am having a very similar problem thanks to a lack of documentation from NXP. See here IAP via JTAG on LPC1754 #3 

If you are only having issues programming sector0, like I am, then it might be because you are not relocating the interrupt vector table before writing to that first page.

Best Regards,

Peter

0 Kudos
2,730 Views
tim99
Contributor III

Hi Peter and thanks for a very interesting tip.

I was hoping, as I disable interrupts before I erase sector 0, that I would not need to reallocate the interrupt table, but probably I do. I will try this solution as soon as I get back to the office.

Thanks,

Terje

0 Kudos