Forums

IAP command query

Started by amb...@seatechnik.com August 2, 2006
Firstly can anyone point me in the right direction for a document which
gives decent details of exactly what the IAP functions actually do? I've
seen info which effectively gives an overview but it doesn't answer all
the questions...

For example: IAP command 50 prepares sectors for write and 51 copies ram
to flash.

Does this combination of commands allow you to do multiple updates to
flash without having to erase in between? for example if I write 512 bytes
each of value 0x55 (minimum size for IAP cmd 51) to the first 512 bytes in
sector 10 (address 0x30000) and then wish to change these values to 0xAA
with a subsequent write do I have to force an erase on the sector before I
can or is the IAP smart enough to do this for me while preserving the
remaining memory in that sector?

Having run a quick test of this it would appear it's not. In which case is
there some mechanism for updating a small section of a sector while
preserving the remaining contents of that sector?

Andy

An Engineer's Guide to the LPC2100 Series

--- In l..., amb@... wrote:
>
> Firstly can anyone point me in the right direction for a document which
> gives decent details of exactly what the IAP functions actually do? I've
> seen info which effectively gives an overview but it doesn't answer all
> the questions...
>
> For example: IAP command 50 prepares sectors for write and 51 copies ram
> to flash.
>
> Does this combination of commands allow you to do multiple updates to
> flash without having to erase in between? for example if I write 512
bytes
> each of value 0x55 (minimum size for IAP cmd 51) to the first 512
bytes in
> sector 10 (address 0x30000) and then wish to change these values to 0xAA
> with a subsequent write do I have to force an erase on the sector
before I
> can or is the IAP smart enough to do this for me while preserving the
> remaining memory in that sector?
>
> Having run a quick test of this it would appear it's not. In which
case is
> there some mechanism for updating a small section of a sector while
> preserving the remaining contents of that sector?
>
> Andy

Andy, Philips is using the term "prepare" to mean "unlock" in relation
to sector operations. So you still have to erase sectors before you
write arbitrary data.

In conventional flash memory systems, writing only turns ones to
zeroes. Thus you can overwrite the same location as many times as
you wish and you read always returns the 'and' result of all writes.

Philips flash is special in that it uses EDC on 16-byte blocks to
improve yield. So for practical purposes, you can only write in any
16-byte block once and you cannot do 'and' updates like conventional
flash memory.

Hope this helps.

Jaya
Hi,

and yes that's pretty much how I figured it worked - conventional flash
basically. Just seems a shame there's no capacity within the IAP commands
for buffering the contents of a large sector given some of them can be 64K
in size and there's no way of preserving residual data this way...

No matter for me really as it's only to save configuration settings in
anyway and won't be written to many times aside from commissioning and I
can read and physically buffer the settings before I overwrite any of
them.

Cheers anyway, just wanted to check I wasn't missing anything

Andy

> --- In l..., amb@... wrote:
>>
>> Firstly can anyone point me in the right direction for a document which
>> gives decent details of exactly what the IAP functions actually do? I've
>> seen info which effectively gives an overview but it doesn't answer all
>> the questions...
>>
>> For example: IAP command 50 prepares sectors for write and 51 copies ram
>> to flash.
>>
>> Does this combination of commands allow you to do multiple updates to
>> flash without having to erase in between? for example if I write 512
> bytes
>> each of value 0x55 (minimum size for IAP cmd 51) to the first 512
> bytes in
>> sector 10 (address 0x30000) and then wish to change these values to 0xAA
>> with a subsequent write do I have to force an erase on the sector
> before I
>> can or is the IAP smart enough to do this for me while preserving the
>> remaining memory in that sector?
>>
>> Having run a quick test of this it would appear it's not. In which
> case is
>> there some mechanism for updating a small section of a sector while
>> preserving the remaining contents of that sector?
>>
>> Andy
>
> Andy, Philips is using the term "prepare" to mean "unlock" in relation
> to sector operations. So you still have to erase sectors before you
> write arbitrary data.
>
> In conventional flash memory systems, writing only turns ones to
> zeroes. Thus you can overwrite the same location as many times as
> you wish and you read always returns the 'and' result of all writes.
>
> Philips flash is special in that it uses EDC on 16-byte blocks to
> improve yield. So for practical purposes, you can only write in any
> 16-byte block once and you cannot do 'and' updates like conventional
> flash memory.
>
> Hope this helps.
>
> Jaya
[CUT]

I've just finish one project based on LPC2106 and IAR Kickstart
Development Board.
In my design the last sector of the Flash (number 14) will be used
like a EEPROM.
Of course when you've to write into the Flash all the sector will be
erased the you've to save the Flash contents in a suitable buffer,
update the buffer with the new data and then write this into the
Flash.

All this stuff can be achieved by using the IAP command.

Well I'll post below the code to write and read the Flash.

I've found this one and make some slighty change to fit my needs.

File Flash_usage.c
******************************************
#include
#include
#include // Per macro relative
agli interrupt
#include "Flash_usage.h"

typedef struct SLayout {
int sectors;
int size;
} Layout;

static IAP iap_entry = (IAP)kIAPentry; // MCU flash firmware
interface function.
static unsigned long sectorbuf[WRITE_SIZE/4]; // The sector buffer
must be word aligned.
// The CPU clock speed (CCLK), the default value is used if no clock
option is found.
static int clock = CCLK;

//=============================================// 128k flash, 1'st generation
// LPC2104 (16k RAM)
// LPC2105 (32k RAM)
// LPC2106 (64k RAM)
// LPC2114 (16k RAM)
// LPC2212 (16k RAM)
// LPC2119 (16k RAM)
//=============================================#define FLASH_SIZE 0x1e000
#include

const Layout flashLayout[] {
{15, 8192},
{ 0, 0}
};

const int allowedWriteSizes[] {
512,
1024,
4096,
8192,
0
};

// ------------------------------
------
// Returns the flash sector number for a given flash address.
// Returns -1 if the address is outside the flash.
// ------------------------------
------
int CalculateSector(unsigned long addr, int *erase_sector)
{
int i;
int j;
int sector = 0;
unsigned long current = 0;

*erase_sector = 0;
for (i = 0; flashLayout[i].sectors; i++)
{
for (j = 0; j < flashLayout[i].sectors; j++)
{
if (addr < current + flashLayout[i].size)
{
if (addr < current + WRITE_SIZE)
{
*erase_sector = 1;
}
return sector;
}
sector++;
current += flashLayout[i].size;
}
}
return -1;
}

// ------------------------------
------
// Execute a flash firmware command.
// ------------------------------
------
int ExecuteCommand(unsigned long* cmd, unsigned long* status)
{
int ret;

for (;;)
{
iap_entry(cmd, status);
ret = status[0];
if (ret != STATUS_BUSY)
{
return ret;
}
// Try again if busy.
}
}

// ------------------------------
------
// Program a sector. The device allows fractions of a sector to be
written.
// dst - the flash address to start writing at.
// src - the address of the data buffer to be written.
// size - the number of bytes in the data buffer to write.
// ------------------------------
------
unsigned char ProgramFlash(unsigned long dst, unsigned long* src,
int size)
{
int i;
int ret;
int sector;
int erase_sector;
unsigned long sum;
unsigned long cmd[6];
unsigned long status[3];

// User Flash mode
MEMMAP = 1;

// Disabilita interrupt
__disable_interrupt();

// Round up size to nearest allowable write size.
for (i = 0; allowedWriteSizes[i]; i++)
{
if (size <= allowedWriteSizes[i])
{
size = allowedWriteSizes[i];
break;
}
}

sector = CalculateSector(dst, &erase_sector);

if (dst + size > FLASH_SIZE || sector == -1)
{
return(0);
}

// Check for first part of sector 0 and that a reset vector is
present,
// note that the buffer is initialized to all 1's.
if (sector == 0 && erase_sector && src[0] != 0xffffffff)
{
// Calculate exception vector 0x14 if the sector is zero and a
reset address is present.
sum = src[0] + src[1] + src[2] + src[3] +
src[4] + src[6] + src[7];
src[5] = -sum; // Vector 0x14.
}

// Prepare sector for erase.
cmd[0] = CMD_PREPARE_SECTORS;
cmd[1] = sector;
cmd[2] = sector;
ret = ExecuteCommand(cmd, status);

if (ret != STATUS_CMD_SUCCESS)
{
return(0);
}

if (erase_sector)
{
// Erase sector.
cmd[0] = CMD_ERASE_SECTORS;
cmd[1] = sector;
cmd[2] = sector;
cmd[3] = clock;
ret = ExecuteCommand(cmd, status);
if (ret != STATUS_CMD_SUCCESS)
{
return(0);
}
}

// Prepare sector for write.
cmd[0] = CMD_PREPARE_SECTORS;
cmd[1] = sector;
cmd[2] = sector;
ret = ExecuteCommand(cmd, status);
if (ret != STATUS_CMD_SUCCESS)
{
return(0);
}

// Program sector.
cmd[0] = CMD_COPY_RAM_TO_FLASH;
cmd[1] = dst;
cmd[2] = (unsigned long)src;
cmd[3] = size;
cmd[4] = clock;
ret = ExecuteCommand(cmd, status);

if (ret != STATUS_CMD_SUCCESS)
{
return(0);
}

// Abilita interrupt
__enable_interrupt();

// All was fine
return(1);
}

// ------------------------------
------
// Write one byte to flash at addr.
// The bytes are first buffered in sectorbuf, this array is
// cleared before take in it the byte to write.
// The sectorbuf is written to the flash when it overflows or when
// he user call the routine with byte equal to -1.
// ------------------------------
------
void FlashWriteByte(unsigned long addr, int byte)
{
int i;
int offset; // Current offset into sector
buffer.
static int bytes = 0; // Number of bytes in the
sector buffer (including gaps).
static int base_addr; // Pysical address of the
start of the sector.
unsigned long flashaddr = 0x1c000; // First address block 14
int flashByte = 0; // Variable for old Flash data

restart:
if (bytes == 0) // First byte of a new sector.
{
// This is the first time that we try to write some byte
// then we've to check for the total byte remainder
// before reach the maximum size, then the data storage
// buffer will be initialized.
bytes = addr % WRITE_SIZE;
base_addr = addr - bytes; // Calculate physical start address of
this sector.

// Intialize sector buffer with the pre-existent data to
// preserve all the remainder data which is stored in Flash.
for (i = 0; i < WRITE_SIZE/4; i++)
{
flashaddr += i;
flashByte = *((int*)flashaddr) & 0xFF;
sectorbuf[i] = flashByte; // Era 0xffffffff
}
}

// Write sector buffer to the flash memory if a flush is requested
(byte = -1)
// or the new byte address is beyond the sector buffer.
if (byte == -1 || addr - base_addr >= WRITE_SIZE)
{
ProgramFlash(base_addr, sectorbuf, bytes);

if (byte == -1)
{
return; // This was a flush operation, all data is written.
}

// We've write the data which is pushed into the storage
sectorbuf
// then we can reset the byte count for future writing
bytes = 0;

goto restart;
}

// Store byte in sector buffer.
offset = addr - base_addr;
((unsigned char*)sectorbuf)[offset] = byte;
bytes = offset + 1;

return;
}

****************************************************************

Then I've also add a template namely Flash_usage.h, below the code:

****************************************************************
#define CCLK 14746

// The write size is not critical to performance.
// 512 bytes is a good size that leaves as much room to the JTAG
// read buffer as possible and is supported by all flash devices.
#define WRITE_SIZE 512

#define kIAPentry 0x7ffffff1

enum {
CMD_PREPARE_SECTORS = 50,
CMD_COPY_RAM_TO_FLASH,
CMD_ERASE_SECTORS,
CMD_BLANK_CHECK_SECTORS,
CMD_READ_PART_ID,
CMD_READ_BOOT_CODE_VERSION,
CMD_COMPARE,
};

enum {
STATUS_CMD_SUCCESS = 0,
STATUS_INVALID_COMMAND,
STATUS_SRC_ADDR_ERROR,
STATUS_DST_ADDR_ERROR,
STATUS_SRC_ADDR_NOT_MAPPED,
STATUS_DST_ADDR_NOT_MAPPED,
STATUS_COUNT_ERROR,
STATUS_INVALID_SECTOR,
STATUS_SECTOR_NOT_BLANK,
STATUS_SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION,
STATUS_COMPARE_ERROR,
STATUS_BUSY,
};

typedef void (__thumb *IAP)(void*, void*);

// --------------------------
// Definizione delle funzioni
// --------------------------
int ExecuteCommand(unsigned long* , unsigned long* );
unsigned char ProgramFlash(unsigned long , unsigned long* , int );
void FlashWriteByte(unsigned long , int );

***************************************************************
That's all, here one example to write a read from Flash.
For write simply put your data and at last to write the updated
buffer use the -1 value, e.g.:

FlashWriteByte(address_to_write, byte_to_write);
FlashWriteByte(sector_base_address, -1);

Read the Flash is more simple than write, simply access it like a
RAM:

#define ADDR_TO_READ 0x1C000 // First address to read

FlashByteAddr = (unsigned long)ADDR_TO_READ;
FlashByte = *((int*)loaddr) & 0xFF; // & 0xFF I need just a byte

That's all, I'm also a newbie with this uP but this work very fine
for me.

Cheers
Fabio