1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #11929 from fabian18/driver-at24cxxx-eeprom

Driver for AT24CXXX EEPROM
This commit is contained in:
benpicco 2020-02-25 18:16:45 +01:00 committed by GitHub
commit aa1c23d4bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1180 additions and 1 deletions

View File

@ -33,6 +33,7 @@ extern "C" {
#define AT24MAC_PARAM_I2C_DEV I2C_DEV(0)
#define AT24MAC_PARAM_I2C_ADDR (0x5E)
#define AT24MAC_PARAM_TYPE AT24MAC4XX
#define AT24CXXX_PARAM_ADDR (0x56)
/** @} */
/**

View File

@ -36,8 +36,14 @@ ifneq (,$(filter at,$(USEMODULE)))
USEMODULE += isrpipe_read_timeout
endif
ifneq (,$(filter at24mac,$(USEMODULE)))
ifneq (,$(filter at24c%,$(USEMODULE)))
FEATURES_REQUIRED += periph_i2c
USEMODULE += xtimer
USEMODULE += at24cxxx
endif
ifneq (,$(filter at24mac,$(USEMODULE)))
USEMODULE += at24cxxx
endif
ifneq (,$(filter at30tse75x,$(USEMODULE)))

View File

@ -20,6 +20,10 @@ ifneq (,$(filter apa102,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/apa102/include
endif
ifneq (,$(filter at24cxxx,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/at24cxxx/include
endif
ifneq (,$(filter at24mac,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/at24mac/include
endif

View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

288
drivers/at24cxxx/at24cxxx.c Normal file
View File

@ -0,0 +1,288 @@
/*
* Copyright (C) 2019 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_at24cxxx
* @{
*
* @file
* @brief Device driver implementation for at24cxxx EEPROM units.
*
* @author Fabian Hüßler <fabian.huessler@ovgu.de>
* @}
*/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "assert.h"
#include "xtimer.h"
#include "at24cxxx_defines.h"
#include "at24cxxx.h"
#ifndef MIN
#define MIN(a, b) ((a) > (b) ? (b) : (a))
#endif
/**
* @brief Calculate x mod y, if y is a power of 2
*/
#define MOD_POW2(x, y) ((x) & ((y) - 1))
/**
* @brief I2C bus number shortcut
*/
#define DEV_I2C_BUS (dev->params.i2c)
/**
* @brief Pin wp shortcut
*/
#define DEV_PIN_WP (dev->params.pin_wp)
/**
* @brief EEPROM size shortcut
*/
#define DEV_EEPROM_SIZE (dev->params.eeprom_size)
/**
* @brief I2C device address shortcut
*/
#define DEV_I2C_ADDR (dev->params.dev_addr)
/**
* @brief Page size shortcut
*/
#define DEV_PAGE_SIZE (dev->params.page_size)
/**
* @brief Max polls shortcut
*/
#define DEV_MAX_POLLS (dev->params.max_polls)
#ifndef AT24CXXX_SET_BUF_SIZE
/**
* @brief Adjust to configure buffer size
*/
#define AT24CXXX_SET_BUF_SIZE (32U)
#endif
static
int _read(const at24cxxx_t *dev, uint32_t pos, void *data, size_t len)
{
int check;
uint8_t polls = DEV_MAX_POLLS;
uint8_t dev_addr;
uint8_t flags = 0;
if (DEV_EEPROM_SIZE > 2048) {
/* 2 bytes word address length if more than 11 bits are
used for addressing */
/* append page address bits to device address (if any) */
dev_addr = (DEV_I2C_ADDR | ((pos & 0xFF0000) >> 16));
pos &= 0xFFFF;
flags = I2C_REG16;
}
else {
/* append page address bits to device address (if any) */
dev_addr = (DEV_I2C_ADDR | ((pos & 0xFF00) >> 8));
pos &= 0xFF;
}
while (-ENXIO == (check = i2c_read_regs(DEV_I2C_BUS, dev_addr,
pos, data, len, flags))) {
if (--polls == 0) {
break;
}
xtimer_usleep(AT24CXXX_POLL_DELAY_US);
}
DEBUG("[at24cxxx] i2c_read_regs(): %d; polls: %d\n", check, polls);
return check;
}
static
int _write(const at24cxxx_t *dev, uint32_t pos, const void *data, size_t len)
{
int check = 0;
const uint8_t *cdata = ((const uint8_t *)data);
while (len) {
size_t clen = MIN(len, DEV_PAGE_SIZE - MOD_POW2(pos, DEV_PAGE_SIZE));
uint8_t polls = DEV_MAX_POLLS;
uint8_t dev_addr;
uint16_t _pos;
uint8_t flags = 0;
if (DEV_EEPROM_SIZE > 2048) {
/* 2 bytes word address length if more than 11 bits are
used for addressing */
/* append page address bits to device address (if any) */
dev_addr = (DEV_I2C_ADDR | ((pos & 0xFF0000) >> 16));
_pos = (pos & 0xFFFF);
flags = I2C_REG16;
}
else {
/* append page address bits to device address (if any) */
dev_addr = (DEV_I2C_ADDR | ((pos & 0xFF00) >> 8));
_pos = pos & 0xFF;
}
while (-ENXIO == (check = i2c_write_regs(DEV_I2C_BUS, dev_addr,
_pos, cdata, clen, flags))) {
if (--polls == 0) {
break;
}
xtimer_usleep(AT24CXXX_POLL_DELAY_US);
}
DEBUG("[at24cxxx] i2c_write_regs(): %d; polls: %d\n", check, polls);
if (!check) {
len -= clen;
pos += clen;
cdata += clen;
}
else {
break;
}
}
return check;
}
static
int _set(const at24cxxx_t *dev, uint32_t pos, uint8_t val, size_t len)
{
int check;
uint8_t set_buffer[AT24CXXX_SET_BUF_SIZE];
memset(set_buffer, val, sizeof(set_buffer));
while (len) {
size_t clen = MIN(sizeof(set_buffer), len);
check = _write(dev, pos, set_buffer, clen);
if (!check) {
len -= clen;
pos += clen;
}
else {
break;
}
}
return check;
}
int at24cxxx_init(at24cxxx_t *dev, const at24cxxx_params_t *params)
{
if (!dev || !params) {
return -EINVAL;
}
dev->params = *params;
if (DEV_PIN_WP != GPIO_UNDEF) {
gpio_init(DEV_PIN_WP, GPIO_OUT);
at24cxxx_disable_write_protect(dev);
}
/* Check I2C bus once */
if (i2c_acquire(DEV_I2C_BUS)) {
return -AT24CXXX_I2C_ERROR;
}
i2c_release(DEV_I2C_BUS);
return AT24CXXX_OK;
}
int at24cxxx_read_byte(const at24cxxx_t *dev, uint32_t pos, void *dest)
{
if (pos >= DEV_EEPROM_SIZE) {
return -ERANGE;
}
i2c_acquire(DEV_I2C_BUS);
int check = _read(dev, pos, dest, 1);
i2c_release(DEV_I2C_BUS);
return check;
}
int at24cxxx_read(const at24cxxx_t *dev, uint32_t pos, void *data,
size_t len)
{
if (pos + len > DEV_EEPROM_SIZE) {
return -ERANGE;
}
int check = AT24CXXX_OK;
if (len) {
i2c_acquire(DEV_I2C_BUS);
check = _read(dev, pos, data, len);
i2c_release(DEV_I2C_BUS);
}
return check;
}
int at24cxxx_write_byte(const at24cxxx_t *dev, uint32_t pos, uint8_t data)
{
if (pos >= DEV_EEPROM_SIZE) {
return -ERANGE;
}
i2c_acquire(DEV_I2C_BUS);
int check = _write(dev, pos, &data, 1);
i2c_release(DEV_I2C_BUS);
return check;
}
int at24cxxx_write(const at24cxxx_t *dev, uint32_t pos, const void *data,
size_t len)
{
if (pos + len > DEV_EEPROM_SIZE) {
return -ERANGE;
}
int check = AT24CXXX_OK;
if (len) {
i2c_acquire(DEV_I2C_BUS);
check = _write(dev, pos, data, len);
i2c_release(DEV_I2C_BUS);
}
return check;
}
int at24cxxx_set(const at24cxxx_t *dev, uint32_t pos, uint8_t val,
size_t len)
{
if (pos + len > DEV_EEPROM_SIZE) {
return -ERANGE;
}
int check = AT24CXXX_OK;
if (len) {
i2c_acquire(DEV_I2C_BUS);
check = _set(dev, pos, val, len);
i2c_release(DEV_I2C_BUS);
}
return check;
}
int at24cxxx_clear(const at24cxxx_t *dev, uint32_t pos, size_t len)
{
return at24cxxx_set(dev, pos, AT24CXXX_CLEAR_BYTE, len);
}
int at24cxxx_erase(const at24cxxx_t *dev)
{
return at24cxxx_clear(dev, 0, DEV_EEPROM_SIZE);
}
int at24cxxx_enable_write_protect(const at24cxxx_t *dev)
{
if (DEV_PIN_WP == GPIO_UNDEF) {
return -ENOTSUP;
}
gpio_set(DEV_PIN_WP);
return AT24CXXX_OK;
}
int at24cxxx_disable_write_protect(const at24cxxx_t *dev)
{
if (DEV_PIN_WP == GPIO_UNDEF) {
return -ENOTSUP;
}
gpio_clear(DEV_PIN_WP);
return AT24CXXX_OK;
}

View File

@ -0,0 +1,388 @@
/*
* Copyright (C) 2019 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_at24cxxx
* @{
*
* @file
* @brief Constants for AT24CXXX EEPROM devices.
*
* @author Fabian Hüßler <fabian.huessler@ovgu.de>
*/
#ifndef AT24CXXX_DEFINES_H
#define AT24CXXX_DEFINES_H
#include "kernel_defines.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Delay between two poll attempts
*/
#define AT24CXXX_POLL_DELAY_US (1000UL)
/**
* @brief Clear byte
*/
#define AT24CXXX_CLEAR_BYTE (0x00)
/**
* @brief AT24CXXX default device address
*
* Different AT24CXXX types may have a different address byte
* format. Some may include a portion of the data word address.
* Some may have a 0, 1, 2 or 3 bit wide address space.
* But all types have a 7 bit I2C address which starts with
* 1010. [1, 0, 1, 0, ?, ?, ?, r/w]
* \__7 bit address__/
*/
#define AT24CXXX_DEF_DEV_ADDR (0x50)
/**
* @name AT24C01A constants
* @{
*/
/**
* @brief 128 byte memory
*/
#define AT24C01A_EEPROM_SIZE (128U)
/**
* @brief 16 pages of 8 bytes each
*/
#define AT24C01A_PAGE_SIZE (8U)
/**
* @brief Delay to complete write operation
*/
#define AT24C01A_PAGE_WRITE_DELAY_US (5000U)
/**
* @brief Number of poll attempts
*/
#define AT24C01A_MAX_POLLS (1 + (AT24C01A_PAGE_WRITE_DELAY_US \
/ AT24CXXX_POLL_DELAY_US))
/** @} */
/**
* @name AT24C02 constants
* @{
*/
/**
* @brief 256 byte memory
*/
#define AT24C02_EEPROM_SIZE (256U)
/**
* @brief 32 pages of 8 bytes
*/
#define AT24C02_PAGE_SIZE (8U)
/**
* @brief Delay to complete write operation
*/
#define AT24C02_PAGE_WRITE_DELAY_US (5000U)
/**
* @brief Number of poll attempts
*/
#define AT24C02_MAX_POLLS (1 + (AT24C02_PAGE_WRITE_DELAY_US \
/ AT24CXXX_POLL_DELAY_US))
/** @} */
/**
* @name AT24C04 constants
* @{
*/
/**
* @brief 512 byte memory
*/
#define AT24C04_EEPROM_SIZE (512U)
/**
* @brief 32 pages of 16 bytes each
*/
#define AT24C04_PAGE_SIZE (16U)
/**
* @brief Delay to complete write operation
*/
#define AT24C04_PAGE_WRITE_DELAY_US (5000U)
/**
* @brief Number of poll attempts
*/
#define AT24C04_MAX_POLLS (1 + (AT24C04_PAGE_WRITE_DELAY_US \
/ AT24CXXX_POLL_DELAY_US))
/** @} */
/**
* @name AT24C08A constants
* @{
*/
/**
* @brief 1 kiB memory
*/
#define AT24C08A_EEPROM_SIZE (1024U)
/**
* @brief 64 pages of 16 bytes each
*/
#define AT24C08A_PAGE_SIZE (16U)
/**
* @brief Delay to complete write operation
*/
#define AT24C08A_PAGE_WRITE_DELAY_US (5000U)
/**
* @brief Number of poll attempts
*/
#define AT24C08A_MAX_POLLS (1 + (AT24C08A_PAGE_WRITE_DELAY_US \
/ AT24CXXX_POLL_DELAY_US))
/** @} */
/**
* @name AT24C16A constants
* @{
*/
/**
* @brief 2 kiB memory
*/
#define AT24C16A_EEPROM_SIZE (2048U)
/**
* @brief 128 pages of 16 bytes each
*/
#define AT24C16A_PAGE_SIZE (16U)
/**
* @brief Delay to complete write operation
*/
#define AT24C16A_PAGE_WRITE_DELAY_US (5000U)
/**
* @brief Number of poll attempts
*/
#define AT24C16A_MAX_POLLS (1 + (AT24C16A_PAGE_WRITE_DELAY_US \
/ AT24CXXX_POLL_DELAY_US))
/** @} */
/**
* @name AT24C32 constants
* @{
*/
/**
* @brief 4 kiB memory
*/
#define AT24C32_EEPROM_SIZE (4096U)
/**
* @brief 256 pages of 32 bytes each
*/
#define AT24C32_PAGE_SIZE (32U)
/**
* @brief Delay to complete write operation
*/
#define AT24C32_PAGE_WRITE_DELAY_US (10000U)
/**
* @brief Number of poll attempts
*/
#define AT24C32_MAX_POLLS (1 + (AT24C32_PAGE_WRITE_DELAY_US \
/ AT24CXXX_POLL_DELAY_US))
/** @} */
/**
* @name AT24C64 constants
* @{
*/
/**
* @brief 8 kiB memory
*/
#define AT24C64_EEPROM_SIZE (8192U)
/**
* @brief 256 pages of 32 bytes each
*/
#define AT24C64_PAGE_SIZE (32U)
/**
* @brief Delay to complete write operation
*/
#define AT24C64_PAGE_WRITE_DELAY_US (10000U)
/**
* @brief Number of poll attempts
*/
#define AT24C64_MAX_POLLS (1 + (AT24C64_PAGE_WRITE_DELAY_US \
/ AT24CXXX_POLL_DELAY_US))
/** @} */
/**
* @name AT24C128 constants
* @{
*/
/**
* @brief 16 kiB memory
*/
#define AT24C128_EEPROM_SIZE (16384U)
/**
* @brief 256 pages of 64 bytes each
*/
#define AT24C128_PAGE_SIZE (64U)
/**
* @brief Delay to complete write operation
*/
#define AT24C128_PAGE_WRITE_DELAY_US (5000U)
/**
* @brief Number of poll attempts
*/
#define AT24C128_MAX_POLLS (1 + (AT24C128_PAGE_WRITE_DELAY_US \
/ AT24CXXX_POLL_DELAY_US))
/** @} */
/**
* @name AT24C256 constants
* @{
*/
/**
* @brief 32 kiB memory
*/
#define AT24C256_EEPROM_SIZE (32768U)
/**
* @brief 512 pages of 64 bytes each
*/
#define AT24C256_PAGE_SIZE (64U)
/**
* @brief Delay to complete write operation
*/
#define AT24C256_PAGE_WRITE_DELAY_US (5000U)
/**
* @brief Number of poll attempts
*/
#define AT24C256_MAX_POLLS (1 + (AT24C256_PAGE_WRITE_DELAY_US \
/ AT24CXXX_POLL_DELAY_US))
/** @} */
/**
* @name AT24C512 constants
* @{
*/
/**
* @brief 64 kiB memory
*/
#define AT24C512_EEPROM_SIZE (65536U)
/**
* @brief 512 pages of 128 bytes each
*/
#define AT24C512_PAGE_SIZE (128U)
/**
* @brief Delay to complete write operation
*/
#define AT24C512_PAGE_WRITE_DELAY_US (5000U)
/**
* @brief Number of poll attempts
*/
#define AT24C512_MAX_POLLS (1 + (AT24C512_PAGE_WRITE_DELAY_US \
/ AT24CXXX_POLL_DELAY_US))
/** @} */
/**
* @name AT24C1024 constants
* @{
*/
/**
* @brief 128 kiB memory
*/
#define AT24C1024_EEPROM_SIZE (131072U)
/**
* @brief 512 pages of 256 bytes each
*/
#define AT24C1024_PAGE_SIZE (256U)
/**
* @brief Delay to complete write operation
*/
#define AT24C1024_PAGE_WRITE_DELAY_US (5000U)
/**
* @brief Number of poll attempts
*/
#define AT24C1024_MAX_POLLS (1 + (AT24C1024_PAGE_WRITE_DELAY_US \
/ AT24CXXX_POLL_DELAY_US))
/** @} */
/**
* @name AT24MAC402/602 constants
* @{
*/
/**
* @brief 256 byte memory
*/
#define AT24MAC_EEPROM_SIZE (256U)
/**
* @brief 16 pages of 16 bytes each
*/
#define AT24MAC_PAGE_SIZE (16U)
/**
* @brief Delay to complete write operation
*/
#define AT24MAC_PAGE_WRITE_DELAY_US (5000U)
/**
* @brief Number of poll attempts
*/
#define AT24MAC_MAX_POLLS (1 + (AT24MAC_PAGE_WRITE_DELAY_US \
/ AT24CXXX_POLL_DELAY_US))
/** @} */
/**
* @name Set constants depending on module
* @{
*/
#if IS_USED(MODULE_AT24C1024)
#define AT24CXXX_EEPROM_SIZE (AT24C1024_EEPROM_SIZE)
#define AT24CXXX_PAGE_SIZE (AT24C1024_PAGE_SIZE)
#define AT24CXXX_MAX_POLLS (AT24C1024_MAX_POLLS)
#elif IS_USED(MODULE_AT24C512)
#define AT24CXXX_EEPROM_SIZE (AT24C512_EEPROM_SIZE)
#define AT24CXXX_PAGE_SIZE (AT24C512_PAGE_SIZE)
#define AT24CXXX_MAX_POLLS (AT24C512_MAX_POLLS)
#elif IS_USED(MODULE_AT24C256)
#define AT24CXXX_EEPROM_SIZE (AT24C256_EEPROM_SIZE)
#define AT24CXXX_PAGE_SIZE (AT24C256_PAGE_SIZE)
#define AT24CXXX_MAX_POLLS (AT24C256_MAX_POLLS)
#elif IS_USED(MODULE_AT24C128)
#define AT24CXXX_EEPROM_SIZE (AT24C128_EEPROM_SIZE)
#define AT24CXXX_PAGE_SIZE (AT24C128_PAGE_SIZE)
#define AT24CXXX_MAX_POLLS (AT24C128_MAX_POLLS)
#elif IS_USED(MODULE_AT24C64)
#define AT24CXXX_EEPROM_SIZE (AT24C64_EEPROM_SIZE)
#define AT24CXXX_PAGE_SIZE (AT24C64_PAGE_SIZE)
#define AT24CXXX_MAX_POLLS (AT24C64_MAX_POLLS)
#elif IS_USED(MODULE_AT24C32)
#define AT24CXXX_EEPROM_SIZE (AT24C32_EEPROM_SIZE)
#define AT24CXXX_PAGE_SIZE (AT24C32_PAGE_SIZE)
#define AT24CXXX_MAX_POLLS (AT24C32_MAX_POLLS)
#elif IS_USED(MODULE_AT24C16A)
#define AT24CXXX_EEPROM_SIZE (AT24C16A_EEPROM_SIZE)
#define AT24CXXX_PAGE_SIZE (AT24C16A_PAGE_SIZE)
#define AT24CXXX_MAX_POLLS (AT24C16A_MAX_POLLS)
#elif IS_USED(MODULE_AT24C08A)
#define AT24CXXX_EEPROM_SIZE (AT24C08A_EEPROM_SIZE)
#define AT24CXXX_PAGE_SIZE (AT24C08A_PAGE_SIZE)
#define AT24CXXX_MAX_POLLS (AT24C08A_MAX_POLLS)
#elif IS_USED(MODULE_AT24C04)
#define AT24CXXX_EEPROM_SIZE (AT24C04_EEPROM_SIZE)
#define AT24CXXX_PAGE_SIZE (AT24C04_PAGE_SIZE)
#define AT24CXXX_MAX_POLLS (AT24C04_MAX_POLLS)
#elif IS_USED(MODULE_AT24C02)
#define AT24CXXX_EEPROM_SIZE (AT24C02_EEPROM_SIZE)
#define AT24CXXX_PAGE_SIZE (AT24C02_PAGE_SIZE)
#define AT24CXXX_MAX_POLLS (AT24C02_MAX_POLLS)
#elif IS_USED(MODULE_AT24C01A)
#define AT24CXXX_EEPROM_SIZE (AT24C01A_EEPROM_SIZE)
#define AT24CXXX_PAGE_SIZE (AT24C01A_PAGE_SIZE)
#define AT24CXXX_MAX_POLLS (AT24C01A_MAX_POLLS)
#elif IS_USED(MODULE_AT24MAC)
#define AT24CXXX_EEPROM_SIZE (AT24MAC_EEPROM_SIZE)
#define AT24CXXX_PAGE_SIZE (AT24MAC_PAGE_SIZE)
#define AT24CXXX_MAX_POLLS (AT24MAC_MAX_POLLS)
#else /* minimal */
#define AT24CXXX_EEPROM_SIZE (128U) /**< EEPROM size */
#define AT24CXXX_PAGE_SIZE (4U) /**< page size */
#define AT24CXXX_MAX_POLLS (6U) /**< maximum poll attempts */
#endif
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* AT24CXXX_DEFINES_H */
/** @} */

View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2019 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_at24cxxx
* @{
*
* @file
* @brief Default configuration for AT24CXXX
*
* @author Fabian Hüßler <fabian.huessler@ovgu.de>
*/
#ifndef AT24CXXX_PARAMS_H
#define AT24CXXX_PARAMS_H
#include "board.h"
#include "periph/gpio.h"
#include "at24cxxx_defines.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Set default configuration parameters for the AT24CXXX driver
* @{
*/
#ifndef AT24CXXX_PARAM_I2C
/**
* @brief I2C bus the EEPROM is connected to
*/
#define AT24CXXX_PARAM_I2C (I2C_DEV(0))
#endif
#ifndef AT24CXXX_PARAM_ADDR
/**
* @brief I2C address of the EEPROM device
*/
#define AT24CXXX_PARAM_ADDR (AT24CXXX_DEF_DEV_ADDR)
#endif
#ifndef AT24CXXX_PARAM_PIN_WP
/**
* @brief EEPROM write protect pin
*/
#define AT24CXXX_PARAM_PIN_WP (GPIO_UNDEF)
#endif
#ifndef AT24CXXX_PARAM_EEPROM_SIZE
/**
* @brief EEPROM size
*/
#define AT24CXXX_PARAM_EEPROM_SIZE (AT24CXXX_EEPROM_SIZE)
#endif
#ifndef AT24CXXX_PARAM_PAGE_SIZE
/**
* @brief Page size
*/
#define AT24CXXX_PARAM_PAGE_SIZE (AT24CXXX_PAGE_SIZE)
#endif
#ifndef AT24CXXX_PARAM_MAX_POLLS
/**
* @brief Maximum poll poll
*/
#define AT24CXXX_PARAM_MAX_POLLS (AT24CXXX_MAX_POLLS)
#endif
#ifndef AT24CXXX_PARAMS
/**
* @brief Default device configuration parameters
*/
#define AT24CXXX_PARAMS { \
.i2c = AT24CXXX_PARAM_I2C, \
.dev_addr = AT24CXXX_PARAM_ADDR, \
.pin_wp = AT24CXXX_PARAM_PIN_WP, \
.eeprom_size = AT24CXXX_PARAM_EEPROM_SIZE, \
.page_size = AT24CXXX_PARAM_PAGE_SIZE, \
.max_polls = AT24CXXX_PARAM_MAX_POLLS \
}
#endif
/** @} */
/**
* @brief Number of configured AT24CXXX EEPROM devices
*/
#define AT24CXXX_NUMOF ARRAY_SIZE(at24cxxx_params)
/**
* @brief AT24CXXX configuration
*/
static const at24cxxx_params_t at24cxxx_params[] =
{
AT24CXXX_PARAMS
};
#ifdef __cplusplus
}
#endif
#endif /* AT24CXXX_PARAMS_H */
/** @} */

199
drivers/include/at24cxxx.h Normal file
View File

@ -0,0 +1,199 @@
/*
* Copyright (C) 2019 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup drivers_at24cxxx AT24CXXX EEPROM unit
* @brief Device driver interface for the AT24CXXX EEPROM units
*
* @{
*
* @file
* @brief Device driver interface for AT24CXXX EEPROM units.
*
* @author Fabian Hüßler <fabian.huessler@ovgu.de>
*
*/
#ifndef AT24CXXX_H
#define AT24CXXX_H
#include <stdint.h>
#include "periph/gpio.h"
#include "periph/i2c.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Return values
*/
enum {
AT24CXXX_OK,
AT24CXXX_I2C_ERROR
};
/**
* @brief Struct that holds initialization parameters
*/
typedef struct at24cxxx_params {
i2c_t i2c; /**< I2C bus number */
gpio_t pin_wp; /**< write protect pin */
uint32_t eeprom_size; /**< EEPROM memory capacity */
uint8_t dev_addr; /**< I2C device address */
uint8_t page_size; /**< page size */
uint8_t max_polls; /**< number of ACK poll attempts */
} at24cxxx_params_t;
/**
* @brief Struct that represents an AT24CXXX device
*/
typedef struct {
at24cxxx_params_t params; /**< parameters */
} at24cxxx_t;
/**
* @brief Initialize an AT24CXXX device handle with AT24CXXX parameters
*
* @param[in, out] dev AT24CXXX device handle
* @param[in] params AT24CXXX parameters
*
* @return AT24CXXX_OK on success
* @return -AT24CXXX_I2C_ERROR if i2c could not be acquired
* @return -EINVAL if input parameters are NULL
*/
int at24cxxx_init(at24cxxx_t *dev, const at24cxxx_params_t *params);
/**
* @brief Read a byte at a given position @p pos
*
* @param[in] dev AT24CXXX device handle
* @param[in] pos Position in EEPROM memory
* @param[out] dest Read byte
*
* @return AT24CXXX_OK on success
* @return -ERANGE if @p pos is out of bounds
* @return @see i2c_read_regs
*/
int at24cxxx_read_byte(const at24cxxx_t *dev, uint32_t pos, void *dest);
/**
* @brief Sequentially read @p len bytes from a given position @p pos
*
* @param[in] dev AT24CXXX device handle
* @param[in] pos Position in EEPROM memory
* @param[out] data Read buffer
* @param[in] len Requested length to be read
*
* @return AT24CXXX_OK on success
* @return -ERANGE if @p pos + @p len is out of bounds
* @return @see i2c_read_regs
*/
int at24cxxx_read(const at24cxxx_t *dev, uint32_t pos, void *data,
size_t len);
/**
* @brief Write a byte at a given position @p pos
*
* @param[in] dev AT24CXXX device handle
* @param[in] pos Position in EEPROM memory
* @param[in] data Value to be written
*
* @return AT24CXXX_OK on success
* @return -ERANGE if @p pos is out of bounds
* @return @see i2c_write_regs
*/
int at24cxxx_write_byte(const at24cxxx_t *dev, uint32_t pos, uint8_t data);
/**
* @brief Sequentially write @p len bytes from a given position @p pos
*
* Writing is performed in chunks of size AT24CXXX_PAGE_SIZE.
*
* @param[in] dev AT24CXXX device handle
* @param[in] pos Position in EEPROM memory
* @param[in] data Write buffer
* @param[in] len Requested length to be written
*
* @return AT24CXXX_OK on success
* @return -ERANGE if @p pos + @p len is out of bounds
* @return @see i2c_write_regs
*/
int at24cxxx_write(const at24cxxx_t *dev, uint32_t pos, const void *data,
size_t len);
/**
* @brief Set @p len bytes from a given position @p pos to the
* value @p val
*
* Writing is performed in chunks of size AT24CXXX_SET_BUFFER_SIZE.
*
* @param[in] dev AT24CXXX device handle
* @param[in] pos Position in EEPROM memory
* @param[in] val Value to be set
* @param[in] len Requested length to be written
*
* @return AT24CXXX_OK on success
* @return -ERANGE if @p pos + @p len is out of bounds
* @return @see i2c_write_byte
*/
int at24cxxx_set(const at24cxxx_t *dev, uint32_t pos, uint8_t val,
size_t len);
/**
* @brief Set @p len bytes from position @p pos to
* AT24CXXX_CLEAR_BYTE
*
* This is a wrapper around @see at24cxxx_set.
*
* @param[in] dev AT24CXXX device handle
* @param[in] pos Position in EEPROM memory
* @param[in] len Requested length to be written
*
* @return @see at24cxxx_set
*/
int at24cxxx_clear(const at24cxxx_t *dev, uint32_t pos, size_t len);
/**
* @brief Set the entire EEPROM memory to AT24CXXX_CLEAR_BYTE
*
* This is a wrapper around @see at24cxxx_clear.
*
* @param[in] dev AT24CXXX device handle
*
* @return @see at24cxxx_set
*/
int at24cxxx_erase(const at24cxxx_t *dev);
/**
* @brief Enable write protection
*
* @param[in] dev AT24CXXX device handle
*
* @return AT24CXXX_OK on success
* @return -ENOTSUP if pin_wp was initialized with GPIO_UNDEF
*/
int at24cxxx_enable_write_protect(const at24cxxx_t *dev);
/**
* @brief Disable write protection
*
* @param[in] dev AT24CXXX device handle
*
* @return AT24CXXX_OK on success
* @return -ENOTSUP if pin_wp was initialized with GPIO_UNDEF
*/
int at24cxxx_disable_write_protect(const at24cxxx_t *dev);
#ifdef __cplusplus
}
#endif
#endif /* AT24CXXX_H */
/** @} */

View File

@ -1,4 +1,5 @@
PSEUDOMODULES += at_urc
PSEUDOMODULES += at24c%
PSEUDOMODULES += can_mbox
PSEUDOMODULES += can_pm
PSEUDOMODULES += can_raw
@ -100,6 +101,9 @@ NO_PSEUDOMODULES += suit_v4
# print ascii representation in function od_hex_dump()
PSEUDOMODULES += od_string
# handle at24cxxx being a distinct module
NO_PSEUDOMODULES += at24cxxx
# include variants of the AT86RF2xx drivers as pseudo modules
PSEUDOMODULES += at86rf23%
PSEUDOMODULES += at86rf21%

View File

@ -0,0 +1,5 @@
include ../Makefile.tests_common
USEMODULE += at24c256
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,180 @@
/*
* Copyright (C) 2019 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief AT24CXXX test application
*
* Tested with bluepill and AT24C256
*
* @}
*/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "xtimer.h"
#include "at24cxxx.h"
#include "at24cxxx_params.h"
#ifndef AT24CXXX_ERASE
#define AT24CXXX_ERASE (0)
#endif
#define WRITE_BYTE_POSITION (12U)
#define WRITE_BYTE_CHARACTER 'A'
#define WRITE_POSITION (AT24CXXX_EEPROM_SIZE - \
3 * AT24CXXX_PAGE_SIZE - 4)
#define WRITE_CHARACTERS { 'B', 'E', 'E', 'R', '4', \
'F', 'R', 'E', 'E', '\0' }
#define SET_POSITION (AT24CXXX_EEPROM_SIZE - \
7 * AT24CXXX_PAGE_SIZE - 4)
#define SET_CHARACTER 'G'
#define SET_LEN (20U)
int main(void)
{
puts("Starting tests for module at24cxxx");
at24cxxx_t at24cxxx_dev;
int check;
printf("EEPROM size: %u byte\n", AT24CXXX_EEPROM_SIZE);
printf("Page size : %u byte\n", AT24CXXX_PAGE_SIZE);
/* Test: Init */
check = at24cxxx_init(&at24cxxx_dev, &at24cxxx_params[0]);
if (check != AT24CXXX_OK) {
printf("[FAILURE] at24cxxx_init: (%d)\n", check);
return 1;
}
else {
puts("[SUCCESS] at24cxxx_init");
}
/* erase EEPROM to exclude side effects from prior test runs */
#if AT24CXXX_ERASE
check = at24cxxx_erase(&at24cxxx_dev);
if (check != AT24CXXX_OK) {
printf("[FAILURE] at24cxxx_erase: %d (EEPROM size = %" PRId32 ")\n",
check, at24cxxx_dev.params.eeprom_size);
return 1;
}
else {
puts("[SUCCESS] at24cxxx_erase");
}
#endif
/* Test: Write/Read Byte */
check = at24cxxx_write_byte(&at24cxxx_dev, WRITE_BYTE_POSITION,
WRITE_BYTE_CHARACTER);
if (check != AT24CXXX_OK) {
printf("[FAILURE] at24cxxx_write_byte: %d\n", check);
return 1;
}
else {
puts("[SUCCESS] at24cxxx_write_byte");
}
uint8_t c;
check = at24cxxx_read_byte(&at24cxxx_dev, WRITE_BYTE_POSITION, &c);
if (check < 0) {
printf("[FAILURE] at24cxxx_read_byte: %d\n", check);
return 1;
}
else {
puts("[SUCCESS] at24cxxx_read_byte");
}
if (c != WRITE_BYTE_CHARACTER) {
printf("[FAILURE] write_byte/read_byte: (%" PRId8 " != %d)\n", c,
WRITE_BYTE_CHARACTER);
return 1;
}
else {
puts("[SUCCESS] write_byte/read_byte");
}
/* Test: Write */
uint8_t expected_write_data[] = WRITE_CHARACTERS;
check = at24cxxx_write(&at24cxxx_dev, WRITE_POSITION, expected_write_data,
sizeof(expected_write_data));
if (check != AT24CXXX_OK) {
printf("[FAILURE] at24cxxx_write: %d (size = %zu)\n", check,
sizeof(expected_write_data));
return 1;
}
else {
puts("[SUCCESS] at24cxxx_write");
}
/* Test: Read */
uint8_t actual_write_data[sizeof(expected_write_data)];
check = at24cxxx_read(&at24cxxx_dev, WRITE_POSITION, actual_write_data,
sizeof(actual_write_data));
if (check != AT24CXXX_OK) {
printf("[FAILURE] at24cxxx_read: %d\n", check);
return 1;
}
else {
puts("[SUCCESS] at24cxxx_read");
}
if (memcmp(actual_write_data, expected_write_data,
sizeof(actual_write_data)) != 0) {
printf("[FAILURE] write/read: (%s != %s)\n", actual_write_data,
expected_write_data);
return 1;
}
else {
puts("[SUCCESS] write/read");
}
/* Test: Set */
uint8_t expected_set_data[SET_LEN];
memset(expected_set_data, SET_CHARACTER, SET_LEN);
uint8_t actual_set_data[sizeof(expected_set_data)];
check = at24cxxx_set(&at24cxxx_dev, SET_POSITION, SET_CHARACTER, SET_LEN);
if (check != AT24CXXX_OK) {
printf("[FAILURE] at24cxxx_set: %d (size = %u)\n", check, SET_LEN);
return 1;
}
else {
puts("[SUCCESS] at24cxxx_set");
}
check = at24cxxx_read(&at24cxxx_dev, SET_POSITION,
actual_set_data, SET_LEN);
if (check != AT24CXXX_OK) {
printf("[FAILURE] set/read: %d\n", check);
return 1;
}
else if (memcmp(actual_set_data, expected_set_data, SET_LEN) != 0) {
printf("[FAILURE] set/read: (%s != %s)\n", actual_set_data,
expected_set_data);
return 1;
}
else {
puts("[SUCCESS] set/read");
}
puts("Finished tests for module at24cxxx");
return 0;
}