diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index a1a45531e7..f237f87d1c 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -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))) diff --git a/drivers/Makefile.include b/drivers/Makefile.include index 43cb202e0c..f7d8124d21 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -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 diff --git a/drivers/at24cxxx/Makefile b/drivers/at24cxxx/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/drivers/at24cxxx/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/at24cxxx/at24cxxx.c b/drivers/at24cxxx/at24cxxx.c new file mode 100644 index 0000000000..53601fda44 --- /dev/null +++ b/drivers/at24cxxx/at24cxxx.c @@ -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 + * @} + */ + +#include +#include +#include + +#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; +} diff --git a/drivers/at24cxxx/include/at24cxxx_defines.h b/drivers/at24cxxx/include/at24cxxx_defines.h new file mode 100644 index 0000000000..69ea85003e --- /dev/null +++ b/drivers/at24cxxx/include/at24cxxx_defines.h @@ -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 + */ + +#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 */ +/** @} */ diff --git a/drivers/at24cxxx/include/at24cxxx_params.h b/drivers/at24cxxx/include/at24cxxx_params.h new file mode 100644 index 0000000000..0e2a7772f1 --- /dev/null +++ b/drivers/at24cxxx/include/at24cxxx_params.h @@ -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 + */ + +#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 */ +/** @} */ diff --git a/drivers/include/at24cxxx.h b/drivers/include/at24cxxx.h new file mode 100644 index 0000000000..404df6fbe3 --- /dev/null +++ b/drivers/include/at24cxxx.h @@ -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 + * + */ + +#ifndef AT24CXXX_H +#define AT24CXXX_H + +#include + +#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 */ +/** @} */ diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 0bcb61fd26..2dd7267fd0 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -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%