RIOT icon indicating copy to clipboard operation
RIOT copied to clipboard

Driver for M24C01 EEPROM

Open leocordier opened this issue 2 years ago • 1 comments

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

leocordier avatar Dec 20 '23 12:12 leocordier

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.

maribu avatar Feb 15 '24 18:02 maribu

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.

crasbe avatar Apr 12 '24 15:04 crasbe

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.

crasbe avatar Apr 15 '24 11:04 crasbe

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 avatar Apr 15 '24 11:04 crasbe

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

maribu avatar Apr 15 '24 12:04 maribu

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 🤣

PXL_20240415_114645806

crasbe avatar Apr 15 '24 13:04 crasbe

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

crasbe avatar Apr 16 '24 13:04 crasbe

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

crasbe avatar Apr 16 '24 14:04 crasbe

@maribu You can close this issue now :)

crasbe avatar Apr 17 '24 18:04 crasbe