5
\$\begingroup\$

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.

\$\endgroup\$
2
  • 9
    \$\begingroup\$ The problem I am facing is these variables works as expected. That's not your problem. \$\endgroup\$
    – Steve
    Commented Aug 4, 2016 at 17:14
  • \$\begingroup\$ Steve, what is the purpose of your comment? \$\endgroup\$ Commented Nov 16, 2020 at 1:57

2 Answers 2

20
\$\begingroup\$

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).

\$\endgroup\$
8
  • \$\begingroup\$ 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. \$\endgroup\$
    – CHendrix
    Commented Aug 4, 2016 at 15:03
  • 8
    \$\begingroup\$ 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. \$\endgroup\$
    – Makyen
    Commented Aug 4, 2016 at 15:08
  • \$\begingroup\$ @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.? \$\endgroup\$
    – S Andrew
    Commented Aug 5, 2016 at 9:29
  • 1
    \$\begingroup\$ Microcontrollers tend to have static RAM and capacitors on board, so they can often retain values across short periods of power-off. \$\endgroup\$
    – pjc50
    Commented Aug 5, 2016 at 10:10
  • \$\begingroup\$ @Makyen Good considerations, thanks! I expanded the answer. \$\endgroup\$
    – Ale
    Commented Aug 5, 2016 at 14:45
14
\$\begingroup\$

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

\$\endgroup\$
2
  • \$\begingroup\$ 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. \$\endgroup\$
    – S Andrew
    Commented Aug 6, 2016 at 4:55
  • \$\begingroup\$ @Andrew There is no command to simply change the number of a contact? It is a basic use case. \$\endgroup\$ Commented Aug 10, 2016 at 11:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.