IAP help

Started by groeselt April 15, 2008
Hi,

I want to use IAP on a lpc2148 to store some variables, which are
needed when the system restarts.

I found several examples of IAP, but non are working, I think so.
I'm using IAR embedded workbench. I can view the memory, but where I
write my data it is not changing.

The code I use:

struct iap_in {
unsigned int cmd;
unsigned int par[4];
};

typedef void (*IAP)(struct iap_in *in, unsigned int *result);
#define iap_entry ((IAP) 0x7FFFFFF1) // IAP entry point

/*
* Convert 'addr' to sector number
*/
unsigned int get_secnum (void *addr) {
unsigned int n;

n = ((unsigned int) addr >> 13) & 0x1F; // pseudo sector
number

if (n >= (0x30000 >> 13)) {
n -= 14; // high small 8kB
Sectors (
}
else if (n >= (0x10000 >> 13)) {
n = 7 + (n >> 3); // large 64kB Sectors
}
return (n); // sector number
}

/*
* Erase Sector between 'start' and 'end'
* Return: IAP error code (0 when OK)
* NOTES: start needs to be a 256 byte boundary
* size should be 256, 512, 1024 or 4089
*/
unsigned int erase (void* start, void* end) {
struct iap_in iap; // IAP input parameters
unsigned int result[16]; // IAP results
unsigned int save_VicInt; // for saving of interrupt
enable register

save_VicInt = VICIntEnable; // save interrupt enable
status
VICIntEnClear = 0xFFFFFFFF; // disable all interrupts

#ifdef BYPASS_IAP
Init_PLL(0); // IAP requires to run
without PLL
#endif

iap.cmd = 50; // IAP Command: Prepare
Sectors for Write
iap.par[0] = get_secnum (start); // start sector
iap.par[1] = get_secnum (end); // end sector
iap_entry (&iap, result); // call IAP function
if (result[0]) goto exit; // an error occured?

iap.cmd = 52; // IAP command: Erase Flash
iap.par[0] = get_secnum (start); // start sector
iap.par[1] = get_secnum (end); // end sector
iap.par[2] = 12000; // CPU clock
iap_entry (&iap, result); // call IAP function

exit:

#ifdef BYPASS_IAP
Init_PLL(1); // start PLL
#endif

VICIntEnable = save_VicInt; // enable interrupts
return (result[0]);
}
/*
* Program *data to flash_addr. number of bytes specified by size
* Return: IAP error code (0 when OK)
* Note:
*/
unsigned int program (void *flash_addr, void *data, unsigned long
size) {
struct iap_in iap; // IAP input parameters
unsigned int result[16]; // IAP results
unsigned int save_VicInt; // for saving of interrupt
enable register

save_VicInt = VICIntEnable; // save interrupt enable
status
VICIntEnClear = 0xFFFFFFFF; // disable all interrupts

#ifdef BYPASS_IAP
Init_PLL(0); // IAP requires to run
without PLL
#endif

iap.cmd = 50; // IAP Command: Prepare
Sectors for Write
iap.par[0] = get_secnum (flash_addr); // start sector
iap.par[1] = iap.par[0]; // end Sektor
iap_entry (&iap, result); // call IAP function
if (result[0]) goto exit; // an error occured?
iap.cmd = 51; // IAP Command: Copy RAM
to Flash
iap.par[0] = (unsigned int) flash_addr; // destination-addr
iap.par[1] = (unsigned int) data; // source-addr
iap.par[2] = size; // number of bytes
iap.par[3] = 12000; // CPU clock
iap_entry (&iap, result); // call IAP function

exit:

#ifdef BYPASS_IAP
Init_PLL(1); // start PLL
#endif

VICIntEnable = save_VicInt; // enable interrupts
return (result[0]);
}

And then at the beginning of the main:

unsigned char vals[512];

void main(void) {

for (int i = 0; i < sizeof(vals); i++) {
vals[i] = i;
}

program((void*)0x00030000, vals, sizeof(vals));

while (1);
}

I hope someone can point me in the good direction. And there is no
option to use external memory. It has to be put somewhere in the
flash.

Thanks

Maurice

An Engineer's Guide to the LPC2100 Series

Hello,

I think you have to erase the whole sector before to write a block. And
after that you cannot make a 0 belongs a 1 if you don't erase the sector
first.

Cheers,

Daniel.

_____

De: l... [mailto:l...] En nombre de
groeselt
Enviado el: martes, 15 de abril de 2008 11:22
Para: l...
Asunto: [lpc2000] IAP help

Hi,

I want to use IAP on a lpc2148 to store some variables, which are
needed when the system restarts.

I found several examples of IAP, but non are working, I think so.
I'm using IAR embedded workbench. I can view the memory, but where I
write my data it is not changing.

The code I use:

struct iap_in {
unsigned int cmd;
unsigned int par[4];
};

typedef void (*IAP)(struct iap_in *in, unsigned int *result);
#define iap_entry ((IAP) 0x7FFFFFF1) // IAP entry point

/*
* Convert 'addr' to sector number
*/
unsigned int get_secnum (void *addr) {
unsigned int n;

n = ((unsigned int) addr >> 13) & 0x1F; // pseudo sector
number

if (n >= (0x30000 >> 13)) {
n -= 14; // high small 8kB
Sectors (
}
else if (n >= (0x10000 >> 13)) {
n = 7 + (n >> 3); // large 64kB Sectors
}
return (n); // sector number
}

/*
* Erase Sector between 'start' and 'end'
* Return: IAP error code (0 when OK)
* NOTES: start needs to be a 256 byte boundary
* size should be 256, 512, 1024 or 4089
*/
unsigned int erase (void* start, void* end) {
struct iap_in iap; // IAP input parameters
unsigned int result[16]; // IAP results
unsigned int save_VicInt; // for saving of interrupt
enable register

save_VicInt = VICIntEnable; // save interrupt enable
status
VICIntEnClear = 0xFFFFFFFF; // disable all interrupts

#ifdef BYPASS_IAP
Init_PLL(0); // IAP requires to run
without PLL
#endif

iap.cmd = 50; // IAP Command: Prepare
Sectors for Write
iap.par[0] = get_secnum (start); // start sector
iap.par[1] = get_secnum (end); // end sector
iap_entry (&iap, result); // call IAP function
if (result[0]) goto exit; // an error occured?

iap.cmd = 52; // IAP command: Erase Flash
iap.par[0] = get_secnum (start); // start sector
iap.par[1] = get_secnum (end); // end sector
iap.par[2] = 12000; // CPU clock
iap_entry (&iap, result); // call IAP function

exit:

#ifdef BYPASS_IAP
Init_PLL(1); // start PLL
#endif

VICIntEnable = save_VicInt; // enable interrupts
return (result[0]);
}

/*
* Program *data to flash_addr. number of bytes specified by size
* Return: IAP error code (0 when OK)
* Note:
*/
unsigned int program (void *flash_addr, void *data, unsigned long
size) {
struct iap_in iap; // IAP input parameters
unsigned int result[16]; // IAP results
unsigned int save_VicInt; // for saving of interrupt
enable register

save_VicInt = VICIntEnable; // save interrupt enable
status
VICIntEnClear = 0xFFFFFFFF; // disable all interrupts

#ifdef BYPASS_IAP
Init_PLL(0); // IAP requires to run
without PLL
#endif

iap.cmd = 50; // IAP Command: Prepare
Sectors for Write
iap.par[0] = get_secnum (flash_addr); // start sector
iap.par[1] = iap.par[0]; // end Sektor
iap_entry (&iap, result); // call IAP function
if (result[0]) goto exit; // an error occured?

iap.cmd = 51; // IAP Command: Copy RAM
to Flash
iap.par[0] = (unsigned int) flash_addr; // destination-addr
iap.par[1] = (unsigned int) data; // source-addr
iap.par[2] = size; // number of bytes
iap.par[3] = 12000; // CPU clock
iap_entry (&iap, result); // call IAP function

exit:

#ifdef BYPASS_IAP
Init_PLL(1); // start PLL
#endif

VICIntEnable = save_VicInt; // enable interrupts
return (result[0]);
}

And then at the beginning of the main:

unsigned char vals[512];

void main(void) {

for (int i = 0; i < sizeof(vals); i++) {
vals[i] = i;
}

program((void*)0x00030000, vals, sizeof(vals));

while (1);
}

I hope someone can point me in the good direction. And there is no
option to use external memory. It has to be put somewhere in the
flash.

Thanks

Maurice


--- In l..., "Daniel Rio"
wrote:
>
> Hello,
>
>
>
> I think you have to erase the whole sector before to write a block.
And
> after that you cannot make a 0 belongs a 1 if you don't erase the
sector
> first.
>
>
>
> Cheers,
>
>
>
> Daniel.
>
>
>
> _____
Thank you for your reply. It worked.
Too bad it wasn't in the example I got.
Thanks.

Maurice