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

PIC24 Program memory re-write issue

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



Joined: 17 Mar 2010
Posts: 4

View user's profile Send private message

PIC24 Program memory re-write issue
PostPosted: Wed Mar 17, 2010 3:50 pm     Reply with quote

I am using PCDIDE 4.097 and PIC24FJ64GA002.

I am reserving space within the program memory to store parameters and have been having an issue with re-writing to the program memory. It writes/reads correctly only the first time through. I've tried numerous options with no success. Can anyone help?

Code:

#include <24fj64ga002.h> 
#PIN_SELECT         U1TX = PIN_B5       // UART1 transmit
#PIN_SELECT         U1RX = PIN_B7       // UART1 receive
   
#include <stdlib.h>
#include <math.h>
#include <stdio.h>                 
                     
#fuses   NOPROTECT,WDT,HS,NODEBUG,NOWRT

#use delay(clock=11.0592M, oscillator=11.0592M)
#use rs232(UART1,BAUD=57600,parity=N,bits=8,ERRORS,stream=test)

typedef unsigned int8  uint8_t;
typedef   signed int8   int8_t;
typedef unsigned int16 uint16_t;
typedef   signed int16  int16_t;
typedef unsigned int32 uint32_t;
typedef   signed int32  int32_t;

//defines for internal flash memory
#define PROGRAM_MEMORY_SIZE      getenv("PROGRAM_MEMORY")

//so define the total amount of memory I want
#define FLASH_DATA_SIZE      12
//Define the end point of my block of flash (the very last byte of flash available)
#define FLASH_DATA_END      PROGRAM_MEMORY_SIZE-1
//Now define where the start of my data will be by subtracting the amount I want from the
//size of the memory
#define FLASH_DATA_START      (PROGRAM_MEMORY_SIZE - FLASH_DATA_SIZE)
#define OFFSET_FOR_NUMBER1    0
#define OFFSET_FOR_NUMBER2    4
#define OFFSET_FOR_NUMBER3    8

//Now tell the compiler to reserve this for me
#org FLASH_DATA_START, FLASH_DATA_END {}

int  writeToFlash(uint32_t location, char *buffer, uint16_t count);
int  readFromFlash(uint32_t location, char *buffer, uint16_t count);

/*********
 * Main
 *********/
void main(void) {
  uint8_t write_num = 0;
  uint8_t read_num = 0;
 
  printf("\r\nCompiled on %s at %s", __DATE__, __TIME__);
 
  setup_wdt(WDT_ON);
  setup_rtc(RTC_ENABLE, 0x00);
  enable_interrupts(int_rtc);
  enable_interrupts(INTR_GLOBAL);
 
  while(TRUE)
  {
     write_num++;
     restart_wdt(); // restart watchdog timer
     writeToFlash(FLASH_DATA_START + OFFSET_FOR_NUMBER1, &write_num, sizeof(write_num));
     delay_ms(500);
     ReadFromFlash(FLASH_DATA_START + OFFSET_FOR_NUMBER1, &read_num, sizeof(read_num));
     delay_ms(500);
     writeToFlash(FLASH_DATA_START + OFFSET_FOR_NUMBER2, &write_num, sizeof(write_num));
     delay_ms(500);
     ReadFromFlash(FLASH_DATA_START + OFFSET_FOR_NUMBER2, &read_num, sizeof(read_num));
     delay_ms(500);
     writeToFlash(FLASH_DATA_START + OFFSET_FOR_NUMBER3, &write_num, sizeof(write_num));
     delay_ms(500);
     ReadFromFlash(FLASH_DATA_START + OFFSET_FOR_NUMBER3, &read_num, sizeof(read_num));
     delay_ms(500);
  }
}

/*******************************************************************************
 * Writes buffer to flash for storage.  The flash on the PIC24 was designed to
 * hold 24bit instructions, and therefore converts every 4th byte to NULL
 * when being written to.  This function compensates for that to prevent data
 * loss/corruption.
 * @param buffer char pointer to the data to be written
 * @param count  int16 number of bytes to write to flash.
 * @returns number of bytes written to flash
 ******************************************************************************/
int writeToFlash(uint32_t location, char* buffer, uint16_t count)
{
   int16 write_count = 0;
   char write_buffer[640] = {0};
   int16 i = 0;
   
   if (location < FLASH_DATA_START || location > FLASH_DATA_END)
   {
      fprintf(test, "\r\nwriting to internal flash failed due to out of boundary check");
      return 0;
   }   
   disable_interrupts(INTR_GLOBAL);
   
   for(i = 0; i < count; i++)
   {
      /* skip every 4th byte starting with buffer[3] */
      if(write_count != 0 && ((write_count + 1) % 4 == 0))
      {
         write_count++;
      }
      write_buffer[write_count++] = buffer[i];
   }
   write_count++;
   if(write_count < 4)
   {
      write_count = 4;
   }
   
   write_program_memory(location, write_buffer, write_count);
   fprintf(test, "\r\nwriting %d bytes to flash", write_count);
   // Display write_buffer
   fprintf(test, "\r\nwrite_buffer: ");
   for(i = 0; i < write_count; i++)
      fprintf(test, "%X ", write_buffer[i]);
   fprintf(test, "\n\r");
   fprintf(test, "\n\r");
   enable_interrupts(INTR_GLOBAL);
   return write_count;
}

/*******************************************************************************
 * Reads from flash storage, skips every 4th byte to remove the NULL byte
 * written by the hardware when writing to the flash memory.
 * @param buffer char pointer for the data to be written into
 * @param count  int16 number of bytes to read from the flash.
 *               NOTE: This number is the number of bytes written to the flash
 *               INCLUDING the NULLs, not the number of bytes of data given
 *               to the writeToFlash call.
 * @returns number of bytes read without the NULL bytes.
 ******************************************************************************/
int readFromFlash(uint32_t location, char* buffer, uint16_t count)
{
   char read_buffer[640] = {0};
   int16 i = 0, j = 0;
   
   disable_interrupts(INTR_GLOBAL);     
     
   fprintf(test, "reading %d bytes from flash\r\n", count);
   read_program_memory(location, read_buffer, count);
   // Display read_buffer
   printf("read_buffer: ");
   for(i = 0; i < count; i++)
      printf("%X ", read_buffer[i]);
   printf("\n\r");
   printf("\n\r");
   for(i = 0; i < count; i++)
   {
      /* skip every 4th byte starting with 3 */
      if(i != 0 && ((i + 1) % 4 == 0))
      {
         continue;
      }
      buffer[j++] = read_buffer[i];
      delay_ms(1);
   }
   enable_interrupts(INTR_GLOBAL);
   return j;
}


Output:

Compiled on 17-Mar-10 at 17:19:29
writing 4 bytes to flash
write_buffer: 01 00 00 00

reading 1 bytes from flash
read_buffer: 01


writing 4 bytes to flash
write_buffer: 01 00 00 00

reading 1 bytes from flash
read_buffer: 01


writing 4 bytes to flash
write_buffer: 01 00 00 00

reading 1 bytes from flash
read_buffer: 01


writing 4 bytes to flash
write_buffer: 02 00 00 00

reading 1 bytes from flash
read_buffer: 00


writing 4 bytes to flash
write_buffer: 02 00 00 00

reading 1 bytes from flash
read_buffer: 00


writing 4 bytes to flash
write_buffer: 02 00 00 00

reading 1 bytes from flash
read_buffer: 00

.........
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Thu Mar 18, 2010 12:52 am     Reply with quote

Obviously, your code ignores the fact, that write_program_memory() only erases the flash, when the write
starts at a page boundary.

The PCD manual clarifies:
Quote:
In order to get the desired results while using write_program_memory(), the block of memory being written to needs to first be read in order to save any other variables currently stored there, then erased to clear all values in the block before the new values can be written. This is because the write_program_memory() function does not save any values in memory and will only erase the block if the first location is written to. If this process is not followed, when new values are written to the block, they will appear as garbage values.

Microchips AN1095 Emulating Data EEPROM for PIC18 and PIC24 shows a method to use PIC24 internal
flash for parameter storage effectively and without exhausting the memory early by frequent erase actions.
newby125



Joined: 17 Mar 2010
Posts: 4

View user's profile Send private message

PostPosted: Thu Mar 18, 2010 7:53 am     Reply with quote

Thanks for the info FvM.

In the end I only plan on writing my parameters when they are manually changed which won't be that often. Since I'm not overly concerned with exhausting the memory I would like to modify my existing functions to allow the reads/re-writes to work properly. I did read that an erase is performed on the whole block when the write is about to happen to a location that is a multiple of FLASH_ERASE_SIZE. Is there an easy way that I can lay out my parameters in memory so that they can be erased individually as separate blocks and all be multiples of FLASH_ERASE_SIZE?

Thanks...
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Thu Mar 18, 2010 12:19 pm     Reply with quote

Page size respectively FLASH_ERASE_SIZE of PIC24 is 0x800 Bytes. A resaonable method is to assign a memory structure
in RAM for your parameters and read and write it as a whole.
newby125



Joined: 17 Mar 2010
Posts: 4

View user's profile Send private message

PostPosted: Thu Mar 18, 2010 1:53 pm     Reply with quote

That sounds like a great idea. I'll give that a try.

Thanks again....
dtaulbee



Joined: 18 Jun 2008
Posts: 2

View user's profile Send private message

PostPosted: Thu Apr 28, 2011 2:45 pm     Reply with quote

Newby, did you ever solve this issue? I have a similar situation where I only need to write data a maximum of 5 or 10 times in the entire life of the product. I think using the #org directive and write_program_memory I can accomplish this, but I just haven't gotten it to work quite right yet. Your method was pretty elegant, so I thought I'd ask if you'd made progress. Thanks!
_________________
Everything should be made as simple as possible, but not simpler. -Albert Einstein
newby125



Joined: 17 Mar 2010
Posts: 4

View user's profile Send private message

PostPosted: Fri Apr 29, 2011 7:08 am     Reply with quote

It's been quite a while since I've looked at this code, but I believe my issue was with my memory location. I did get this working though and used the code in this topic as a template for my final implementation. Here is some code that may help:

Code:

#define WRITE_SIZE               getenv("FLASH_WRITE_SIZE")
#define BUFFER_START             0x9800 // closest location in available program memory (PROGRAM_MEMORY - FLASH_ERASE_SIZE)
                                        // which is a multiple of FLASH_ERASE_SIZE (to auto erase the page properly before writing)

//struct used to store parameters to internal program memory
struct{
   unsigned int32 parameter1;
   unsigned int32 parameter2;
   unsigned int32 parameter3;
   unsigned int32 parameter4;
   unsigned int32 parameter5;
   unsigned int32 parameter6;
   unsigned int32 parameter7;
   unsigned int32 parameter8;
   unsigned int32 parameter9;
   unsigned int32 parameter10;
   unsigned int32 parameter11;
   unsigned int32 parameter12;
   unsigned int32 parameter13;
   unsigned int32 parameter14;
   unsigned int16 parameter15;
}params;

//now use the following lines to write and read the parameters
write_program_memory(BUFFER_START, &params, WRITE_SIZE);  // save parameter struct to internal flash

read_program_memory(BUFFER_START, &params, WRITE_SIZE); // read all parameters into the parameter struct


Hope this helps. Let me know if you get it working and maybe a coding example of how you accomplished this.
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