5

I am designing an application which include GSM SIM900 with PIC18F2520. The application includes basic calling and sms services. A user will press a button a call will be made to a defined number. This number can be changed via sms. So whenever the button is pressed again, the call will be made to the newly defined number. Currently I am using these variables for number:

char callNumber1[10];
char callNumber2[10];
*
*
char callNumber5[10];

The problem I am facing is these variables works as expected. But when I turn off the power of MCU, the data stored in them are lost. I want the data to be remained as it is after the power off and can be used again after power on. How to save them in MCU's memory. Please provide any link where I can read about memory in MCU. Please help.

S Andrew
  • 621
  • 10
  • 29

2 Answers2

20

Whatever you declare as a variable in your code will be in the RAM of the PIC, and thus will disappear when you power it off. However, the PIC18F2580 has 256 bytes of EEPROM memory, which is non-volatile. You can store your phone numbers there each time they are modified, and load them at boot to your variables.

To read and write a byte to a given address of the EEPROM, you have to use the EECON1, EECON2, EEDATL and EEADRL registers (see chapter 8 of the datasheet), for example:

uint8_t read_eeprom(uint8_t addr)
{
  EECON1 = 0;
  EEADRL = addr;
  EECON1bits.RD = 1;
  return EEDATL;
}

void write_eeprom(uint8_t addr, uint8_t value)
{
  EECON1 = 0;
  EEADRL = addr;           // address to write to
  EEDATL = value;          // value to write
  EECON1bits.WREN = 1;     // enable write
  EECON2 = 0x55;           // write unlock sequence
  EECON2 = 0xAA;
  EECON1bits.WR = 1;       // do the actual write
  EECON1bits.WREN = 0;     // disable writing
  while (EECON1bits.WR != 0);  // wait for the writing to complete
  EEIF = 0;                // clear EEPROM interrupt flag
}

And then you can load your numbers with something like this:

void load_number(const uint8_t start_addr, char* n, const int len)
{
  for (uint8_t i = 0; i < n; i++) {
    n[i] = read_eeprom(start_addr + i);
  }
}

load_number(0, callNumber1, 10);
load_number(10, callNumber2, 10);
// etc.

And same idea for saving. To note that this code is not using the EEPROM memory very efficiently, because storing ASCII digits in it wastes space. If you get constrained by the 256 bytes of EEPROM, you might for example store the numbers in BCD format, thus having two digits per byte.

Unlike RAM, nonvolatile memories as EEPROM and Flash have a limited number of write cycles. Although this number is generally very high (1 million cycles for the PIC18F2580 EEPROM), it is good practice not to write to nonvolatile memory unless this is necessary, i.e, the data has actually been modified and has to be stored.

If data has to be written periodically to a EEPROM or Flash memory, a wear-levelling algortithm might be helpful to evenly distribute the wear on the memory cells. This might be even more important with Flash-based nonvolatile memory, that often has less write cycles than EEPROM (e.g., the Flash memory of the PIC18F2580 has "only" 100k write cycles endurance).

Ale
  • 846
  • 6
  • 19
  • If you don't have EEPROM available, most micros (all of the ones I've run across) will let the firmware write to flash. It's not as fast, easy, or power-friendly as EEPROM, but it can be done. If you have EEPROM, that's definitely the way to go. – CHendrix Aug 04 '16 at 15:03
  • 8
    Even though the EEPROM in the PIC18F2520 has a 1M erase/write cycle spec, it might be a good idea to mention that issue. You might cover it briefly or point to other questions/resources which cover mitigating the number of times the EEPROM is written (e.g. only writing upon detection of loss of power, wear leveling, etc.). While it might not be needed in the OPs specific situation, it would be helpful for people seeing this Q&A in the future to at least have mentioned that there are additional considerations other than thinking they should store some random variable in EEPROM/FLASH. – Makyen Aug 04 '16 at 15:08
  • @Ale Thanks. This is great. I studied about memory management and tried this code and its working. Before merging this code to my existing GSM code, I tested my code for the GSM. I power off the MCU and turned it on again and it was working. The defined variables are even working after power off. Now this has created a huge confusion in my mind. How the variable are working after power off. How the data in the variables are still safe.? – S Andrew Aug 05 '16 at 09:29
  • 1
    Microcontrollers tend to have static RAM and capacitors on board, so they can often retain values across short periods of power-off. – pjc50 Aug 05 '16 at 10:10
  • @Makyen Good considerations, thanks! I expanded the answer. – Ale Aug 05 '16 at 14:45
  • Ideally you only want to save on a power down to avoid wearing out the non volatile storage, do that right though you need hardware to detect the power is going down, and enough capacitance or other energy storage to guarantee to stay up long enough to complete the write. – old_timer Aug 05 '16 at 20:11
  • you could use an sd card (something removable) for this, save early and often, when it wears out give them a corrupt card message and they can buy a new sd card to keep it working. – old_timer Aug 05 '16 at 20:12
  • @dwelch For applications that intensively write to non-volatile memory, this might make sense, either with a SD card or similar memory support, or even an EEPROM on a DIL socket (depending on the application, one or the other might make more sense). However, one has to check what the possible lifetime of the EEPROM will be: supposing that the program writes to the EEPROM every hour at the same address, the PIC18F EEPROM will still have a lifetime of 114 years before reaching its EOL. Compare with the 40 years data retention of its Flash before needing to "refresh" it... – Ale Aug 09 '16 at 20:19
14

The SIM900 actually has its own 'phonebook', which you could use to save the numbers. See AT+CPBW and related commands.

Examples from the documentation. Write to phonebook:

AT+CPBW=,"13918 18xxxx",129,"Daniel"

Read from phonebook:

AT+CPBF="Daniel"

returns

+CPBF:5, "13918186089",129,"Daniel"

List phonebook:

AT+CPBR=1,10

pjc50
  • 46,540
  • 4
  • 64
  • 126
  • This method is great but the problem is when we save the contacts, it doesnt tell us the location at which the contact is saved. Now later if I want to modify it, we first have to delete the contact. While deleting it ask for contacts location which we do not know. Though I can use `AT+CPBR` to list all the contacts but that will list all the contacts data which will overflow the buffer. It doesnt delete the contact using name. – S Andrew Aug 06 '16 at 04:55
  • @Andrew There is no command to simply change the number of a contact? It is a basic use case. – Bence Kaulics Aug 10 '16 at 11:40