The Infineon XMC2Go board is a really good board to use with the Arduino IDE. It is small, rather fast and inexpensive. It is ideal for wearables, small sensors with a display. The 64kB flash is big enough for larger applications and 16kB memory is also super when one wants to do complicated things.
There is only one shortcoming, it has no EEPROM and also no EEPROM emulation. As the flash is pretty large, this would have been easy to implement, but the the standard core comes without this feature.
This is my attempt to build an EEPROM emulation from scratch for this board.
EEPROMs and FlashEEPROMs and Flash storage keep the data at power off. However, from the point of view of technology they are very different. While EEPROM can be rewritten quite often, up to 100000 times, flash memory has a shorter lifespan. 10000 rewrites are a rule of thumb. EEPROMs have small blocks that can be rewritten individually, while flash has larger page sizes. Addressing and writing a flash just like an EEPROM will kill it fast. An EEPROM emulation on flash will never be like a real EEPROM. It needs to implement a buffering strategy to protect the flash from wearing out.
Sophisticated EEPROM emulation strategies use multiple pages for the same data and avoid updates of the same page. The solution I show here is simpler. It contains a rather large write buffer and a small read buffer. The write buffer is as big as the physical flash size. All read and write operation go through this buffer. If stays in RAM until a commit operations writes to the flash or a write page fault occurs. This limits the write operation to the flash to a minimum.
A word of caution on XMC2Go boardsXMC2Go boards come in two variants. Theres is a common 64kB type. If has 64kB flash memory and is supported by the Arduino IDE. Flash parameters are set right for this board.
There is also a 32kB variant with a reduced flash. These boards have the code 032B on the main chip in the front part of the board. These boards work with the Arduino IDE but they are not really supported. Special caution is needed using them.
Getting startedTo use these boards, you need the Arduino core for XMC. Best follow the instruction in the official repo https://github.com/Infineon/XMC-for-Arduino to install the core and the uploader. The Segger J-Lin uploader is needed in addition to the Arduino IDE and the core files.
Infineon has also written an excellent instruction page here on hackster https://www.hackster.io/Infineon_Team/xmc-for-arduino-4a29f6.
In addition to this you need the XMCEEPROM library from https://github.com/slviajero/XMCEEPROMLib.
Download the library and place it into your Arduino/library folder. The library consists only of a file XMCEEPROMLib.h. There is no cpp file. Alternatively you also can put the header file into your sketch directory.
Try it outTo get the EEPROM emulation running a minimal sketch would look like this.
#include <XMCEEPROMLib.h>
void setup() {
Serial.begin(9600);
delay(3000);
Serial.println("EEPROM emulator started");
EEPROM.begin();
// now you can do things with the EEPROM
}
The include generates an EEPROM object, just like on the Arduino. Unlike on Arduino, a call to EEPROM.begin() is needed. Without an argument, it reserves the upper 4 kB of the flash for the EEPROM emulation on a 64kB board.
For different EEPROM sizes use EEPROM.begin() with an argument like e.g. EEPROM.begin(1024).
If you have a 32kB board, use EEPROM.begin(4096, 32768) as a begin method. This places the EEPROM emulation storage just below the 32kB.
All EEPROM methods of the Arduino API are implemented plus one additional method.
uint8_t EEPROM.read(int address)
void EEPROM.write(int address, uint8_t val)
void EEPROM.update(int address, uint8_t val)
uint16_t EEPROM.length()
void EEPROM.commit()
void EEPROM.end()
int EEPROM.status()
read(), write(), and update() work just like on the Arduino. update() and write() are identical.
commit() writes the buffer page to flash. This method has to be called occasionally to make sure no data is lost if the MCU loses power. end() is identical to commit(). status() returns the status of the last flash operation. It should be checked after any physical write, i.e. after a commit. A status of 0 means that the operation was successful. Any error from the flash operation sets the status to the error value.
Run the test programAll the features of the flash emulation are demonstrated in the example program
/*
* Stefan's XMC EEPROM Library
*
* See the licence file on for copyright/left.
* (GNU GENERAL PUBLIC LICENSE, Version 3, 29 June 2007)
*
* Author: Stefan Lenz, sl001@serverfabrik.de
*
* Simple test program
*
*/
#include <XMCEEPROMLib.h>
void setup() {
// start Serial
Serial.begin(9600);
delay(3000);
// begin the EEPROM Emulator
Serial.println("EEPROM emulator started");
EEPROM.begin(4096);
Serial.print("Status: "); Serial.println(EEPROM.status());
// wait a little
delay(3000);
// show what is there
Serial.println("EEPROM page 0");
for (int i=0; i<256; i++) {
if (i % 16 == 0 ) {
Serial.println();
Serial.print(i);
Serial.print(": ");
}
Serial.print(EEPROM.read(i)); Serial.print(" ");
}
Serial.println();
// wait a little and say something
Serial.print("Error status is ");
Serial.println(EEPROM.status());
delay(1000);
// test 1 - write one byte and make permanent with a commit
Serial.println("First test, write one cell");
Serial.print("Cell 10 is ");
Serial.println(EEPROM.read(10));
if (EEPROM.read(10) == 42) EEPROM.write(10,84); else EEPROM.write(10, 42);
Serial.print("Cell 10 is now ");
Serial.println(EEPROM.read(10));
Serial.println("This should have changed now.");
Serial.println("Committing to flash");
EEPROM.commit();
// test 2 - provoke a write page fault
Serial.println("EEPROM page 0 is now");
for (int i=0; i<256; i++) {
if (i % 16 == 0 ) {
Serial.println();
Serial.print(i);
Serial.print(": ");
}
Serial.print(EEPROM.read(i)); Serial.print(" ");
}
Serial.println();
// wait a little and say something
Serial.print("Error status is ");
Serial.println(EEPROM.status());
delay(1000);
// write and then provoke the page fault
EEPROM.write(10, 77);
EEPROM.write(256, 0);
Serial.println("EEPROM page 0 is now");
for (int i=0; i<256; i++) {
if (i % 16 == 0 ) {
Serial.println();
Serial.print(i);
Serial.print(": ");
}
Serial.print(EEPROM.read(i)); Serial.print(" ");
}
Serial.println();
}
void loop() {
// put your main code here, to run repeatedly:
}
Note the use of EEPROM.commit() to trigger the flash write.
Looking under the hoodThe library used the XMC flash interface. This interface can read 16 byte blocks from the flash to memory and it can write entire 256 byte pages to the flash memory by erasing it first and then programming it.
To reduce flash erase cycles and to have enough performance on read, two buffers are implemented. One buffer has 256 bytes and holds an entire page. It is filled with data, once you call the EEPROM.write() call for the first time. The page you want to write your byte to is loaded to memory and written. All EEPROM.read() and EEPROM.write() operations to this page now go through the buffer and the flash remains untouched until one of two operations happen:
If you call EEPROM.commit() the page is written and the data is preserved in the buffer. You can continue to write and read from the buffer. If you write beyond the page boundary, i.e. in another 256 byte region, the page is written to the flash and the new page is loaded. A page fault like this causes a flash erase and write only if the page has changed data. Unchanged data causes no flash erase.
In addition to this, there is an independent 16 byte read buffer. All reads go through this buffer, if they are outside the page buffer. Read operation cannot cause a page fault of the write page.
What to do and what to avoidThe EEPROM emulation can read quickly and you can do random reads.
If you write, keep the writes to one page at a time. This keeps the page in memory and you can write different locations quickly without any risk to the flash. Call EEPROM.commit() now and then to make sure your data is protected against a data loss.
Never write randomly with high frequency to different pages. Every page fault causes a flash erase and after 10000 erase cycles your board is dead.
The Arduino IDE does not know about the EEPROM emulation. It still thinks that all of the 64kB flash is available for sketches. Make sure that your sketch leaves enough room at the top of the flash area for the EEPROM.
If you feel paranoid and want to make sure, add this to your boards.txt file
XMC1100_XMC2GOE.name=XMC1100 XMC2Go (EEPROM)
XMC1100_XMC2GOE.upload.tool=xmcprog
XMC1100_XMC2GOE.upload.speed=115200
XMC1100_XMC2GOE.upload.resetmethod=ck
XMC1100_XMC2GOE.upload.maximum_size=61440
XMC1100_XMC2GOE.upload.wait_for_upload_port=true
XMC1100_XMC2GOE.communication=usb
XMC1100_XMC2GOE.protocol=dragon_isp
XMC1100_XMC2GOE.program.protocol=dragon_isp
XMC1100_XMC2GOE.program.tool=xmcprog
XMC1100_XMC2GOE.program.extra_params=-Pusb
XMC1100_XMC2GOE.serial.disableDTR=true
XMC1100_XMC2GOE.serial.disableRTS=true
XMC1100_XMC2GOE.build.mcu=cortex-m0
XMC1100_XMC2GOE.build.f_cpu=32000000L
XMC1100_XMC2GOE.build.board=ARM_XMC
XMC1100_XMC2GOE.build.board.version=1100
XMC1100_XMC2GOE.build.board.type=T038x0064
XMC1100_XMC2GOE.build.board.v=0064
XMC1100_XMC2GOE.build.core=./
XMC1100_XMC2GOE.build.variant=XMC1100
XMC1100_XMC2GOE.build.board_variant=XMC1100_XMC2GO
XMC1100_XMC2GOE.build.flash_size=64K
XMC1100_XMC2GOE.build.flash_ld=linker_script.ld
XMC1100_XMC2GOE.build.extra_flags=-DARM_MATH_CM0 -DXMC1_SERIES
XMC1100_XMC2GOE.menu.UART.debug=PC
XMC1100_XMC2GOE.menu.UART.debug.uart.selected=-DSERIAL_HOSTPC
XMC1100_XMC2GOE.menu.UART.onBoard=On Board
XMC1100_XMC2GOE.menu.UART.onBoard.uart.selected=-DSERIAL_ONBOARD
XMC1100_XMC2GOE.menu.LIB.NONE=None
XMC1100_XMC2GOE.menu.LIB.NONE.library.selected=
XMC1100_XMC2GOE.menu.LIB.NN=ARM NN Framework
XMC1100_XMC2GOE.menu.LIB.NN.library.selected=-DARM_LIB_CMSIS_NN
XMC1100_XMC2GOE.menu.LIB.DSP=ARM DSP
XMC1100_XMC2GOE.menu.LIB.DSP.library.selected=-DARM_LIB_CMSIS_DSP
XMC1100_XMC2GOE.menu.LIB.DSPNN=ARM DSP / ARM NN Framework
XMC1100_XMC2GOE.menu.LIB.DSPNN.library.selected=-DARM_LIB_CMSIS_DSP -DARM_LIB_CMSIS_NN
This creates an addition board XMC1100 XMC2Go (EEPROM) in your Arduino IDE with only 61440 bytes of free flash.
What is missing?Currently there is no flash array like the EEPROM[] array in Arduino. Floats and strings have to be written to the EEPROM byte by byte.
One last wordThe XMCEEPROMLib was developed as one component of the IoT BASIC interpreter. BASIC uses the EEPROM as storage medium for programs and date. If you want to try this, check this page for more: https://github.com/slviajero/tinybasic
Comments