LPC4357 M4 upgrades m0 firmware

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

LPC4357 M4 upgrades m0 firmware

1,324 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pgeloso on Thu Jun 11 09:15:09 MST 2015

Hi,
I'd like to know how to implement a dual core LPC4357 firmware upgrade using IAP. 
The aim is to upgrade m0 fw through M4, using IAP. 

1) I create a *.bin file of the m0 code. Then I'v extrected the bytes needed for the upgrade and I've placed them into M4 code
2) using IAP from M4, I simply program FlashB, starting from sector 0

I tried this procedure but the m0 code doesn't start after the upgrade (and after an LPC4357 reset).

Any sugegstions?

Thanks
Pietro


Labels (1)
0 Kudos
17 Replies

1,202 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pgeloso on Mon Jun 15 03:08:29 MST 2015
Good point!
Now it finally works!

I was placing bytes in a 32bit word in a reverse mode. Now the uint32_t word is filled correctly.
flash_data=(new_firmware[fw_index+3]<<24)|(new_firmware[fw_index+2]<<16)|(new_firmware[fw_index+1]<<8)|new_firmware[fw_index];//    THE RIGHT WAY!

Now I can upgrade m0 from M4 and also M4 from m0.
I'm attachinig the code, if it can be useful for other people (I'm using LPCXpresso 7.8.0 and EA-LPC4357 board).

Thank you so Much, "TheFallGuy" and also "R2D2".

Have a good day!
Bye
0 Kudos

1,202 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by TheFallGuy on Mon Jun 15 01:44:32 MST 2015
Does your software run if you don't download it, but have it as the default image in flash? Have you compared what is in memory vs what you expect to be in memory?
0 Kudos

1,202 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pgeloso on Mon Jun 15 01:24:15 MST 2015
Ok, thank you very much for the help,
I missed the checksum "story", even if from the documentation it's not very clear if its related to M4 only or also to m0 core.

I generated a bin file through checksum, but there's still something wrong...
The m0 doesn't start...
..very annoying...

Any other suggestions?
Do you where's a reference example for IAP fw upgrade with LPC4300?

Thanks!
Pietro
0 Kudos

1,202 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Fri Jun 12 09:19:02 MST 2015

Quote: pgeloso
Hi,
sorry, I don't understand why checksum could help to have a valid m0 .bin file.



User manual:


Quote:
6.4.4.1 Criterion for Valid User Code
The reserved Cortex-M4 exception vector location 7 (offset 0x 001C in the vector table) should contain the 2’s complement of the check-sum of table entries 0 through 6. This causes the checksum of the first 8 table entries to be 0. The boot loader code checksums the first 8 locations in sector 0 of the flash.[color=#f00] If the result is 0, then execution control is transferred to the user code.
[/color]
[color=#f00]If the signature is not valid, the auto-baud routine synchronizes with the host via serial port 0.[/color]


0 Kudos

1,202 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by TheFallGuy on Fri Jun 12 09:12:36 MST 2015

Quote:
Am I missing something?



Yes.

Read about image checksums. You *need* it.
http://www.lpcware.com/content/faq/lpcxpresso/image-checksums
0 Kudos

1,202 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pgeloso on Fri Jun 12 08:58:29 MST 2015
Hi,
sorry, I don't understand why checksum could help to have a valid m0 .bin file.
I'm not validating m0 code consistancy because I'm not transmitting it through UART, I'm using it directly, as it is..I'm not calculating any checksum

Am I missing something?
Thanks
Bye
0 Kudos

1,202 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Fri Jun 12 08:34:51 MST 2015

Quote: pgeloso
2) I compile to have the bin file with this option: arm-none-eabi-objcopy -O binary ${BuildArtifactFileName} ${BuildArtifactFileBaseName}.bin



So where's the checksum  :~
0 Kudos

1,202 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pgeloso on Fri Jun 12 08:28:10 MST 2015
Good question,
I think so because I used this procedure to upgrade lpc1114 parts..
I expect the vector table and the other suff should be there..but I don't know how to verify it.

The procedure I use to have to m0 fw that will be installed,  is the following:

1) the m0 code I'm compiling it the one that is already run by M4 core. I simply change one variable to have quicker "blinky" on an output pin, just to see on the oscilloscope what's going on.
2) I compile to have the bin file with this option: arm-none-eabi-objcopy -O binary ${BuildArtifactFileName} ${BuildArtifactFileBaseName}.bin
3) I extract data with the routine attached.

That's it..I don't know if something is missing..

Thank you for your interest in this issue!
Regards
Pietro


int main(void) { //m0 core

int i;
const int time=500000;//10000=fast 500000=slow  //<<<<--- I just change this value to change the blinky frequency

#if defined (M0_SLAVE_PAUSE_AT_MAIN)
    // Pause execution until debugger attaches and modifies variable
    while (pause_at_main == 0) {}
#endif


    SystemCoreClockUpdate();
    Board_UART_Init(0);//needed, or it will not compile ..??..

// LED setup
//pin SODIMM-GPIO76=P9_0=GPIO4[12] pin 57 del J5
Chip_SCU_PinMuxSet(4, 12, SCU_MODE_FUNC0 | SCU_MODE_INACT);  //SCU_MODE_INACT disable pull up/down  // la SCU_MODE_FUNC0/1/2/.. la trovi sull'U.M. (User Manual)
  Chip_GPIO_SetPinDIROutput(LPC_GPIO_PORT, 4, 12);
    Chip_GPIO_SetPinOutHigh(LPC_GPIO_PORT,4, 12); //led high
  Chip_GPIO_SetPinOutLow(LPC_GPIO_PORT, 4, 12);//led low


    while(1) {
    for(i=0;i<time;i++);
    Chip_GPIO_SetPinOutHigh(LPC_GPIO_PORT, 4, 12); //led high
    for(i=0;i<time;i++);
Chip_GPIO_SetPinOutLow(LPC_GPIO_PORT, 4, 12);//led low
    }
    return 0 ;
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
/// This code runs on PC to convert *.bin file into ascii *.h file
///////////////////////////////////////////////////////////////////////////////////////////////////

#include <stdio.h>

int main(int argc, char *argv[])
{
FILE *fpi, *fpo;
unsigned char v;

  if (argc < 3)
  {
    printf("USAGE: BINconvert <sourcefile.bin> <destfile.h>\n");
    return 0;
  }
  
  fpi = fopen(argv[1], "rb");
  if (fpi == 0)
  {
    printf("Cannot open file %s\n", argv[1]);
    return -1;
  }
  fpo = fopen(argv[2], "w");
  if (fpo == 0)
  {
    printf("Cannot create file %s\n", argv[2]);
    return -1;
  }
  
  fread(&v, 1, 1, fpi);
  while (!feof(fpi))
  {
    fprintf(fpo, "%d,\n", (int)v);
    fread(&v, 1, 1, fpi);
  }
  
  fclose(fpo);
  fclose(fpi);
  return 0;
}



0 Kudos

1,202 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by TheFallGuy on Fri Jun 12 07:36:35 MST 2015
So, does the image that you are loading have the vector table (including SP and initial PC) at the start of the file ?
0 Kudos

1,202 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pgeloso on Fri Jun 12 07:15:53 MST 2015
Hi,
thanks, I've tried also this:

haltSlave(SLAVE_M0APP);//halt the slave
result8 = fw_upgrade_m0();
result8 += verify_fw_copy();//verify
cr_start_m0(SLAVE_M0APP,&__core_m0app_START__);

where "haltSlave" and "cr_start_m0" are  in the cr_start_m0.c file created by LPCXpresso:

..but without success.
Are you referring to this or I misunderstood somthing?

Thanks
Bye!


//*****************************************************************************
//   +--+
//   | ++----+
//   +-++    |
//     |     |
//   +-+--+  |
//   | +--+--+
//   +----+    Copyright (c) 2013 Code Red Technologies Ltd.
//
// cr_start_m0.c
//
// Provides function for CM4 'master' CPU in an NXP LPC43xx MCU to release
// CM0 'slave' CPUs from reset and begin executing.
//
// Version : 130410
//
// Software License Agreement
//
// The software is owned by Code Red Technologies and/or its suppliers, and is
// protected under applicable copyright laws.  All rights are reserved.  Any
// use in violation of the foregoing restrictions may subject the user to criminal
// sanctions under applicable laws, as well as to civil liability for the breach
// of the terms and conditions of this license.
//
// THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
// OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
// USE OF THIS SOFTWARE FOR COMMERCIAL DEVELOPMENT AND/OR EDUCATION IS SUBJECT
// TO A CURRENT END USER LICENSE AGREEMENT (COMMERCIAL OR EDUCATIONAL) WITH
// CODE RED TECHNOLOGIES LTD.
//
//*****************************************************************************

#include "cr_start_m0.h"

// Provide defines for accessing peripheral registers necessary to release
// CM0 slave processors from reset. Note that this code does not use the
// CMSIS register access mechanism, as there is no guarantee that the
// project has been configured to use CMSIS.
#define RGU_RESET_CTRL1          (*((volatile uint32_t *) 0x40053104))
#define RGU_RESET_ACTIVE_STATUS1  (*((volatile uint32_t *) 0x40053154))
#define RGU_RESET_CTRL0          (*((volatile uint32_t *) 0x40053100))
#define RGU_RESET_ACTIVE_STATUS0  (*((volatile uint32_t *) 0x40053150))
#define CREG_M0APPMEMMAP        (*((volatile uint32_t *) 0x40043404))
#define CREG_M0SUBMEMMAP          (*((volatile uint32_t *) 0x40043308))

/*******************************************************************
 * Static function to Release SLAVE processor from reset
 *******************************************************************/
 void startSlave(uint32_t slavenum) {

volatile uint32_t u32REG, u32Val;

if (slavenum <= SLAVE_M0SUB) {

if (slavenum == SLAVE_M0APP) {
/* Release Slave from reset, first read status */
/* Notice, this is a read only register !!! */
u32REG = RGU_RESET_ACTIVE_STATUS1;

/* If the M0 is being held in reset, release it */
/* 1 = no reset, 0 = reset */
while (!(u32REG & (1u << 24))) {
u32Val = (~(u32REG) & (~(1 << 24)));
RGU_RESET_CTRL1 = u32Val;
u32REG = RGU_RESET_ACTIVE_STATUS1;
};
}
else { // (slavenum == SLAVE_M0SUB)
/* Release Slave from reset, first read status */
/* Notice, this is a read only register !!! */
u32REG = RGU_RESET_ACTIVE_STATUS0;

/* If the M0 is being held in reset, release it */
/* 1 = no reset, 0 = reset */
while (!(u32REG & (1u << 12))) {
u32Val = (~(u32REG) & (~(1 << 12)));
RGU_RESET_CTRL0 = u32Val;
u32REG = RGU_RESET_ACTIVE_STATUS0;
};

}
}
}

/*******************************************************************
 * Static function to put the SLAVE processor back in reset
 *******************************************************************/
 void haltSlave(uint32_t slavenum) {

volatile uint32_t u32REG, u32Val;

if (slavenum <= SLAVE_M0SUB) {

if (slavenum == SLAVE_M0APP) {

/* Check if M0 is reset by reading status */
u32REG = RGU_RESET_ACTIVE_STATUS1;

/* If the M0 has reset not asserted, halt it... */
/* in u32REG, status register, 1 = no reset */
while ((u32REG & (1u << 24))) {
u32Val = ((~u32REG) | (1 << 24));
RGU_RESET_CTRL1 = u32Val;
u32REG = RGU_RESET_ACTIVE_STATUS1;
}
} else { // (slavenum == SLAVE_M0SUB)
/* Check if M0 is reset by reading status */
u32REG = RGU_RESET_ACTIVE_STATUS0;

/* If the M0 has reset not asserted, halt it... */
/* in u32REG, status register, 1 = no reset */
while ((u32REG & (1u << 12))) {
u32Val = ((~u32REG) | (1 << 12));
RGU_RESET_CTRL0 = u32Val;
u32REG = RGU_RESET_ACTIVE_STATUS0;
}

}
}

}

/*******************************************************************
 * Function to start required CM0 slave cpu executing
 *******************************************************************/
void cr_start_m0(uint32_t slavenum, uint8_t *CM0image_start)  {

if (slavenum <= SLAVE_M0SUB) {

// Make sure M0 is not running
haltSlave(slavenum);

// Set M0's vector table to point to start of M0 image
if (slavenum == SLAVE_M0APP) {
CREG_M0APPMEMMAP = (uint32_t) CM0image_start;
} else { // (slavenum == SLAVE_M0SUB)
CREG_M0SUBMEMMAP = (uint32_t) CM0image_start;
}
// Release M0 from reset
startSlave(slavenum);
}
}

0 Kudos

1,202 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by TheFallGuy on Fri Jun 12 06:43:30 MST 2015
So, the m0 is running from Flash?
And then, while it is running, you overwrite the code it is running from. What do you think it will do at this stage?

You need to stop the m0. Program the Flash, then restart it, providing the new startup address (Stack pointer followed by initial PC)
0 Kudos

1,202 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pgeloso on Fri Jun 12 06:22:53 MST 2015
Hi,
thanks, I'll add some details of the code written LPCXpresso 7.8.0 and EA-LPC4357 board.

I've created an m0 that toggles a pin output that is run by the M4 core. Now I want to upgrade the m0 core with a new fw that simply increses the frequency of the pin topggled.

With the build option:
arm-none-eabi-objcopy -O binary ${BuildArtifactFileName} ${BuildArtifactFileBaseName}.bin
I create a bin file of m0 code.
Then I extract ascii data from the .bin file and I save them in a .h file, loaded by M4 code into an array:
     const unsigned char new_firmware[] = { //2664 bytes
          #include "m0toggle_fast.h"
     };

In M4, once started the m0 code, I copy the data into FlashB, sector 0 and (then I verify the  if writing is ok).
That's it!
But the m0 doesn't start again..

I'm adding part of the code and the entire m4 code.

Any help is welcome!
Regards!

int main(void) {

uint8_t result8=0;

    // Read clock settings and update SystemCoreClock variable
    SystemCoreClockUpdate();
    // Set up and initialize all required blocks and
    // functions related to the board hardware
    Board_Init();

    // Set the LED to the state of "On"
//    Board_LED_Set(0, true);

    // Start M0APP slave processor
#if defined (__MULTICORE_MASTER_SLAVE_M0APP)
    cr_start_m0(SLAVE_M0APP,&__core_m0app_START__);
#endif

    if(result8!=0){// it enters here only during debug...
//haltSlave(SLAVE_M0APP);//halt the slave ???
result8 = fw_upgrade_m0();//used to copy blinky.h file into Flash BankA in the traditional way. Routine from flash

 result8 += verify_fw_copy();//verify
 if(result8!=0){
 while(1);//error!
 }

    }

    while(1) {
    }
    return 0 ;
}




// we're copying fw upgrade data from .h file into flash bankB, starting from sector 0
uint8_t fw_upgrade_m0(void){

uint32_t sector_bankb_start_map[15];
uint32_t sector_bankb_end_map[15];

uint32_t fw_lenght, fw_index,sector_address;
int i;
uint8_t result8=0;

//Define start address of B Flash sector
sector_bankb_start_map[0]= 0x1B000000;
sector_bankb_start_map[1]= 0x1B002000;
sector_bankb_start_map[2]= 0x1B004000;
sector_bankb_start_map[3]= 0x1B006000;
sector_bankb_start_map[4]= 0x1B008000;
sector_bankb_start_map[5]= 0x1B00A000;
sector_bankb_start_map[6]= 0x1B00C000;
sector_bankb_start_map[7]= 0x1B00E000;
sector_bankb_start_map[8]= 0x1B010000;
sector_bankb_start_map[9]= 0x1B020000;
sector_bankb_start_map[10]=0x1B030000;
sector_bankb_start_map[11]=0x1B040000;
sector_bankb_start_map[12]=0x1B050000;
sector_bankb_start_map[13]=0x1B060000;
sector_bankb_start_map[14]=0x1B070000;

//Define end address of B Flash sector
sector_bankb_end_map[0]=0x1B001FFF;
sector_bankb_end_map[1]=0x1B003FFF;
sector_bankb_end_map[2]=0x1B005FFF;
sector_bankb_end_map[3]=0x1B007FFF;
sector_bankb_end_map[4]=0x1B009FFF;
sector_bankb_end_map[5]=0x1B00BFFF;
sector_bankb_end_map[6]=0x1B00DFFF;
sector_bankb_end_map[7]=0x1B00FFFF;
sector_bankb_end_map[8]=0x1B01FFFF;
sector_bankb_end_map[9]=0x1B02FFFF;
sector_bankb_end_map[10]=0x1B03FFFF;
sector_bankb_end_map[11]=0x1B04FFFF;
sector_bankb_end_map[12]=0x1B05FFFF;
sector_bankb_end_map[13]=0x1B06FFFF;
sector_bankb_end_map[14]=0x1B07FFFF;


Chip_IAP_Initialise();

uint32_t n_sector=STARTING_SECTOR_N;//we start writing data here, the first sector of bank B

 __disable_irq();

sector_address=sector_bankb_start_map[n_sector];
    result8 = Chip_IAP_PreSectorForReadWrite(n_sector, n_sector, 1); //sector 14(64KB) of flashBankB=1//prepare first
    result8+= Chip_IAP_EraseSector(n_sector, n_sector, 1);//erase first sector!

 fw_lenght=sizeof(new_firmware);
 fw_index=0;
 //scrivo 1024 dati da 32bit per volta. Dato che accedo a singoli byte, vuol dire che scrivo 1024*4 bytes per volta.

 while(fw_index<fw_lenght){

for(i=0;i<FLASH_DWORD_BLOCK;i++){ //filling 4k bytes into 1k dword
flash_data=(new_firmware[fw_index]<<24)|(new_firmware[fw_index+1]<<16)|(new_firmware[fw_index+2]<<8)|new_firmware[fw_index+3];//creating 32bit data
fw_index +=4;
if(!(fw_index<fw_lenght)){//last_iteration?
   for(i=i+1;i<FLASH_DWORD_BLOCK;i++) flash_data=0xFFFFFFFF;// fill with erased data
break;//fine del ciclo for
}
}

//storing data into flash
//prepare
//copy ram
result8 += Chip_IAP_PreSectorForReadWrite(n_sector, n_sector, 1); // flashBankA=0
    result8+= Chip_IAP_CopyRamToFlash(sector_address, flash_data, FLASH_BLOCK);//we have written 1024*4=4096bytes sulla flash

//ora cambia indirizzo su flash
sector_address +=FLASH_BLOCK;
if(!(sector_address<sector_bankb_end_map[n_sector])){//if needed, change sector
n_sector++; //new sector
if(!(n_sector<MAX_FLASH_SECTOR)){
//fail !!
}
sector_address=sector_bankb_start_map[n_sector];//new address
//nuovo settore:
//ret_val=(*longfunc_)(sector_number);//prepare
//ret_val +=(*longfunc2)(sector_number);//erase
    result8 += Chip_IAP_PreSectorForReadWrite(n_sector, n_sector, 1); //sector x of flashBankB=1//prepare first
    result8 += Chip_IAP_EraseSector(n_sector, n_sector, 1);//erase first sector!
}
 }

 __enable_irq();

 return result8;
}


0 Kudos

1,202 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by starblue on Fri Jun 12 04:15:22 MST 2015
In principle what you are doing sounds reasonable.

But there are a lot of things that can go wrong, and your description is not precise enough (far from it) to understand what is causing your problems.
0 Kudos

1,202 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pgeloso on Fri Jun 12 01:55:26 MST 2015
Yes,
but I'm in a special situation.

- I run M4 and then I release m0: everything works fine.
- Then I write sector 0 of FlashB using IAP (in LPCXpresso environment),  to upgrade the m0 firmware..but the m0 doesn't start anymore.
- I've tried to halt the m0 before the upgrade and also to "restart" it after the upgrade..but it's still dead.

I'm still not sure what's the correct procedure to let M4 upgrade the m0 firmware.
Any suggestions?

Thanks, bye!
0 Kudos

1,202 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by starblue on Fri Jun 12 01:32:28 MST 2015
The M0 is in reset state when the controller boots, the M4 has to remove the reset to let the M0 start.
0 Kudos

1,202 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by pgeloso on Fri Jun 12 01:25:40 MST 2015
Hi,
thank you for the answer.
Are you referring to putting m0 core into reset state, before the upgrade?
I use LPCXPresso and I found an interesting routine "haltSlave()" that manages RESET_CTRL1 register to place m0 into reset state.

..unfortunately it's still not working..

Any other suggestion?

Thanks
Pietro
0 Kudos

1,202 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by MikeSimmonds on Thu Jun 11 14:40:48 MST 2015
The M4 has to 'release' the M0 processor -- see your user manual.
0 Kudos