Monday, June 29, 2020

STM32 Tutorial - STM32 EEPROM Emulation Arduino

STM32 EEPROM Blue Pill

STM32 EEPROM Emulation - EEPROM is an extension of Electrically Erasable Programmable Read-Only Memory, a memory chip that can store data even if power or resources are disconnected.

Generally every microcontroller already has an Internal EEPROM, this makes the circuit simpler without having to add an external chip.

Unlike Arduino which has an internal non-volatile storage chip, some Blue Pill devices do not have it. For this reason, if we want to save data to Blue Pill, we need a method that can allocate program flash memory as EEPROM.

In the official language of the ST datasheet, this memory allocation is called STM32 EEPROM Emulation. I have never used this on Arduino, so from that I shared a little program in this Article.

A. STM32 EEPROM Emulation

This emulation is done by considering the limitation of Flash memory and some requirements. This approach requires at least two pages of flash memory of the same size allocated for non-volatile data. For a more complete explanation of this EEPROM Emulation, please read the official ST document.

STM32 Tutorial, STM32 EEPROM Emulation Arduino, How to Access Read Write STM32 EEPROM Blue Pill Using Arduino IDE
STM32 EEPROM Arduino

Officially, to program this chip using software from the ST itself named STM32CubeIDE. But because I'm not familiar with it, I just use Arduino IDE because there are already many libraries available.

Well, because the Arduino IDE is basically an IDE for programming AVR, someone developed a library board for this chip to be used in the Arduino IDE. This is very useful.

B. Library for STM32 Emulation Arduino

The library board to support this chip to be programmed using the Arduino IDE has several options. However, the library board that I use on this project is STM32 Arduino Core.

This Arduino Core STM32 tries to emulate this non-volatile storage access way as in Arduino. STM32 Arduino Core provides this library which I managed to try.

If we use arduino, to write data just use "EEPROM.write (address, data)" and read with "EEPROM.read (address)".

Whereas what I use to write is "EEPROMwrite (address, data)" and reads with "EEPROMread (address, data_data)".

The STM32 program is to use ST-LINK V2 Clone (China) and for serial monitor communication I connect FTDI on pins A9 and A10.

Below is the program code that I have tested and succeeded. Please upload the following STM32 EEPROM code to your STM32 and open Serial Monitor to see the stored data and the results of reading the data.

C. Schematic For Testing

To program this Blue Pill, I use ST Link V2. For serial communication, using FTDI, please follow the following table

STM32FTDI
 A9RX
 A10TX

D. Progam Code STM32 EEPROM Emulation

Program:
#include <EEPROM.h>

const int addressEEPROM_min = 0;              // Specify the address restrictions you want to use.
const int addressEEPROM_max = 4095;           // For example, the maximum is 4095, which means we allocate 4KB of memory (4096 bytes) for the Virtual EEPROM.

float latitude =   4.158919;                  // This is an example of data that you want to save to EEPROM.
float longitude = 96.124843;                  // Coordinate data consisting of Latitude and Longitude.

int addressLat = 0;                           // The number of characters in the latitude value is 8, so the address starts from 0 to 8.
int addressLon = 9;                           // The number of characters in the longitude value is 9, so the address starts from 9 to 17.

void setup()
{
  Serial.begin(9600);
  delay(100);

  String lat = String (latitude, 6);         // Data to be saved to EEPROM is a String. This line is used for the conversion of float to String.
  String lon = String (longitude, 6);        // Value 6 shows how many digits behind the comma will be converted.

  // ------------------- Write Data Commands -------------------
  Serial.println(" -----------------------------------------");
  Serial.println("| Writing Latitude to EEPROM  | Saved |");
  EEPROMwrite(addressLat, lat);
  Serial.println("| Writing Longitude to EEPROM | Saved |");
  EEPROMwrite(addressLon, lon);
  Serial.println(" -----------------------------------------");
  Serial.println("\n");
  delay(1000);
  //----------------------------------------------------------

  // ------------------- Read Data Commands -------------------
  Serial.println("Baca data dari EEPROM.....");
  Serial.print("Latitude  : ");
  Serial.println(EEPROMread(addressLat, 8));  // Get data from address 0 with 8 characters.
  Serial.print("Longitude : ");
  Serial.println(EEPROMread(addressLon, 9));  // Get data from address 9 with a total of 9 characters.
  Serial.println("\n");
  delay(1000);
  //----------------------------------------------------------

  Serial.println("Now, please COMMENT *Write Data Commands* to deactivate data write commands to EEPROM.");
  delay(5000);
  Serial.println("Then, please press the reset button or remove STM32 from the computer to see whether the data from the EEPROM is still stored or not.");
} 

void loop()
{

}

String EEPROMread(int StartAddr, int StringLength)
{
  char buf[StringLength + 1];
  eeprom_read_string(StartAddr, buf, StringLength + 1);
  String dataStr = buf;
  return dataStr;
}

void EEPROMwrite(int StartAddr, String DataString)
{
  int val = DataString.length() + 1;
  char StringChar[val];
  char buff[val];

  DataString.toCharArray(StringChar, val);
  strcpy(buff, StringChar);
  eeprom_write_string(StartAddr, buff);
}

boolean eeprom_is_addr_ok(int addr)
{
  return ((addr >= addressEEPROM_min) && (addr <= addressEEPROM_max));
}

boolean eeprom_write_bytes(int startAddr, const byte* array, int numBytes)
{
  int i;

  if (!eeprom_is_addr_ok(startAddr) || !eeprom_is_addr_ok(startAddr + numBytes))
  {
    return false;
  }

  for (i = 0; i < numBytes; i++)
  {
    EEPROM.write(startAddr + i, array[i]);
  }
  return true;
}

boolean eeprom_write_string(int addr, const char* string)
{
  int numBytes;                                                    // number of actual bytes to be written

  numBytes = strlen(string) + 1;                                   // Write string content plus byte terminator string (0x00)
  return eeprom_write_bytes(addr, (const byte*)string, numBytes);
}

boolean eeprom_read_string(int addr, char* buffer, int bufSize)
{
  byte ch;                                                         // read bytes from eeprom
  int bytesRead;                                                   // number of bytes read so far

  if (!eeprom_is_addr_ok(addr))                                    // check the starting address
  {
    return false;
  }

  if (bufSize == 0)                                                // how can we store bytes in an empty buffer?
  {
    return false;
  }

  if (bufSize == 1)                                                
  {
    buffer[0] = 0;
    return true;
  }

  bytesRead = 0;                                                   // initialize a byte counter
  ch = EEPROM.read(addr + bytesRead);                              // read the next byte from eeprom
  buffer[bytesRead] = ch;                                          // save it in the user's buffer
  bytesRead++;

  // if no stop conditions are met, read the next byte from the eeprom
  while ( (ch != 0x00) && (bytesRead < bufSize) && ((addr + bytesRead) <= addressEEPROM_max) )
  {
    ch = EEPROM.read(addr + bytesRead);
    buffer[bytesRead] = ch;                                        // save it in the user's buffer
    bytesRead++;
  }

  if ((ch != 0x00) && (bytesRead >= 1))                            // make sure the user buffer has the string terminator, (0x00) as the last byte
  {
    buffer[bytesRead - 1] = 0;
  }
  return true;
}

Results:
STM32 Tutorial, STM32 EEPROM Emulation Arduino
Result from STM32 EEPROM


May be useful.