|
|
View previous topic :: View next topic |
Author |
Message |
pfournier
Joined: 30 Sep 2003 Posts: 89
|
Write_program_memory question |
Posted: Tue Jan 18, 2005 1:07 pm |
|
|
Here is the text from the manual about write program memory:
Quote: |
WRITE_PROGRAM_MEMORY()
Syntax:
write_program_memory( address, dataptr, count );
Parameters:
address is 16 bits on PCM parts and 32 bits on PCH parts
dataptr is a pointer to one or more bytes
count is a 8 bit integer
Returns: undefined
Function: Writes count bytes to program memory from dataptr to
address. This function is most effective when count is a
multiple of FLASH_WRITE_SIZE. Whenever this
function is about to write to a location that is a multiple
of FLASH_ERASE_SIZE then an erase is performed on
the whole block.
Availability: Only devices that allow writes to program memory.
Requires Nothing
Examples:
for(i=0x1000;i<=0x1fff;i++) {
value=read_adc();
write_program_memory(i, value, 2);
delay_ms(1000);
}
Example Files: loader.c
Also See: write_program_eeprom, erase_program_eeprom
|
The question comes up what if you write to addresses that are NOT multiples of FLASH_WRITE_SIZE. If I try and write 10 bytes somewhere in the middle, what happens?
-Pete _________________ -Pete |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Jan 18, 2005 5:48 pm |
|
|
Post an example program that shows what you want to do,
and we'll look at the assembly listing. Post your version
of the compiler and the PIC you're using. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Jan 19, 2005 2:11 am |
|
|
Quote: | The question comes up what if you write to addresses that are NOT multiples of FLASH_WRITE_SIZE. If I try and write 10 bytes somewhere in the middle, what happens? | My guess is that in that case you are responsible for erasing the data before writing. The function write_program_memory() will only perform an erase when the starting address is equal to a location that is a multiple of FLASH_ERASE_SIZE, in all other cases you are responsible for the flash memory being erased before.
Specific details of the flash memory depend on the processor type you are using. For example for the PIC18F458 there are the following hardware restrictions:
- You can only write to flash that has been erased before.
- Minimum erase size is 32 words (64 bytes)
- Minimum write size is 4 words (8 bytes)
Example, if you just want to change a single byte in 18F458-flash:
- first read a 32 bytes block from flash
- change the data in RAM
- erase the block in flash
- write 32 bytes to flash. |
|
|
Guest
|
|
Posted: Wed Jan 19, 2005 7:17 am |
|
|
Quote: | Post an example program that shows what you want to do,
and we'll look at the assembly listing. Post your version
of the compiler and the PIC you're using. |
I guess what I should have asked was "What does "Write_Program_Memory" actually do, what steps does it take?"
ckielstra wrote: | Quote: | The question comes up what if you write to addresses that are NOT multiples of FLASH_WRITE_SIZE. If I try and write 10 bytes somewhere in the middle, what happens? | My guess is that in that case you are responsible for erasing the data before writing. The function write_program_memory() will only perform an erase when the starting address is equal to a location that is a multiple of FLASH_ERASE_SIZE, in all other cases you are responsible for the flash memory being erased before.
Specific details of the flash memory depend on the processor type you are using. For example for the PIC18F458 there are the following hardware restrictions:
- You can only write to flash that has been erased before.
- Minimum erase size is 32 words (64 bytes)
- Minimum write size is 4 words (8 bytes)
Example, if you just want to change a single byte in 18F458-flash:
- first read a 32 bytes block from flash
- change the data in RAM
- erase the block in flash
- write 32 bytes to flash. |
Well here is where it gets interesting..... this is the code from CCS's loader.c
Code: |
if (line_type == 0)
{
// Loops through all of the data and stores it in data
// The last 2 bytes are the check sum, hence buffidx-3
for (i = 9,dataidx=0; i < buffidx-3; i += 2)
data[dataidx++]=atoi_b16(&buffer[i]);
#if getenv("FLASH_ERASE_SIZE")>2
#if defined(__PCM__)
if ((addr!=next_addr)&&(addr&(getenv("FLASH_ERASE_SIZE")-1)!=0))
#else
if ((addr!=next_addr)&&(addr&(getenv("FLASH_ERASE_SIZE")/2-1)!=0))
#endif
erase_program_eeprom(addr);
next_addr = addr + 1;
#endif
write_program_memory(addr, data, count);
}
|
Note that it does NOT do a READ-MODIFY-ERASE-WRITE sequence. Instead it does a WRITE without erase if at the start of a block, or a ERASE-WRITE otherwise. Yet the code seems to work. That is why I was wondering if something else was happening with this function or did CCS leave something out?
-Pete |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Jan 19, 2005 8:39 am |
|
|
Quote: | Yet the code seems to work. | The term 'seems to work' is a relative issue depending on the defined environment specifications. For example the above mentioned bootloader makes the assumption that the data in the hex-file is sorted with increasing address values. Try swapping two lines in your hex-file and this bootloader will corrupt your program because the second line (with lower address) will erase the previous loaded line. |
|
|
Haplo
Joined: 06 Sep 2003 Posts: 659 Location: Sydney, Australia
|
|
Posted: Wed Jan 19, 2005 3:59 pm |
|
|
This is a function I wrote a few months ago. It writes one byte to the flash. I have tested it on PIC18F452 and it works.
Code: |
//************************************************************
void W_P_Byte (int16 Addr,byte Value) //Write one byte to the FLASH
{
//This such a freakin' ordeal it is almost not worth it...
byte TempTbl[64];
int16 TempAddr;
byte Index;
Index=Addr & 0x3F; //Get the first 6 bits
TempAddr=Addr & 0xFFC0; //Ignore the first 6 bits
read_program_memory(TempAddr,TempTbl,64);
TempTbl[Index]=Value;
disable_interrupts(global);
erase_program_eeprom(TempAddr);
write_program_memory(TempAddr,TempTbl,64);
enable_interrupts(global);
}
|
|
|
|
Guest Guest
|
Slightly Better Code |
Posted: Tue Jul 05, 2005 4:28 pm |
|
|
I just recently got aggrevated by this little bug as well. I like the one byte solution, but it just is not a working replacement for write_program_memory so I submit this bit of code that completely replaces the write_program_memory. Feel free to clean-up/edit as you'd like.
Code: | ***********************************************************
*
* PROCEDURE NAME:
* working_write_program_memory
*
* DESCRIPTION:
* Actually performs the write_program_memory function
* correctly as specified in the manual.
*
***********************************************************/
void working_write_program_memory(uint32 addr,uint8 * dataptr, uint8 count)
{
uint32 true_address; // The address to read at.
sint16 i; // Current ammount of data written to disk.
uint8 flash_size; // How big a flash erase is.
uint8 offset; // Offset from the addr start as to where the location really is.
uint8 length; // How much data to write out.
uint32 bit_mask; // Mask to use for translating between flash sizes.
// Initialize variables.
flash_size = getenv("FLASH_ERASE_SIZE");
i = 0;
bit_mask = (flash_size - 1) ^ 0xFFFFFFFF;
// The actually starting location of the flash boundries.
true_address = addr & bit_mask;
// If these are not equal than the need to write out the head.
if ( true_address != addr)
{
offset = addr - true_address;
if (count < (flash_size - offset))
{
length = count;
}
else
{
length = flash_size - offset;
}
partial_write_program_memory(true_address, dataptr, offset, length);
// Set the i to the ammount written, increase the address pointer.
i = length;
true_address += flash_size;
}
// Write out the center section, write_program_memory should work ok.
while (i < count)
{
// need to make sure that interrupts are not processed when doing this.
disable_interrupts(global);
write_program_memory(true_address, dataptr + i, flash_size);
// enable the interrupts so that things can continue on their way.
enable_interrupts(global);
true_address += flash_size;
i+= flash_size;
}
// Write out the tail.
i -= flash_size;
if (i > 0)
{
partial_write_program_memory(true_address,dataptr+i,0,count-i);
}
}
/***********************************************************
*
* PROCEDURE NAME:
* partial_write_program_memory
*
* DESCRIPTION:
* Writes part of a partial chunk of data to the flash.
*
***********************************************************/
void partial_write_program_memory(uint32 addr,uint8 * dataptr, uint8 offset,uint8 datalength)
{
uint8 block[getenv("FLASH_ERASE_SIZE")]; // A block the size needed to erase memory
uint8 flash_size;
flash_size = getenv("FLASH_ERASE_SIZE");
read_program_memory(addr, block, flash_size);
memcpy(block+offset, dataptr, datalength);
// need to make sure that interrupts are not processed when doing this.
disable_interrupts(global);
write_program_memory(addr, block, flash_size);
// enable the interrupts so that things can continue on their way.
enable_interrupts(global);
} |
|
|
|
mrbmcg
Joined: 02 Jun 2005 Posts: 2
|
Many Thanks |
Posted: Thu Jul 07, 2005 7:52 am |
|
|
Just to thank guest for the above code. You are a life saver! |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Thu Jul 07, 2005 8:33 am |
|
|
Guest, will you put that in the code library. I would do it for you, but I didn't look at it, and don't realy understand the program memeory write.
And I wouldn't be able to support it.
But it sounds like its a good chunk of code. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|