Driver for M24C01 EEPROM
Description
I would like to use the external EEPROM i have on my board, with basics functions to write and read data from it. The component is a 1Mbit EEPROM from ST Microelectronics. It use the i2c protocol for the data transfer.
Useful links
Official component page: https://www.st.com/en/memories/m24c01-r.html Datasheet : https://www.st.com/resource/en/datasheet/m24c01-r.pdf
I wonder if the existing at24cxx driver would just work here. I was told that most EEPROMs are basically drop-in replacements for those.
@fabian18 might just need only a quick look into the datasheet to see if those are compatible.
I'm not fabian18, but a quick comparison of both datasheets did not yield significant potential issues. The only major difference is that the M24C01 does not support Fast Mode+ with 1MHz clock.
This is the datasheet I compared it against: https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-8871F-SEEPROM-AT24C01D-02D-Datasheet.pdf It even feels like the datasheets were inspired from each other, since the order is exactly the same and the wording often similar :D
We did not have any M24C01 in stock, so I ordered some to test it out. The results might take some time though.
Okay, I actually did find M24C01 EEPROMs. I put them in my backpack weeks ago because I wanted to work on this issue 🤣
@maribu as you already assumed, the M24C01 works as it should as a drop-in replacement for the AT24C01. There is a difference in page size. The AT24C01 has a page size of 8 bytes and the M24C01 has a page size of 16 bytes. Partial page writes are allowed though, so from the user perspective, nothing changes.
On this note, the AT24CXXX library is already very universal and in the https://github.com/RIOT-OS/RIOT/blob/master/drivers/at24cxxx/include/at24cxxx_defines.h file, a lot of defines for different I2C EEPROMs already exist. I think it would make sense to extend this library and perhaps add a note that even though it is called AT24CXXX library, it works for all (most?) I²C EEPROMs. Furthermore I think it might make sense to add an example for the I2C EEPROM or at least extend the documentation a little bit. Currently there is not much of a hint that many configurations already exist. Should this be discussed in this issue or in a separate issue?
@leocordier As stated above, for the time being you can just use the settings of the AT24C01A and everything should work fine. I'll attach my test code.
The code was tested with my NRF52840 Development Kit and an ST M24C01WP I2C EEPROM in DIP-8. Default Address, /WC line not connected. Just VCC, GND, SDA, SCL.
main.c
#include <stdio.h>
#include "at24cxxx.h"
int main(void)
{
at24cxxx_t eeprom_dev;
const at24cxxx_params_t eeprom_params = {
.i2c = 0,
.pin_wp = 2,
.eeprom_size = 128,
.dev_addr = 0x50,
.page_size = 16,
.max_polls = 8
};
int res = at24cxxx_init(&eeprom_dev, &eeprom_params);
if(res != AT24CXXX_OK) {
puts("Error while initializing the I2C EEPROM.");
} else {
puts("I2C EEPROM initialized successfully.");
}
char data[eeprom_dev.params.eeprom_size];
at24cxxx_read(&eeprom_dev, 0, &data, eeprom_dev.params.eeprom_size);
for(uint8_t i = 0; i < eeprom_dev.params.eeprom_size; i++) {
printf("%02X ", data[i]);
}
printf("\n");
fflush(stdout);
while(1);
return 0;
}
Makefile
APPLICATION = EEPROMTest
PROJECT_BASE ?= $(CURDIR)/../..
RIOTBASE ?= $(PROJECT_BASE)/RIOT
# Optionally, provide paths to where external boards and/or modules
# reside, so that they can be included in the app
EXTERNAL_MODULE_DIRS += $(PROJECT_BASE)/modules
EXTERNAL_BOARD_DIRS += $(PROJECT_BASE)/boards
BOARD ?= nrf52840dk
# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
DEVELHELP ?= 1
# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1
# Modules to include:
USEMODULE += at24cxxx
include $(RIOTBASE)/Makefile.include
Edit: Updated the code (double occurance of at24cxxx_t dev;).
@crasbe: Thanks for testing this :heart:
What we could do now is adding the parameters from the datasheet, similar to:
https://github.com/RIOT-OS/RIOT/blob/3c3c5c281c13972c54ceadde355335603540f760/drivers/at24cxxx/include/at24cxxx_defines.h#L347-L368
and select those by default if an m24c01 pseudo module is in used, similar to:
https://github.com/RIOT-OS/RIOT/blob/3c3c5c281c13972c54ceadde355335603540f760/drivers/at24cxxx/include/at24cxxx_defines.h#L426-L429
let the m24c01 pseudo module depend on at24cxx in:
https://github.com/RIOT-OS/RIOT/blob/3c3c5c281c13972c54ceadde355335603540f760/drivers/Makefile.dep#L15-L17
and finally, add m24c01 as pseudo modules to makefiles/pseudomodules.inc.mk.
With all that in place, one could just use USEMODULE += m24c01 and the at24cxx driver would be initialized with the correct parameters for the M24C01 (of course, only if a single I2C EEPROM chip is in use. With multiple connected, one would have to provide the parameters as array by hand).
Would you mind to open a PR to do that, so that you also get the credit in our git history, since you did the testing and digging through the data sheet? Otherwise I could also do that.
I'll open a PR. That's the most sensible option anyways since I have the hardware to test it here on my desk :) The PR will have another commit for the updated documentation to make it clear(er) how universal the driver actually is already.
There is actually code to support the MTD subsystem, but I'm not sure if my small 128 byte EEPROM (it's actually 1KBit instead of 1MBit as stated above) is enough for a LittleFS filesystem 🤣
@maribu I think the drivers/at24cxxx/Makefile.include would be a better place to define the pseudomodule for the M24C01 (or rather M24C%), considering the at24c% pseudomodules are not defined there either. Then we avoid "spamming" the global pseudomodules Makefile. I'll create the PR shortly.
Something else I noticed: I noticed that the AT24CXXX driver is categorized under "Miscellaneous Drivers" instead of "Storage Drivers". It was moved (along other things) from the root level/uncategorized to the Misc. category in 2020 in this PR: https://github.com/RIOT-OS/RIOT/pull/13491
However this issue is probably not the right place to discuss this, even though I'm not sure where a better place would be...
This is my updated example/test code (now running on a nRF52832DK instead of the nRF52840DK, because I needed the latter for something else in the meantime.)
The makefile and code demonstrate that the m24c01 pseudomodule is working. It utilizes the AT24CXXX_PARAMS macro, which is based on the defines derived from the pseudomodule definition.
#include <stdio.h>
#include "at24cxxx.h"
#include "at24cxxx_params.h"
int main(void)
{
at24cxxx_t eeprom_dev;
at24cxxx_params_t eepronm_params = AT24CXXX_PARAMS;
int res = at24cxxx_init(&eeprom_dev, &eepronm_params);
if(res != AT24CXXX_OK) {
puts("Error while initializing the I2C EEPROM.");
} else {
puts("I2C EEPROM initialized successfully.");
}
char data[eeprom_dev.params.eeprom_size];
at24cxxx_read(&eeprom_dev, 0, &data, eeprom_dev.params.eeprom_size);
for(uint8_t i = 0; i < eeprom_dev.params.eeprom_size; i++) {
printf("%02X ", data[i]);
fflush(stdout);
}
printf("\n");
fflush(stdout);
while(1);
return 0;
}
APPLICATION = EEPROMTest2
PROJECT_BASE ?= $(CURDIR)/../..
RIOTBASE ?= $(PROJECT_BASE)/RIOT
# Optionally, provide paths to where external boards and/or modules
# reside, so that they can be included in the app
EXTERNAL_MODULE_DIRS += $(PROJECT_BASE)/modules
EXTERNAL_BOARD_DIRS += $(PROJECT_BASE)/boards
BOARD ?= nrf52dk
# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
DEVELHELP ?= 1
# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1
# Modules to include:
USEMODULE += m24c01
include $(RIOTBASE)/Makefile.include
This is the expected output on the serial terminal from this test program (depending on the content of the EEPROM of course...):
chris@ThinkPias:~/test-riot/apps/EEPROMTest2$ make term
/home/chris/test-riot/RIOT/dist/tools/pyterm/pyterm -p "/dev/ttyACM0" -b "115200"
Twisted not available, please install it if you want to use pyterm's JSON capabilities
2024-04-16 16:11:26,889 # Connect to serial port /dev/ttyACM0
Welcome to pyterm!
Type '/exit' to exit.
2024-04-16 16:11:31,452 # main(): This is RIOT! (Version: 2024.07-devel-20-g61148-HEAD)
2024-04-16 16:11:31,454 # I2C EEPROM initialized successfully.
2024-04-16 16:11:31,501 # 20 1E CE 1F 16 20 DE 20 2E 21 00 00 00 00 00 00 64 1B 3E 1F 3E 1F 3E 1F 3E 1F 00 00 00 00 00 00 00 00 40 02 B1 03 2F 04 40 02 00 00 00 00 00 00 00 00 AE 00 C6 00 AE 00 C8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 08 03 02 BF D7 09 00 00 00 00 00 00 20 20 42 45 43 4B 45 52 41 57 47 37 34 39 43 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
@maribu You can close this issue now :)