Skip to content

Commit

Permalink
drivers/at24cxxx: at24cxxx EEPROM driver
Browse files Browse the repository at this point in the history
  • Loading branch information
fabian18 committed Feb 24, 2020
1 parent faa334e commit 2c77ee4
Show file tree
Hide file tree
Showing 8 changed files with 994 additions and 1 deletion.
8 changes: 7 additions & 1 deletion drivers/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
Expand Down
4 changes: 4 additions & 0 deletions drivers/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions drivers/at24cxxx/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base
288 changes: 288 additions & 0 deletions drivers/at24cxxx/at24cxxx.c
Original file line number Diff line number Diff line change
@@ -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;
}
Loading

0 comments on commit 2c77ee4

Please sign in to comment.