LPC1225 IAP Erase Sector and Page Erase returns BUSY

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

LPC1225 IAP Erase Sector and Page Erase returns BUSY

2,050 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Sbriz on Fri Sep 21 04:04:59 MST 2012
Hi to everybody,

I'm new in this forum.
I'm working with a LPC1225/301 microcontroller. I've encountered this problem:

When I'm trying to execute the IAP ERASE SECTOR routine for a single sector, or for a number of sectors that not covers the entire microcontroller memory, I receive always the IAP staus code BUSY.(the PREPARE SECTOR routine instead returns always the CMD_SUCCES).

Otherwise if I execute the IAP ERASE SECTOR routine from start sector number 0 to end sector number 15 (the whole memory), it works properly!

I encounter the same behaviour also for the IAP ERASE PAGE routine, while I can correctly blanckcheck a single or more sectors.

My code runs in RAM, and the other IAP routines (COPY RAM TO FLASH, BLANK CHECK SECTOR, READ PART ID etc.) works correctly.

Is there anyone who encountered the same strange behaviour and could solve this issue?

Thanks in advance for your prompt reply.


  

 

Labels (1)
0 Kudos
15 Replies

1,541 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by tha on Thu Sep 12 18:43:28 MST 2013
No, this is present in all the parts.  For example, for the LPC1768:
- interrupt vector mapping in the UM 2.2
- criterion for valid user code, UM 32.3.1.1
- CRP, UM 32.6

That is why care should be taken if sector 0 is to be erase and reprogram
0 Kudos

1,541 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Rome Huang on Thu Sep 12 18:12:54 MST 2013
Thanks for the reply, but I didn't found the same issue in LPC1768, LPC1343, is this protection only in LPC122X?

BR,
Rome.
0 Kudos

1,541 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by tha on Thu Sep 12 16:32:01 MST 2013
Sector 0 contains a three important items which is crucial for the code to run correctly:
- The interrupt vector (UM 2.3)
- The checksum for valid code (UM 20.5.4)
- CRP value (UM 20.6)

This is why Daniel said: "You cannot erase the sector 0, without erasing everything"
0 Kudos

1,541 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Rome Huang on Wed Sep 11 20:55:47 MST 2013
Hello Daniel,

Regarding "You cannot erase the sector 0, without erasing everything", Please could you help point out where the document it located.
I also met erase chip successful, but erase sector 0 returns busy using IAP on LPC1227.

Thanks.

~Rome.
0 Kudos

1,541 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Daniel Widyanto on Sun Oct 28 20:03:51 MST 2012
Hi Sbriz,

As explained, I don't do one to one debugging for customers.

Also, as explained in the previous post, please add stack space for the return value.

The code below is not acceptable
<code>
.....
uint32_t result;
......
iap_entry (command,&result);
......
</code>
0 Kudos

1,541 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Sbriz on Mon Oct 15 00:14:41 MST 2012
Hi Daniel,

any news about my LPC1225 issue? Did you examine my kernel code?What do you think about it?

Thanks in advance for your help.

Best regards
0 Kudos

1,541 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Sbriz on Fri Oct 05 00:43:04 MST 2012
Hi Daniel,

The IAP block is accessed only once for every command I sent.

During my tests Sector Erase is the only command I sent, so there are not 
pending instructions that can put the IAP block in a busy state.

The kernel is loaded into SRAM and the parameters are the following:

kernel code start address: 0x10000000
kernel stack address: 0x10002000 (I also set 0x10001000 and the result was 
the same)
kernel data address: 0x10000900

I've sent to you the kernel code.
Best Regards


0 Kudos

1,541 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Daniel Widyanto on Tue Oct 02 22:09:19 MST 2012
Hi Sbriz,

Sorry, it's quite difficult for me to replicate the issue, unless you have smaller code to demonstrate the issue ?

Anyway, BUSY return value means that the IAP block is still busy with other request.

Since you are accessing the IAP through microkernel, I just wonder whether it's possible that you accidentally access the IAP block several times, within several threads. Also, since the last 32-bytes of the SRAM is used by IAP code, have you configure the kernel to not use it as general storage ?

0 Kudos

1,541 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Sbriz on Mon Oct 01 06:08:35 MST 2012
Hello Daniel,

I briefly explain you what exactly I'm doing with the LPC1225.

I'm designing a flash programming algorithm for our consolidated universal flash programmer.
Because of a particular request, the flash programming is done using the Serial Wire Debug (SWD) flash programming interface.

So what my algorithm does is:

-loading into the LPC1225 RAM a microkernel code. This microkernel implements the IAP driver.
-sending some custom commands that the microkernel recognized. At each custom command corresponds the call to a particular IAP routine, first in the way I indicate to you in my previous posts, then correcting the code basing on your driver (that means that I use an array of 4 elements for the result variable).

Everything works (Copy RAM to Flash, Prepare Sector for Write operations,Chip Erase,Blank check sector,Read Part ID)except for Sector Erase and Page Erase IAP routines.

The way in which the Sector Erase and Page Erase are called is the same of the Blank check Sector Routine.


So after this specification, in the following the answers to your questions:

-I've not changed the CRP value of the virgin microcontroller. I've read from the 0x000002FC location the value 0xFFFFFFFF. The SWD interface works correctly. I can program the flash using the SWD protocol. CRP1,CRP2,CRP3 are not enabled

-The core speed is 12 Mhz. I'm not using the SystemCoreClockUpdate(). I use this system configuration settings:

SYSMEMREMAP=0x02
MAINCLKSEL=0x00
MAINCLKUEN=0x01
SYSAHBCLKDIV=0x01
SYSAHBCLKCTRL=0x0000001F

-I've tried with different sectors, not only with the sector 0, but the result is always the same.


Any idea? Thanks in advance.


Best regards
















 


0 Kudos

1,541 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Daniel Widyanto on Sun Sep 30 23:17:49 MST 2012
Hello Sbriz,

The bootROM will use 4 bytes as return value. So, you cannot use single unsigned long as storage for return value. It may corrupt your stack or BSS area (eg. other non related global or static variables suddenly turn to 0x00 after IAP calling, or MCU is HardFault because jumping to address 0x00).

But since you are using my driver, my questions are:
- Which CRP that you are using ?
- What is the core speed when you are calling the IAP ? If you use SystemCoreClock variable, have you called SystemCoreClockUpdate() ?
- Which sector that you are trying to erase ? You cannot erase the sector 0, without erasing everything, regardless the CRP settings

Can you post the main() or the code part where you call the IAP driver ?
0 Kudos

1,541 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Sbriz on Fri Sep 28 03:46:58 MST 2012
Hi Daniel,

sorry, I was wrong with the code I posted to you.

I use iap_entry (command,&result) because I declare "result" as a single unsigned long variable, and not as an unsigned long array of 4 elements, as wrongly described in my previous post. So the function I used was correct.

However, to be sure, I tried also with the code you kindly posted in this tread, but the result is still a BUSY response from the microcontroller (result[0]=0x0B). As for my previous code, also with your code the Page Erase fails too, while the Sector BlankCheck (substantially the same procedure structure as Sector Erase except for Prepare Erase) works correctly.

The Sector Erase and Page Erase routine work only when the start address and end address covers the entire memory, that means that the microcontroller recognizes correctly the parameters and skips to the internal masserase routine, as described in the user's manual (page 309).

So my question is: could be something corrupted in this NXP embedded routines for some microcontrollers? (I tried also with another LPC1225 microcontroller, with the same mask, and the result was the same).



0 Kudos

1,541 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Daniel Widyanto on Thu Sep 27 19:48:00 MST 2012
For those who follow this thread. Here's simple IAP driver / IAP demo code that you can use in your project. Tested in LPC11xx, LPC11Cxx, LPC12xx.

Don't forget to update your linker file to not use the last 32-bytes of the SRAM for IAP !!

IAP_driver.h
<code>
/*
* Copyright (c) 2010, NXP Semiconductors N.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*   * Neither the name of the NXP Semiconductors N.V. nor the
*     names of its contributors may be used to endorse or promote products
*     derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND  CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED  WARRANTIES,  INCLUDING,  BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF  MERCHANTABILITY  AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED.  IN NO EVENT SHALL NXP Semiconductors N.V. BE LIABLE FOR ANY
* DIRECT, INDIRECT,  INCIDENTAL,  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY  THEORY  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR  OTHERWISE)  ARISING  IN  ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*
* iap_driver.h
* Demonstrate basic capability of In-Application Programming feature
*
* by: Daniel Widyanto <daniel.widyanto@nxp.com>
*/

#ifndef IAP_DRIVER_H_
#define IAP_DRIVER_H_

/*
* IAP status codes
*/
typedef enum {
CMD_SUCCESS = 0,
INVALID_COMMAND,
SRC_ADDR_ERROR,
DST_ADDR_ERROR,
SRC_ADDR_NOT_MAPPED,
DST_ADDR_NOT_MAPPED,
COUNT_ERROR,
INVALID_SECTOR,
SECTOR_NOT_BLANK,
SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION,
COMPARE_ERROR,
BUSY,
} __e_iap_status;

/**
* Init IAP driver
* @return0 for success
*/
int iap_init(void);

/**
* Erase flash sector(s)
*
* @param sector_start  The start of the sector to be erased
* @param sector_end    The end of the sector to be erased
*
* @return CMD_SUCCESS, BUSY, SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION,
*         or INVALID_SECTOR
*/
int iap_erase_sector(unsigned int sector_start, unsigned int sector_end);

/**
* Prepare flash sector(s) for erase / writing
*
* @param sector_start  The start of the sector to be prepared
* @param sector_end    The end of the sector to be prepared
*
* @return CMD_SUCCESS, BUSY, or INVALID_SECTOR
*/
int iap_prepare_sector(unsigned int sector_start, unsigned int sector_end);

/**
* Copy RAM contents into flash
*
* @param ram_address    RAM address to be copied
*                       It should be in word boundary
* @param flash_address  Flash address where the contents are to be copied
*                       It should be within 256bytes boundary
* @param count          Number of data to be copied (in bytes)
*                       The options: 256, 512, 1024, 4096
*
* @return CMD_SUCCESS, BUSY, or INVALID_SECTOR
*/
int iap_copy_ram_to_flash(void* ram_address, void* flash_address,
unsigned int count);

#endif /* IAP_DRIVER_H_ */
</code>

IAP_driver.c
<code>
/*
* Copyright (c) 2010, NXP Semiconductors N.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*   * Neither the name of the NXP Semiconductors N.V. nor the
*     names of its contributors may be used to endorse or promote products
*     derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND  CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED  WARRANTIES,  INCLUDING,  BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF  MERCHANTABILITY  AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED.  IN NO EVENT SHALL NXP Semiconductors N.V. BE LIABLE FOR ANY
* DIRECT, INDIRECT,  INCIDENTAL,  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY  THEORY  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR  OTHERWISE)  ARISING  IN  ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*
* iap_driver.c
* Demonstrate basic capability of In-Application Programming feature
*
* by: Daniel Widyanto <daniel.widyanto@nxp.com>
*/

#include <LPC122x.h>
#include "iap_driver.h"

/*
* The IAP funtion address in LPC11xx ROM
*/
#define IAP_ADDRESS0x1FFF1FF1

/*
* Command codes for IAP
*/
#define PREPARE_SECTOR50
#define COPY_RAM_TO_FLASH51
#define ERASE_SECTOR52
#define BLANK_CHECK_SECTOR53
#define READ_PART_ID54
#define READ_BOOT_CODE_REV55
#define COMPARE56
#define REINVOKE_ISP57
#define READ_UID58

typedef unsigned int (*IAP)(unsigned int[], unsigned int[]);
static const IAP iap_entry = (IAP) IAP_ADDRESS;

/*---------------------------------------------------------------------------
* Public functions
*/

/**
* Init IAP driver
* @return0 for success
*/
int iap_init(void) {
/* Need to update 'SystemCoreClock' according to the current clock settings
* It's needed as IAP parameter
*/
SystemCoreClockUpdate();
return 0;
}

/**
* Erase flash sector(s)
*
* @param sector_start  The start of the sector to be erased
* @param sector_end    The end of the sector to be erased
*
* @return CMD_SUCCESS, BUSY, SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION,
*         or INVALID_SECTOR
*/
int iap_erase_sector(unsigned int sector_start, unsigned int sector_end) {
unsigned int command[5];
unsigned int result[4];

command[0] = ERASE_SECTOR;
command[1] = (unsigned int) sector_start;
command[2] = (unsigned int) sector_end;
command[3] = SystemCoreClock / 1000;
iap_entry(command, result);

return (int) result[0];
}

/**
* Prepare flash sector(s) for erase / writing
*
* @param sector_start  The start of the sector to be prepared
* @param sector_end    The end of the sector to be prepared
*
* @return CMD_SUCCESS, BUSY, or INVALID_SECTOR
*/
int iap_prepare_sector(unsigned int sector_start, unsigned int sector_end) {
unsigned int command[5];
unsigned int result[4];

command[0] = PREPARE_SECTOR;
command[1] = (unsigned int) sector_start;
command[2] = (unsigned int) sector_end;
iap_entry(command, result);

return (int) result[0];
}

/**
* Copy RAM contents into flash
*
* @param ram_address    RAM address to be copied
*                       It should be in word boundary
* @param flash_address  Flash address where the contents are to be copied
*                       It should be within 256bytes boundary
* @param count          Number of data to be copied (in bytes)
*                       The options: 256, 512, 1024, 4096
*
* @return CMD_SUCCESS, BUSY, or INVALID_SECTOR
*/
int iap_copy_ram_to_flash(void* ram_address, void* flash_address,
unsigned int count) {
unsigned int command[5];
unsigned int result[4];

command[0] = COPY_RAM_TO_FLASH;
command[1] = (unsigned int) flash_address;
command[2] = (unsigned int) ram_address;
command[3] = count;
command[4] = SystemCoreClock / 1000;
iap_entry(command, result);

return (int) result[0];
}
</code>

Simple code to test the IAP_driver
<code>
/*
* Copyright (c) 2010, NXP Semiconductors N.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*   * Neither the name of the NXP Semiconductors N.V. nor the
*     names of its contributors may be used to endorse or promote products
*     derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND  CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED  WARRANTIES,  INCLUDING,  BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF  MERCHANTABILITY  AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED.  IN NO EVENT SHALL NXP Semiconductors N.V. BE LIABLE FOR ANY
* DIRECT, INDIRECT,  INCIDENTAL,  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY  THEORY  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR  OTHERWISE)  ARISING  IN  ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <LPC122x.h>
#include <cr_section_macros.h>
#include <NXP/crp.h>

#include "iap_driver.h"

// Variable to store CRP value in. Will be placed automatically
// by the linker when "Enable Code Read Protect" selected.
// See crp.h header for more information
__CRP const unsigned int CRP_WORD = CRP_NO_CRP ;

/* Flash offset where the configuration is stored */
#define CONFIG_FLASH_OFFSET0x1000
#define CONFIG_FLASH_SECTOR(CONFIG_FLASH_OFFSET >> 12)
#define CONFIG_FLASH_SECTOR_SIZE1

static uint8_t demo_messg[] = "Greetings from IAP";

int main(void) {
__e_iap_status iap_status;

/* Init the IAP driver */
iap_init();

/* Prepare the sector for erase */
iap_status = (__e_iap_status) iap_prepare_sector(CONFIG_FLASH_SECTOR,
(CONFIG_FLASH_SECTOR + CONFIG_FLASH_SECTOR_SIZE));
if (iap_status != CMD_SUCCESS) while(1);

/* Erase the sector */
iap_status = (__e_iap_status) iap_erase_sector(CONFIG_FLASH_SECTOR,
(CONFIG_FLASH_SECTOR + CONFIG_FLASH_SECTOR_SIZE));
if (iap_status != CMD_SUCCESS) while(1);

/* Prepare the sector for writing */
iap_status = (__e_iap_status) iap_prepare_sector(CONFIG_FLASH_SECTOR,
(CONFIG_FLASH_SECTOR + CONFIG_FLASH_SECTOR_SIZE));
if (iap_status != CMD_SUCCESS) while(1);

/* write data to flash */
iap_status = (__e_iap_status) iap_copy_ram_to_flash(&demo_messg,
(void *)CONFIG_FLASH_OFFSET, 256);
if (iap_status != CMD_SUCCESS) while(1);

while(1);
return 0 ;
}
</code>
0 Kudos

1,541 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Daniel Widyanto on Thu Sep 27 19:41:00 MST 2012
Hi Sbriz,

The iap_entry needs pointer to the buffer, not pointer to the pointer of the buffer. Refer to <code>iap_entry (command,&result); </code>

I think the result is ok, but since it is stored into the pointer of the pointer of 'result', then you read the wrong value.

It should be <code>iap_entry (command, result); </code>
0 Kudos

1,541 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Sbriz on Thu Sep 27 00:53:43 MST 2012
Hi Daniel,

thanks for your reply. I pass the parameters as follows:

I define the IAP location entry point.
#define IAP_LOCATION 0x1fff1ff1

Then I define data structure to pass IAP command and result to the IAP
function:
unsigned long command[5];
unsigned long result[4];

I define pointer to function type:
typedef void (*IAP)(unsigned int [],unsigned int[]);
IAP iap_entry;

I set the function pointer:
iap_entry=(IAP) IAP_LOCATION;

Then I call the sector erase IAP procedure as follows :

command[0] = 50;                            // Prepare Sector for Erase
command[1] = start_num_sect;                      // Start Sector
command[2] = end_num_sect;                      // End Sector
iap_entry (command,&result);                // Execute IAP Command

if (result)
return (PREPARE_SECTOR_ERR); // Command Failed


command[0] = 52;                            // Erase Sector
command[1] = start_num_sect;                      // Start Sector
command[2] = end_num_sect;          // End Sector
command[3] = clk_khz;                       // CCLK in kHz

iap_entry (command,&result);                // Execute IAP Command


Note that the routine is the same I use as for the sector blankcheck (command 53), and in that case it works correctly!Any idea about why the sector/page erase routine returns busy? I tried also to disable interrupts using the following in line assembly function

static inline void __disable_irq(void) { __asm volatile ("cpsid i"); };

but the result was always the same.  



0 Kudos

1,541 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Daniel Widyanto on Thu Sep 27 00:33:00 MST 2012
Hi Sbriz,

So, how do you pass the parameters ? What are the parameters that you passed to the IAP ?

Regards,
-daniel
0 Kudos