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 |
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; } |
//***************************************************************************** // +--+ // | ++----+ // +-++ | // | | // +-+--+ | // | +--+--+ // +----+ 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); } } |
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; } |