diff --git a/drivers/at24cxxx/at24cxxx.c b/drivers/at24cxxx/at24cxxx.c index 53601fda44..d8de2d9022 100644 --- a/drivers/at24cxxx/at24cxxx.c +++ b/drivers/at24cxxx/at24cxxx.c @@ -103,6 +103,42 @@ int _read(const at24cxxx_t *dev, uint32_t pos, void *data, size_t len) return check; } +static +int _write_page(const at24cxxx_t *dev, uint32_t pos, const void *data, size_t len) +{ + int check; + 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, data, len, flags))) { + if (--polls == 0) { + break; + } + xtimer_usleep(AT24CXXX_POLL_DELAY_US); + } + + DEBUG("[at24cxxx] i2c_write_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) { @@ -111,31 +147,9 @@ int _write(const at24cxxx_t *dev, uint32_t pos, const void *data, size_t len) 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); + + check = _write_page(dev, pos, cdata, clen); + if (!check) { len -= clen; pos += clen; @@ -243,6 +257,24 @@ int at24cxxx_write(const at24cxxx_t *dev, uint32_t pos, const void *data, return check; } +int at24cxxx_write_page(const at24cxxx_t *dev, uint32_t page, uint32_t offset, + const void *data, size_t len) +{ + int check; + + assert(offset < DEV_PAGE_SIZE); + + /* write no more than to the end of the current page to prevent wrap-around */ + size_t remaining = DEV_PAGE_SIZE - offset; + len = MIN(len, remaining); + + i2c_acquire(DEV_I2C_BUS); + check = _write_page(dev, page * DEV_PAGE_SIZE + offset, data, len); + i2c_release(DEV_I2C_BUS); + + return check ? check : (int) len; +} + int at24cxxx_set(const at24cxxx_t *dev, uint32_t pos, uint8_t val, size_t len) { diff --git a/drivers/at24cxxx/mtd/mtd.c b/drivers/at24cxxx/mtd/mtd.c index dd36e54a26..1a69469d6c 100644 --- a/drivers/at24cxxx/mtd/mtd.c +++ b/drivers/at24cxxx/mtd/mtd.c @@ -56,6 +56,12 @@ static int _mtd_at24cxxx_write(mtd_dev_t *mtd, const void *src, uint32_t addr, return at24cxxx_write(DEV(mtd), addr, src, size) == AT24CXXX_OK ? 0 : -EIO; } +static int mtd_at24cxxx_write_page(mtd_dev_t *mtd, const void *src, uint32_t page, + uint32_t offset, uint32_t size) +{ + return at24cxxx_write_page(DEV(mtd), page, offset, src, size); +} + static int _mtd_at24cxxx_erase(mtd_dev_t *mtd, uint32_t addr, uint32_t size) { return at24cxxx_clear(DEV(mtd), addr, size) == AT24CXXX_OK ? 0 : -EIO; @@ -72,6 +78,7 @@ const mtd_desc_t mtd_at24cxxx_driver = { .init = _mtd_at24cxxx_init, .read = _mtd_at24cxxx_read, .write = _mtd_at24cxxx_write, + .write_page = mtd_at24cxxx_write_page, .erase = _mtd_at24cxxx_erase, .power = _mtd_at24cxxx_power }; diff --git a/drivers/include/at24cxxx.h b/drivers/include/at24cxxx.h index 5e6874df48..a291550c31 100644 --- a/drivers/include/at24cxxx.h +++ b/drivers/include/at24cxxx.h @@ -129,6 +129,23 @@ int at24cxxx_write_byte(const at24cxxx_t *dev, uint32_t pos, uint8_t data); int at24cxxx_write(const at24cxxx_t *dev, uint32_t pos, const void *data, size_t len); +/** + * @brief Sequentially write @p len bytes to a given @p page. + * The function will write up to the page boundary and then return + * the number of bytes written up to that. + * + * @param[in] dev AT24CXXX device handle + * @param[in] page page of EEPROM memory + * @param[in] offset offset from the start of the page, must be < page size + * @param[in] data write buffer + * @param[in] len requested length to be written + * + * @return number of bytes written on success + * @return error on failure + */ +int at24cxxx_write_page(const at24cxxx_t *dev, uint32_t page, uint32_t offset, + const void *data, size_t len); + /** * @brief Set @p len bytes from a given position @p pos to the * value @p val