CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Write_program_memory question

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
pfournier



Joined: 30 Sep 2003
Posts: 89

View user's profile Send private message

Write_program_memory question
PostPosted: Tue Jan 18, 2005 1:07 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jan 18, 2005 5:48 pm     Reply with 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.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed Jan 19, 2005 2:11 am     Reply with quote

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








PostPosted: Wed Jan 19, 2005 7:17 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Jan 19, 2005 8:39 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Jan 19, 2005 3:59 pm     Reply with quote

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
PostPosted: Tue Jul 05, 2005 4:28 pm     Reply with quote

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

View user's profile Send private message

Many Thanks
PostPosted: Thu Jul 07, 2005 7:52 am     Reply with quote

Just to thank guest for the above code. You are a life saver!
treitmey



Joined: 23 Jan 2004
Posts: 1094
Location: Appleton,WI USA

View user's profile Send private message Visit poster's website

PostPosted: Thu Jul 07, 2005 8:33 am     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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