flash_example.c - Illustrates run time self programming of the flash memoryΒΆ

 
#include "pic24_all.h"
#include <stdio.h>

#if (defined(__PIC24F__) || defined(__PIC24E__) || defined(__dsPIC33E__))
# warning "For all PIC24F and some PIC24E/dsPIC33E family members, the DATA_FLASH_PAGE is set to the second to last flash page instead of the last page,"
# warning "as the last flash page in the 24F family contains the configuration bits."
#endif


#if defined(__PIC24HJ64GP502__) || defined(__PIC24FJ64GA002__)
# define LAST_IMPLEMENTED_PMEM 0x00ABFF
#elif defined(__PIC24HJ32GP202__) || defined(__PIC24FJ32GA002__) || defined(__dsPIC33FJ32GP202__)
# define LAST_IMPLEMENTED_PMEM 0x0057FF
#elif defined(__dsPIC33FJ128GP802__)
# define LAST_IMPLEMENTED_PMEM 0x0157FF
#elif defined(__PIC24EP64GP202__)               // test PIC24E device
# define LAST_IMPLEMENTED_PMEM 0x00AFFF
#elif defined(__dsPIC33EP64GP502__) || defined(__dsPIC33EP64GP503__) || defined(__dsPIC33EP64GP504__) || defined(__dsPIC33EP64GP506__)
# define LAST_IMPLEMENTED_PMEM 0x00AFFF
#elif defined(__dsPIC33EP128GP502__) || defined(__dsPIC33EP128GP504__) || defined(__dsPIC33EP128GP506__)
# define LAST_IMPLEMENTED_PMEM 0x0157FF
#elif defined(__dsPIC33EP256GP502__) || defined(__dsPIC33EP256GP504__) || defined(__dsPIC33EP256GP506__)
# define LAST_IMPLEMENTED_PMEM 0x02AFFF
#elif defined(__dsPIC33EP512GP502__) || defined(__dsPIC33EP512GP504__) || defined(__dsPIC33EP512GP506__)
# define LAST_IMPLEMENTED_PMEM 0x0557FF
#else
# error "Define LAST_IMPLEMENTED_PMEM for your processor!"
#endif

//calculate starting address of a flash page to store data
#if (defined(__PIC24F__) || defined(__PIC24E__) || defined(__dsPIC33E__))
# define DATA_FLASH_PAGE (((LAST_IMPLEMENTED_PMEM/FLASH_PAGESIZE)*FLASH_PAGESIZE)-FLASH_PAGESIZE)  //2nd to last page of flash
#endif
#if (defined(__PIC24H__) || defined(__dsPIC33F__))
# define DATA_FLASH_PAGE ((LAST_IMPLEMENTED_PMEM/FLASH_PAGESIZE)*FLASH_PAGESIZE)  //last page of flash
#endif



#define RECORD_SIZE 15      //arbitrarily chosen
#define NUM_RECORDS 8       //arbitrarily chosen
#define FREE_STATUS 0xA5    //arbitrarily chosen, different from USED_STATUS
#define USED_STATUS 0x5A    //arbitrarily chosen, different from FREE_STATUS

typedef struct _REC {   //one record
  uint8_t status;            //indicates if free or used
  char  data[RECORD_SIZE]; //holds the data
} REC;

#define NUM_ROWS (((NUM_RECORDS*sizeof(REC))/FLASH_ROWBYTES) + 1)
#define FLASH_DATA_SIZE (NUM_ROWS*FLASH_ROWBYTES)

typedef union _UFDATA {
  REC  records[NUM_RECORDS];
  char fill[FLASH_DATA_SIZE];  //worst case allocates extra row, but ensures RAM data block is multiple of row size
} UFDATA;

UFDATA fdata __attribute__ ((aligned(4)));

void doFormat(UFDATA* p_ufdata) {
  uint16_t u16_i;
  for (u16_i = 0; u16_i < NUM_RECORDS; u16_i++) {
    p_ufdata->records[u16_i].status = FREE_STATUS;
  }
}

void doCommit(UFDATA* p_ufdata) {
  union32 u_memaddr;
  u_memaddr.u32 = DATA_FLASH_PAGE;
  doWritePageFlash(u_memaddr, (uint8_t *) p_ufdata, FLASH_DATA_SIZE);
}

void doRead(UFDATA* p_ufdata) {
  union32 u_memaddr;
  u_memaddr.u32 = DATA_FLASH_PAGE;
  doReadPageFlash(u_memaddr, (uint8_t *) p_ufdata, FLASH_DATA_SIZE);
}

void doDelete(uint16_t u16_recnum) {
  fdata.records[u16_recnum].status = FREE_STATUS;
}

void doPrint(UFDATA* p_ufdata) {
  uint16_t u16_i;
  for (u16_i = 0; u16_i < NUM_RECORDS; u16_i++) {
    printf("%d: %s, Data: %s\n",
           u16_i, (p_ufdata->records[u16_i].status == FREE_STATUS ? "Free" : "Used"),
           (p_ufdata->records[u16_i].status == FREE_STATUS ? "n/a" : p_ufdata->records[u16_i].data));
  }
}

void doInsert(UFDATA* p_ufdata, char* sz_1) {
  uint16_t u16_i, u16_j;
  for (u16_i = 0; u16_i < NUM_RECORDS; u16_i++) {
    if (p_ufdata->records[u16_i].status == FREE_STATUS) {
      u16_j = 0;
      while (*sz_1) {  //copy data
        p_ufdata->records[u16_i].data[u16_j] = *sz_1;
        sz_1++;
        u16_j++;
      } //end while
      p_ufdata->records[u16_i].data[u16_j] = *sz_1; //write null
      p_ufdata->records[u16_i].status = USED_STATUS; //mark as used
      break; //exit if
    }//end if
  }//end for
}//end function

uint8_t printMenu() {
  printf("1 Format data\n");
  printf("2 Enter one record\n");
  printf("3 Delete a record\n");
  printf("4 Commit data\n");
  printf("5 Read and print all records\n");
  printf(" Enter number (1-5): ");
  return inCharEcho();
}

void doMenu() {
  uint8_t u8_c;
  char data[RECORD_SIZE];
  uint16_t u16_recnum;
  u8_c = printMenu();
  printf("\n");
  switch(u8_c) {
    case '1':
      doFormat(&fdata);
      break;
    case '2':
      printf("Enter string+\\n (14 chars max): ");
      inStringEcho(data,RECORD_SIZE-1);
      doInsert(&fdata, data);
      break;
    case '3':
      printf("Enter record number+\\n (0 to 15, decimal): ");
      inStringEcho(data,RECORD_SIZE-1);
      sscanf(data,"%d", (int *) &u16_recnum);
      doDelete(u16_recnum);
      break;
    case '4':
      doCommit(&fdata);
      break;
    case '5':
      doRead(&fdata);
      doPrint(&fdata);
      break;
  }
}

int main (void) {
  configBasic(HELLO_MSG);
  while(1) {
    doMenu(1);
  } //end while
}//end main