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

Saving and Recovering data from flash

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
BotBill



Joined: 18 Jul 2007
Posts: 1
Location: UK

View user's profile Send private message

Saving and Recovering data from flash
PostPosted: Wed Jul 18, 2007 7:18 am     Reply with quote

Code:

/*
This is an example of how to save and recover various data types to and from FLASH
It should work on most PIC18 devices that allow writing and reading from flash
This can be very usefull to store variables in non-volatile memory

The example works with arrays of various data types including arrays of pointers
The programe will start by reading whatever might be in flash,
then it prints the result before generating new data, saving to flash and then recovering it.

At each point it prints the data for you over the serial port
*/


#include <18F4680.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES H4                       //High speed osc with HW enabled 4X PLL
#FUSES NOPROTECT                //Code not protected from reading
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES BORV21                   //Brownout reset at 2.1V
#FUSES PUT                      //Power Up Timer
#FUSES NOCPD                    //No EE protection
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES LVP                      //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES IESO                     //Internal External Switch Over mode enabled
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES PBADEN                   //PORTB pins are configured as analog input channels on RESET
#FUSES BBSIZ4K                  //4K words Boot Block size
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOEBTRB                  //Boot block not protected from table reads
#FUSES NOCPB                    //No Boot Block code protection
#FUSES LPT1OSC                  //Timer1 configured for low-power operation
#FUSES MCLR                     //Master Clear pin enabled
#FUSES NOXINST                    //Extended set extension and Indexed Addressing mode enabled

#use delay(clock=32000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)


//this gets the total size of the program memory from the compiler
#define PROGRAM_MEMORY_SIZE      getenv("PROGRAM_MEMORY")

/*
Programe data in flash starts at the bottom and fills upwards
I'm assuming that my code will not use up more than 50% of the flash
which is 64k for this PIC so I want to reserve the TOP 50% of flash for my own use
*/
//so define the total amount of memory I want
#define FLASH_DATA_SIZE      32767
//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)


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

/*
Next I'm declaring some global variable arrays that I will be using to store date
I will then show how to copy the contents of this to flash and recover it
I have four types of array, each with 32 elements
There are two arrays of 16 bit variables, one for data and the other for pointers
and two int8 arrays, again one for data and the other for pointers
REMEMBER! int8 pointers actually use TWO bytes of memory - this will be important
when it comes to saving the data to flash

Its useful to remember that when you declare global variables like this that they
are then arranged in memory in the order that you declare them.
The actual functions to copy blocks of data to and from flash work directly with bytes
in RAM and don't care about datatypes - all they do is copy the number of bytes you
have specified from wherever in RAM you have told it to start, to wherever in flash
you want it to go.

When it comes to copying the array of int16's to flash we know that all the elements in RAM
are arranges sequentially BUT although there are 32 elements in the array there are actually
64 bytes in RAM because each element uses two bytes

*/
signed int16                DataArray16[32];     //64 bytes
signed int16*                PointerArray16[32];  //64 bytes                                         
int8            DataArray8[32];         //32 bytes
int8*            PointerArray8[32];   //64 bytes


//These are a couple of variables initialised to zero so I have something to point the pointers to during the demo
int8 Default8 = 0;
signed int16 Default16 = 0;
   
//Now the function declarations
void FillArrays();
void ClearArrays();
void WriteArrayToFlash();
void ReadArrayFromFlash();
void PrintArrays();

void main()
{

   setup_adc_ports(ALL_ANALOG|VSS_VDD);
   setup_adc(ADC_CLOCK_DIV_2|ADC_TAD_MUL_2);
   setup_psp(PSP_DISABLED);
   setup_spi(SPI_SS_DISABLED);
   setup_wdt(WDT_OFF);
   setup_timer_0(RTCC_INTERNAL);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   setup_oscillator(FALSE);

   delay_ms(100);
   printf("\nStarting . . .\n");

   //First lets read the data in flash - if you have just programmed the PIC then this
   //will probably be empty or garbage
   //If you have already run this programe before then this will read the data stored from last time
   
   printf("\nReading Data From Flash . . .\n");
   ReadArrayFromFlash();
   
   //Now print the data - thie will print the contents of the data arrays
   //and the variables that the pointers actually point to
   printf("\nPrinting Data . . .\n");
   PrintArrays();

   //Now lets fill the arrays with new data
   printf("\nFilling Arrays with values . . .\n");
   FillArrays();
   
   //and print them again
   printf("\nPrinting Arrays . . .\n");
   PrintArrays();
   
   //Now save this data to flash
   printf("\nSaving to flash . . .\n");
   WriteArrayToFlash();
   
   //clear the data arrays
   printf("\nErasing RAM . . .\n");
   ClearArrays();
   
   //Print them again to verify that they have been erased
   printf("\nPrinting Erased RAM . . .\n");
   PrintArrays();
   
   //Recover the data from flash
   printf("\nRecovering Data From Flash . . .\n");
   ReadArrayFromFlash();
   
   //and print again to check that it all works
   printf("\nPrinting Revovered Data . . .\n");
   PrintArrays();


   printf("\nFINISHED\n");
   delay_ms(100);
   

}

void FillArrays()
{
   //fill the arrays with some data
   int8 n;

   for(n = 0; n < 32; n++)
   {
      //Put some values into each data array
      DataArray16[n]       = 100+n;
      DataArray8[n]       = n;
      
      //Point each pointer in the array at the values in the data arrays above
      PointerArray16[n]    = &DataArray16[n];
      PointerArray8[n]    = &DataArray8[n];

   }
}

void ClearArrays()
{
   //Clear all the arrays
   int8 n;

   for(n = 0; n < 32; n++)
   {
      //Set the elements in each data array to zero
      DataArray16[n]       = 0;
      DataArray8[n]       = 0;
      //Set the poiters to point at a zero valued variable
      PointerArray16[n]    = &Default16;
      PointerArray8[n]    = &Default8;

   }
}

void WriteArrayToFlash()
{
   
   //write arrays to flash
   //work out the start address in flash for the first byte
   int16 FlashStartAddress;
   
   //Disable interrupts when reading and writing to flash
   disable_interrupts(GLOBAL);
   
   //First work out the address in flash where we want our data to start
   FlashStartAddress = FLASH_DATA_START;
   
   //now write the first array into flash, starting from this address
   
   /*
   DataArray16 has 32 elements, each using two bytes so we are actually copying 64 bytes to flash
   We are giving the function the address in flash we want it to start at,
   a pointer to the first byte in RAM of the data we want (Because we are working with arrays
   we just pass the array name as this is actually a pointer)
   We also need to tell the function how many bytes we want to copy
   */
   write_program_memory( FlashStartAddress, DataArray16, 64 );
   //Now we add 64 to the flash address variable
   FlashStartAddress += 64;
   //Now the same as above but this time we copy the array of pointers -
   //this will save the actual pointers to flash NOT the variables they point to!
   //Again there are 64 bytes, two for each 16 bit pointer
   write_program_memory( FlashStartAddress, PointerArray16, 64 );
   FlashStartAddress += 64;
   
   //Now we can copy the array of int8 data to flash
   //This array also has 32 elements but each element is only a single byte
   write_program_memory( FlashStartAddress, DataArray8, 32 );
   //Now increase the flash address again, but only by 32 bytes this time
   FlashStartAddress += 32;
   
   //Finally we are going to copy the 32 elements in the array of int8 pointers
   //REMEMBER! Pointers use 16 bits so even though these point to int8 variables
   //the actual pointers are 16 bit values so we are saving 64 bytes                                       
   write_program_memory( FlashStartAddress, PointerArray8, 64 );
   
   //Now re-enable any interrupts

   enable_interrupts(GLOBAL);
}


void ReadArrayFromFlash()
{
   int16 FlashStartAddress;
   //Disable interrupts
   disable_interrupts(GLOBAL);
   
   //read all the arrays from flash
   //This is identical to the function above in every way except
   //we are calling the read function instead of the write function
   
   FlashStartAddress = FLASH_DATA_START;
   
   read_program_memory( FlashStartAddress, DataArray16, 64 );

   FlashStartAddress += 64;
   
   read_program_memory( FlashStartAddress, PointerArray16, 64 );
   FlashStartAddress += 64;
   
   read_program_memory( FlashStartAddress, DataArray8, 32 );
   
   FlashStartAddress += 32;
   
   //Remember that these int8 pointers use two bytes!
   read_program_memory( FlashStartAddress, PointerArray8, 64 );
   
   //re-enable any interrupts when finished
   enable_interrupts(GLOBAL);
}


void PrintArrays()
{
   //Prints the contents of all the arrays to the serial port
   int8 n;
   printf("\nSInt16 Data Array:\n");
   for(n = 0; n < 32; n++)
   {
      printf("%ld ",DataArray16[n]);
   }
   
   printf("\nSInt16 Pointer Array:\n");
   for(n = 0; n < 32; n++)
   {
      printf("%ld ",*PointerArray16[n]);
   }
   
   printf("\nInt 8 Data Array:\n");
   for(n = 0; n < 32; n++)
   {
      printf("%u ",DataArray8[n]);
   }
   
   printf("\nInt 8 Pointer Array:\n");
   for(n = 0; n < 32; n++)
   {
      printf("%u ",*PointerArray8[n]);
   }
   printf("\n\n");

   
}
aldina



Joined: 09 Oct 2009
Posts: 26

View user's profile Send private message Send e-mail

PostPosted: Fri Mar 04, 2016 11:57 am     Reply with quote

Hi BotBill,

Maybe you can give me your opinion. I'm trying to read and write in flash memory but I can not.
So, I have a int8 var that change the value in diferent functions. In main program I cal a function that read that value or change when the B2 input goes High.
My idea is when I turn off the power supply of my microcontroller, the last value of my flag_system var will stay on flash memory for the next read. So when I turn on again the var should have the last value, but this is not happening, when I turn on my system var flag_system is always with int8 = 0 and not with the last value.
Can you see my code and give me your oppinion?

Thanks for your attention!!!

Code:
#include <16f526.h>
#device ADC=8
#fuses INTRC,NOWDT,NOMCLR,PROTECT
#use delay(clock=8000000)
#include <math.h>

 //this gets the total size of the program memory from the compiler
 #define PROGRAM_MEMORY_SIZE      getenv("PROGRAM_MEMORY")

 /*
 Programe data in flash starts at the bottom and fills upwards
 I'm assuming that my code will not use up more than 50% of the flash
 which is 64k for this PIC so I want to reserve the TOP 50% of flash for my own use
 */
 //so define the total amount of memory I want
 #define FLASH_DATA_SIZE      32767
 //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)

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

int8 flag_system=0;

// Function - System A
void Sistema_A(){
   flag_system=0;
     
    //write arrays to flash
    //work out the start address in flash for the first byte
    int8 FlashStartAddress;
     
    //Disable interrupts when reading and writing to flash
    //disable_interrupts(GLOBAL);
     
    //First work out the address in flash where we want our data to start
    FlashStartAddress = FLASH_DATA_START;
     
    //now write the first array into flash, starting from this address
     
    /*
    flag_system has 1 element, using one byte, so we are actually copying 1 bytes to flash
    We are giving the function the address in flash we want it to start at,
    to the first byte in RAM of the data we want
    We also need to tell the function how many bytes we want to copy
    */
    //write_program_memory( FlashStartAddress, flag_system, 1 );
    write_bank( FlashStartAddress, 0, flag_system );
    //Now we add 64 to the flash address variable
    FlashStartAddress += 8;
         
    //Now re-enable any interrupts

    //enable_interrupts(GLOBAL);
 }

// Function System B
void Sistema_B(){
   flag_system=1;
   
   //write arrays to flash
    //work out the start address in flash for the first byte
    int8 FlashStartAddress;
     
    //Disable interrupts when reading and writing to flash
    //disable_interrupts(GLOBAL);
     
    //First work out the address in flash where we want our data to start
    FlashStartAddress = FLASH_DATA_START;
     
    //now write the first array into flash, starting from this address
     
    /*
    flag_system has 1 element, using one byte, so we are actually copying 1 bytes to flash
    We are giving the function the address in flash we want it to start at,
    to the first byte in RAM of the data we want
    We also need to tell the function how many bytes we want to copy
    */
    //write_program_memory( FlashStartAddress, flag_system, 1 );
    write_bank( FlashStartAddress, 0, flag_system );
    //Now we add 64 to the flash address variable
    FlashStartAddress += 8;
         
    //Now re-enable any interrupts

    //enable_interrupts(GLOBAL);
}

// Function System C
void Sistema_C(){
   flag_system=2;
   //write arrays to flash
    //work out the start address in flash for the first byte
    int8 FlashStartAddress;
     
    //Disable interrupts when reading and writing to flash
    //disable_interrupts(GLOBAL);
     
    //First work out the address in flash where we want our data to start
    FlashStartAddress = FLASH_DATA_START;
     
    //now write the first array into flash, starting from this address
     
    /*
    flag_system has 1 element, using one byte, so we are actually copying 1 bytes to flash
    We are giving the function the address in flash we want it to start at,
    to the first byte in RAM of the data we want
    We also need to tell the function how many bytes we want to copy
    */
    //write_program_memory( FlashStartAddress, flag_system, 1 );
    write_bank( FlashStartAddress, 0, flag_system );
    //Now we add 64 to the flash address variable
    FlashStartAddress += 8;
         
    //Now re-enable any interrupts

    //enable_interrupts(GLOBAL);
}

// Function System D
void Sistema_D(){
   flag_system=3;
   //write arrays to flash
    //work out the start address in flash for the first byte
    int16 FlashStartAddress;
     
    //Disable interrupts when reading and writing to flash
    //disable_interrupts(GLOBAL);
     
    //First work out the address in flash where we want our data to start
    FlashStartAddress = FLASH_DATA_START;
     
    //now write the first array into flash, starting from this address
     
    /*
    flag_system has 1 element, using one byte, so we are actually copying 1 bytes to flash
    We are giving the function the address in flash we want it to start at,
    to the first byte in RAM of the data we want
    We also need to tell the function how many bytes we want to copy
    */
    //write_program_memory( FlashStartAddress, flag_system, 1 );
    write_bank( FlashStartAddress, 0, flag_system );
    //Now we add 64 to the flash address variable
    FlashStartAddress += 8;
         
    //Now re-enable any interrupts

    //enable_interrupts(GLOBAL);
}

// Function to select system
void SelectSystem()
{
   int8 flag;
   
    int8 FlashStartAddress;
    //Disable interrupts
    //disable_interrupts(GLOBAL);
     
    //read from flash
    //This is identical to the function above in every way except
    //we are calling the read function instead of the write function
     
    FlashStartAddress = FLASH_DATA_START;
     
    //read_program_memory( FlashStartAddress, DataArray16, 64 );
    flag=read_bank(FlashStartAddress,0);
         
    FlashStartAddress += 8;
         
    //re-enable any interrupts when finished
    //enable_interrupts(GLOBAL);
 
   if(flag==0)
   {
      Sistema_A();
      delay_ms(1);
   }
   else if(flag==1)
   {
     Sistema_B();
     delay_ms(1);
   }
   else if(flag==2)
   {
    Sistema_C();
    delay_ms(1);
   }
   else if(flag==3)
   {
      Sistema_D();
      delay_ms(1);
   }

   while(true)
   {
      if(input(PIN_B2))
      {
         delay_ms(20);
         if(input(PIN_B2))
         {
            if(flag_system==0)
            {
               delay_ms(50);
               Sistema_B();
               break;
            }
            else if(flag_system==1)
            {
               delay_ms(50);
               Sistema_C();
               break;
            }
            else if(flag_system==2)
            {
               delay_ms(50);
               Sistema_D();
               break;
            }
            else if(flag_system==3)
            {
               delay_ms(50);
               Sistema_A();
               break;
            }
 
         }
      }
      break;
   }
   delay_ms(10);
}

void main() {

   set_tris_c(0x00); 
   
   SETUP_ADC(ADC_OFF);
   SETUP_ADC_PORTS(NO_ANALOGS); 
   setup_comparator(NC_NC_NC_NC);
 
   while(true)
   {
       SelectSystem();
   
       if(flag_system==0)
       {   // Sistema A
          output_high(PIN_C0); // Leds on 50ms
          delay_ms(50);  // Ton
          output_low(PIN_C0);
          delay_ms(50);
         
          output_high(PIN_C0); // Leds on
          delay_ms(50);  // Ton
          output_low(PIN_C0);
          delay_ms(50);
         
          output_high(PIN_C0); // Leds on
          delay_ms(150);  // Ton
          output_low(PIN_C0);
          delay_ms(450);
       }
       
       else if(flag_system==1)
       {
          output_high(PIN_C0); // Leds on 50ms
          delay_ms(50);  // Ton
          output_low(PIN_C0);
          delay_ms(50);
         
          output_high(PIN_C0); // Leds on
          delay_ms(150);  // Ton
          output_low(PIN_C0);
          delay_ms(450);
       }
           
       else if(flag_system==2)
       {
          output_high(PIN_C0);
          delay_ms(350);
          output_low(PIN_C0);
          delay_ms(350);
       }
           
       else if(flag_system==3)
       {   // Sistema D     
          output_high(PIN_C0); // Leds on 50ms
          delay_ms(50);  // Ton
          output_low(PIN_C0);
          delay_ms(50);
         
          output_high(PIN_C0); // Leds on
          delay_ms(150);  // Ton
          output_low(PIN_C0);
          delay_ms(150);
         
          output_high(PIN_C0); // Leds on
          delay_ms(50);  // Ton
          output_low(PIN_C0);
          delay_ms(50);
         
          output_high(PIN_C0); // Leds on 50ms
          delay_ms(150);  // Ton
          output_low(PIN_C0);
          delay_ms(750);
       }
    }
}

Best regards,
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Fri Mar 04, 2016 5:38 pm     Reply with quote

any safe and reliable method for storing(especially re-writing) data in PROG MEMORY or
EEPROM MUST have some form of error detection,
and a method for post-handling
detection of corrupted data on READ_back .

16 bit checksum and CRC come to mind with little overhead .

Unless you don't care about the results -
it is reckless to just read and write data as these routines do.

well documented but potentially , operationally dangerous to borrow and use .

CAVEAT EMPTOR folks
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library 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