From 9028916e8b89dcf9f8b41cefbd075efdf80cbac6 Mon Sep 17 00:00:00 2001 From: Fabien Poussin Date: Tue, 16 Feb 2016 00:22:40 +0100 Subject: EEPROM: Initial commit --- os/hal/src/ee24xx.c | 353 +++++++++++++++++++++++++++++++++++++++++++++ os/hal/src/ee25xx.c | 404 ++++++++++++++++++++++++++++++++++++++++++++++++++++ os/hal/src/eeprom.c | 197 +++++++++++++++++++++++++ 3 files changed, 954 insertions(+) create mode 100644 os/hal/src/ee24xx.c create mode 100644 os/hal/src/ee25xx.c create mode 100644 os/hal/src/eeprom.c (limited to 'os/hal/src') diff --git a/os/hal/src/ee24xx.c b/os/hal/src/ee24xx.c new file mode 100644 index 0000000..c89635f --- /dev/null +++ b/os/hal/src/ee24xx.c @@ -0,0 +1,353 @@ +/* + Copyright (c) 2013 Timon Wong + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* + Copyright 2012 Uladzimir Pylinski aka barthess. + You may use this work without restrictions, as long as this notice is included. + The work is provided "as is" without warranty of any kind, neither express nor implied. +*/ + +/***************************************************************************** + * DATASHEET NOTES + ***************************************************************************** +Write cycle time (byte or page) - 5 ms + +Note: + Page write operations are limited to writing bytes within a single physical + page, regardless of the number of bytes actually being written. Physical page + boundaries start at addresses that are integer multiples of the page buffer + size (or page size and end at addresses that are integer multiples of + [page size]. If a Page Write command attempts to write across a physical + page boundary, the result is that the data wraps around to the beginning of + the current page (overwriting data previously stored there), instead of + being written to the next page as might be expected. +*********************************************************************/ + +#include "ee24xx.h" +#include + +#if (defined(HAL_USE_EEPROM) && HAL_USE_EEPROM && EEPROM_USE_EE24XX) || defined(__DOXYGEN__) + +/* + ****************************************************************************** + * DEFINES + ****************************************************************************** + */ +/* +#if defined(SAM7_PLATFORM) +#define EEPROM_I2C_CLOCK (MCK / (((i2cp->config->cwgr & 0xFF) + ((i2cp->config->cwgr >> 8) & 0xFF)) * (1 << ((i2cp->config->cwgr >> 16) & 7)) + 6)) +#else +#define EEPROM_I2C_CLOCK (i2cp->config->clock_speed) +#endif +*/ +#define EEPROM_I2C_CLOCK 400000 + +/* + ****************************************************************************** + * EXTERNS + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL VARIABLES + ****************************************************************************** + */ + +/* + ******************************************************************************* + * LOCAL FUNCTIONS + ******************************************************************************* + */ +/** + * @brief Split one uint16_t address to two uint8_t. + * + * @param[in] txbuf pointer to driver transmit buffer + * @param[in] addr uint16_t address + */ +#define eeprom_split_addr(txbuf, addr){ \ + (txbuf)[0] = ((uint8_t)((addr >> 8) & 0xFF)); \ + (txbuf)[1] = ((uint8_t)(addr & 0xFF)); \ + } + +/* + ******************************************************************************* + * EXPORTED FUNCTIONS + ******************************************************************************* + */ + +/** + * @brief Calculates requred timeout. + */ +static systime_t calc_timeout(I2CDriver *i2cp, size_t txbytes, size_t rxbytes) { + (void)i2cp; + const uint32_t bitsinbyte = 10; + uint32_t tmo; + tmo = ((txbytes + rxbytes + 1) * bitsinbyte * 1000); + tmo /= EEPROM_I2C_CLOCK; + tmo += 10; /* some additional milliseconds to be safer */ + return MS2ST(tmo); +} + +/** + * @brief EEPROM read routine. + * + * @param[in] eepcfg pointer to configuration structure of eeprom file + * @param[in] offset addres of 1-st byte to be read + * @param[in] data pointer to buffer with data to be written + * @param[in] len number of bytes to be red + */ +static msg_t eeprom_read(const I2CEepromFileConfig *eepcfg, + uint32_t offset, uint8_t *data, size_t len) { + + msg_t status = MSG_RESET; + systime_t tmo = calc_timeout(eepcfg->i2cp, 2, len); + + osalDbgAssert(((len <= eepcfg->size) && ((offset + len) <= eepcfg->size)), + "out of device bounds"); + + eeprom_split_addr(eepcfg->write_buf, (offset + eepcfg->barrier_low)); + +#if I2C_USE_MUTUAL_EXCLUSION + i2cAcquireBus(eepcfg->i2cp); +#endif + + status = i2cMasterTransmitTimeout(eepcfg->i2cp, eepcfg->addr, + eepcfg->write_buf, 2, data, len, tmo); + +#if I2C_USE_MUTUAL_EXCLUSION + i2cReleaseBus(eepcfg->i2cp); +#endif + + return status; +} + +/** + * @brief EEPROM write routine. + * @details Function writes data to EEPROM. + * @pre Data must be fit to single EEPROM page. + * + * @param[in] eepcfg pointer to configuration structure of eeprom file + * @param[in] offset addres of 1-st byte to be write + * @param[in] data pointer to buffer with data to be written + * @param[in] len number of bytes to be written + */ +static msg_t eeprom_write(const I2CEepromFileConfig *eepcfg, uint32_t offset, + const uint8_t *data, size_t len) { + msg_t status = MSG_RESET; + systime_t tmo = calc_timeout(eepcfg->i2cp, (len + 2), 0); + + osalDbgAssert(((len <= eepcfg->size) && ((offset + len) <= eepcfg->size)), + "out of device bounds"); + osalDbgAssert((((offset + eepcfg->barrier_low) / eepcfg->pagesize) == + (((offset + eepcfg->barrier_low) + len - 1) / eepcfg->pagesize)), + "data can not be fitted in single page"); + + /* write address bytes */ + eeprom_split_addr(eepcfg->write_buf, (offset + eepcfg->barrier_low)); + /* write data bytes */ + memcpy(&(eepcfg->write_buf[2]), data, len); + +#if I2C_USE_MUTUAL_EXCLUSION + i2cAcquireBus(eepcfg->i2cp); +#endif + + status = i2cMasterTransmitTimeout(eepcfg->i2cp, eepcfg->addr, + eepcfg->write_buf, (len + 2), NULL, 0, tmo); + +#if I2C_USE_MUTUAL_EXCLUSION + i2cReleaseBus(eepcfg->i2cp); +#endif + + /* wait until EEPROM process data */ + chThdSleep(eepcfg->write_time); + + return status; +} + +/** + * @brief Determines and returns size of data that can be processed + */ +static size_t __clamp_size(void *ip, size_t n) { + + if (((size_t)eepfs_getposition(ip) + n) > (size_t)eepfs_getsize(ip)) + return eepfs_getsize(ip) - eepfs_getposition(ip); + else + return n; +} + +/** + * @brief Write data that can be fitted in one page boundary + */ +static void __fitted_write(void *ip, const uint8_t *data, size_t len, uint32_t *written) { + + msg_t status = MSG_RESET; + + osalDbgAssert(len != 0, "something broken in hi level part"); + + status = eeprom_write(((I2CEepromFileStream *)ip)->cfg, + eepfs_getposition(ip), data, len); + if (status == MSG_OK) { + *written += len; + eepfs_lseek(ip, eepfs_getposition(ip) + len); + } +} + +/** + * @brief Write data to EEPROM. + * @details Only one EEPROM page can be written at once. So fucntion + * splits large data chunks in small EEPROM transactions if needed. + * @note To achieve the maximum effectivity use write operations + * aligned to EEPROM page boundaries. + */ +static size_t write(void *ip, const uint8_t *bp, size_t n) { + + size_t len = 0; /* bytes to be written at one trasaction */ + uint32_t written; /* total bytes successfully written */ + uint16_t pagesize; + uint32_t firstpage; + uint32_t lastpage; + + osalDbgCheck((ip != NULL) && (((EepromFileStream *)ip)->vmt != NULL)); + + if (n == 0) + return 0; + + n = __clamp_size(ip, n); + if (n == 0) + return 0; + + pagesize = ((EepromFileStream *)ip)->cfg->pagesize; + firstpage = (((EepromFileStream *)ip)->cfg->barrier_low + + eepfs_getposition(ip)) / pagesize; + lastpage = (((EepromFileStream *)ip)->cfg->barrier_low + + eepfs_getposition(ip) + n - 1) / pagesize; + + written = 0; + /* data fitted in single page */ + if (firstpage == lastpage) { + len = n; + __fitted_write(ip, bp, len, &written); + bp += len; + return written; + } + + else { + /* write first piece of data to first page boundary */ + len = ((firstpage + 1) * pagesize) - eepfs_getposition(ip); + len -= ((EepromFileStream *)ip)->cfg->barrier_low; + __fitted_write(ip, bp, len, &written); + bp += len; + + /* now writes blocks at a size of pages (may be no one) */ + while ((n - written) > pagesize) { + len = pagesize; + __fitted_write(ip, bp, len, &written); + bp += len; + } + + /* wrtie tail */ + len = n - written; + if (len == 0) + return written; + else { + __fitted_write(ip, bp, len, &written); + } + } + + return written; +} + +/** + * Read some bytes from current position in file. After successful + * read operation the position pointer will be increased by the number + * of read bytes. + */ +static size_t read(void *ip, uint8_t *bp, size_t n) { + msg_t status = MSG_OK; + + osalDbgCheck((ip != NULL) && (((EepromFileStream *)ip)->vmt != NULL)); + + if (n == 0) + return 0; + + n = __clamp_size(ip, n); + if (n == 0) + return 0; + + /* Stupid I2C cell in STM32F1x does not allow to read single byte. + So we must read 2 bytes and return needed one. */ +#if defined(STM32F1XX_I2C) + if (n == 1) { + uint8_t __buf[2]; + /* if NOT last byte of file requested */ + if ((eepfs_getposition(ip) + 1) < eepfs_getsize(ip)) { + if (read(ip, __buf, 2) == 2) { + eepfs_lseek(ip, (eepfs_getposition(ip) + 1)); + bp[0] = __buf[0]; + return 1; + } + else + return 0; + } + else { + eepfs_lseek(ip, (eepfs_getposition(ip) - 1)); + if (read(ip, __buf, 2) == 2) { + eepfs_lseek(ip, (eepfs_getposition(ip) + 2)); + bp[0] = __buf[1]; + return 1; + } + else + return 0; + } + } +#endif /* defined(STM32F1XX_I2C) */ + + /* call low level function */ + status = eeprom_read(((I2CEepromFileStream *)ip)->cfg, + eepfs_getposition(ip), bp, n); + if (status != MSG_OK) + return 0; + else { + eepfs_lseek(ip, (eepfs_getposition(ip) + n)); + return n; + } +} + +static const struct EepromFileStreamVMT vmt = { + write, + read, + eepfs_put, + eepfs_get, + eepfs_close, + eepfs_geterror, + eepfs_getsize, + eepfs_getposition, + eepfs_lseek, +}; + +EepromDevice eepdev_24xx = { + EEPROM_DEV_24XX, + &vmt +}; + +#endif /* EEPROM_USE_EE24XX */ diff --git a/os/hal/src/ee25xx.c b/os/hal/src/ee25xx.c new file mode 100644 index 0000000..07f4373 --- /dev/null +++ b/os/hal/src/ee25xx.c @@ -0,0 +1,404 @@ +/* + Copyright (c) 2013 Timon Wong + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* + Copyright 2012 Uladzimir Pylinski aka barthess. + You may use this work without restrictions, as long as this notice is included. + The work is provided "as is" without warranty of any kind, neither express nor implied. +*/ + +/***************************************************************************** + * DATASHEET NOTES + ***************************************************************************** +Write cycle time (byte or page) - 5 ms + +Note: + Page write operations are limited to writing bytes within a single physical + page, regardless of the number of bytes actually being written. Physical page + boundaries start at addresses that are integer multiples of the page buffer + size (or page size and end at addresses that are integer multiples of + [page size]. If a Page Write command attempts to write across a physical + page boundary, the result is that the data wraps around to the beginning of + the current page (overwriting data previously stored there), instead of + being written to the next page as might be expected. +*********************************************************************/ + +#include "ee25xx.h" +#include + +#if (defined(HAL_USE_EEPROM) && HAL_USE_EEPROM && EEPROM_USE_EE25XX) || defined(__DOXYGEN__) + +/** + * @name Commands of 25XX chip. + * @{ + */ +#define CMD_READ 0x03 /**< @brief Read data from memory array beginning at + selected address. */ +#define CMD_WRITE 0x02 /**< @brief Write data to memory array beginning at + selected address. */ +#define CMD_WRDI 0x04 /**< Reset the write enable latch (disable write + operations). */ +#define CMD_WREN 0x06 /**< Set the write enable latch (enable write + operations). */ +#define CMD_RDSR 0x05 /**< Read STATUS register. */ +#define CMD_WRSR 0x01 /**< Write STATUS register. */ + +/** @} */ + +/** + * @name Status of 25XX chip. + * @{} + */ +#define STAT_BP1 0x08 /**< @brief Block protection (high). */ +#define STAT_BP0 0x04 /**< @brief Block protection (low). */ +#define STAT_WEL 0x02 /**< @brief Write enable latch. */ +#define STAT_WIP 0x01 /**< @brief Write-In-Progress. */ + +/** @} */ + +/** + * @brief 25XX low level write then read rountine. + * + * @param[in] eepcfg pointer to configuration structure of eeprom file. + * @param[in] txbuf pointer to buffer to be transfered. + * @param[in] txlen number of bytes to be transfered. + * @param[out] rxbuf pointer to buffer to be received. + * @param[in] rxlen number of bytes to be received. + */ +static void ll_25xx_transmit_receive(const SPIEepromFileConfig *eepcfg, + const uint8_t *txbuf, size_t txlen, + uint8_t *rxbuf, size_t rxlen) { + +#if SPI_USE_MUTUAL_EXCLUSION + spiAcquireBus(eepcfg->spip); +#endif + spiSelect(eepcfg->spip); + spiSend(eepcfg->spip, txlen, txbuf); + if (rxlen) /* Check if receive is needed. */ + spiReceive(eepcfg->spip, rxlen, rxbuf); + spiUnselect(eepcfg->spip); + +#if SPI_USE_MUTUAL_EXCLUSION + spiReleaseBus(eepcfg->spip); +#endif +} + +/** + * @brief Check whether the device is busy (writing in progress). + * + * @param[in] eepcfg pointer to configuration structure of eeprom file. + * @return @p true on busy. + */ +static bool ll_eeprom_is_busy(const SPIEepromFileConfig *eepcfg) { + + uint8_t cmd = CMD_RDSR; + uint8_t stat; + ll_25xx_transmit_receive(eepcfg, &cmd, 1, &stat, 1); + if (stat & STAT_WIP) + return TRUE; + return FALSE; +} + +/** + * @brief Lock device. + * + * @param[in] eepcfg pointer to configuration structure of eeprom file. + */ +static void ll_eeprom_lock(const SPIEepromFileConfig *eepcfg) { + + uint8_t cmd = CMD_WRDI; + ll_25xx_transmit_receive(eepcfg, &cmd, 1, NULL, 0); +} + +/** + * @brief Unlock device. + * + * @param[in] eepcfg pointer to configuration structure of eeprom file. + */ +static void ll_eeprom_unlock(const SPIEepromFileConfig *eepcfg) { + + uint8_t cmd = CMD_WREN; + ll_25xx_transmit_receive(eepcfg, &cmd, 1, NULL, 0); +} + +/** + * @brief Prepare byte sequence for command and address + * + * @param[in] seq pointer to first 3byte sequence + * @param[in] size size of the eeprom device + * @param[in] cmd command + * @param[in] addr address + * @return number of bytes of this sequence + */ +static uint8_t ll_eeprom_prepare_seq(uint8_t *seq, uint32_t size, uint8_t cmd, + uint32_t addr) { + + seq[0] = ((uint8_t)cmd & 0xff); + + if (size > 0xffffUL) { + /* High density, 24bit address. */ + seq[1] = (uint8_t)((addr >> 16) & 0xff); + seq[2] = (uint8_t)((addr >> 8) & 0xff); + seq[3] = (uint8_t)(addr & 0xff); + return 4; + } + else if (size > 0x00ffUL) { + /* Medium density, 16bit address. */ + seq[1] = (uint8_t)((addr >> 8) & 0xff); + seq[2] = (uint8_t)(addr & 0xff); + return 3; + } + + /* Low density, 8bit address. */ + seq[1] = (uint8_t)(addr & 0xff); + return 2; +} + +/** + * @brief EEPROM read routine. + * + * @param[in] eepcfg pointer to configuration structure of eeprom file. + * @param[in] offset addres of 1-st byte to be read. + * @param[out] data pointer to buffer with data to be written. + * @param[in] len number of bytes to be red. + */ +static msg_t ll_eeprom_read(const SPIEepromFileConfig *eepcfg, uint32_t offset, + uint8_t *data, size_t len) { + + uint8_t txbuff[4]; + uint8_t txlen; + + osalDbgAssert(((len <= eepcfg->size) && ((offset + len) <= eepcfg->size)), + "out of device bounds"); + + if (eepcfg->spip->state != SPI_READY) + return MSG_RESET; + + txlen = ll_eeprom_prepare_seq(txbuff, eepcfg->size, CMD_READ, + (offset + eepcfg->barrier_low)); + ll_25xx_transmit_receive(eepcfg, txbuff, txlen, data, len); + + return MSG_OK; +} + +/** + * @brief EEPROM write routine. + * @details Function writes data to EEPROM. + * @pre Data must be fit to single EEPROM page. + * + * @param[in] eepcfg pointer to configuration structure of eeprom file. + * @param[in] offset addres of 1-st byte to be writen. + * @param[in] data pointer to buffer with data to be written. + * @param[in] len number of bytes to be written. + */ +static msg_t ll_eeprom_write(const SPIEepromFileConfig *eepcfg, uint32_t offset, + const uint8_t *data, size_t len) { + + uint8_t txbuff[4]; + uint8_t txlen; + systime_t now; + + osalDbgAssert(((len <= eepcfg->size) && ((offset + len) <= eepcfg->size)), + "out of device bounds"); + osalDbgAssert((((offset + eepcfg->barrier_low) / eepcfg->pagesize) == + (((offset + eepcfg->barrier_low) + len - 1) / eepcfg->pagesize)), + "data can not be fitted in single page"); + + if (eepcfg->spip->state != SPI_READY) + return MSG_RESET; + + /* Unlock array for writting. */ + ll_eeprom_unlock(eepcfg); + +#if SPI_USE_MUTUAL_EXCLUSION + spiAcquireBus(eepcfg->spip); +#endif + + spiSelect(eepcfg->spip); + txlen = ll_eeprom_prepare_seq(txbuff, eepcfg->size, CMD_WRITE, + (offset + eepcfg->barrier_low)); + spiSend(eepcfg->spip, txlen, txbuff); + spiSend(eepcfg->spip, len, data); + spiUnselect(eepcfg->spip); + +#if SPI_USE_MUTUAL_EXCLUSION + spiReleaseBus(eepcfg->spip); +#endif + + /* Wait until EEPROM process data. */ + now = chVTGetSystemTimeX(); + while (ll_eeprom_is_busy(eepcfg)) { + if ((chVTGetSystemTimeX() - now) > eepcfg->write_time) { + return MSG_TIMEOUT; + } + + chThdYield(); + } + + /* Lock array preventing unexpected access */ + ll_eeprom_lock(eepcfg); + return MSG_OK; +} + +/** + * @brief Determines and returns size of data that can be processed + */ +static size_t __clamp_size(void *ip, size_t n) { + + if (((size_t)eepfs_getposition(ip) + n) > (size_t)eepfs_getsize(ip)) + return eepfs_getsize(ip) - eepfs_getposition(ip); + else + return n; +} + +/** + * @brief Write data that can be fitted in one page boundary + */ +static msg_t __fitted_write(void *ip, const uint8_t *data, size_t len, uint32_t *written) { + + msg_t status = MSG_RESET; + + osalDbgAssert(len != 0, "something broken in hi level part"); + + status = ll_eeprom_write(((SPIEepromFileStream *)ip)->cfg, + eepfs_getposition(ip), data, len); + if (status == MSG_OK) { + *written += len; + eepfs_lseek(ip, eepfs_getposition(ip) + len); + } + return status; +} + +/** + * @brief Write data to EEPROM. + * @details Only one EEPROM page can be written at once. So fucntion + * splits large data chunks in small EEPROM transactions if needed. + * @note To achieve the maximum effectivity use write operations + * aligned to EEPROM page boundaries. + */ +static size_t write(void *ip, const uint8_t *bp, size_t n) { + + size_t len = 0; /* bytes to be written at one trasaction */ + uint32_t written; /* total bytes successfully written */ + uint16_t pagesize; + uint32_t firstpage; + uint32_t lastpage; + + volatile const SPIEepromFileConfig *cfg = ((SPIEepromFileStream *)ip)->cfg; + + osalDbgCheck((ip != NULL) && (((SPIEepromFileStream *)ip)->vmt != NULL)); + + if (n == 0) + return 0; + + n = __clamp_size(ip, n); + if (n == 0) + return 0; + + pagesize = cfg->pagesize; + firstpage = (cfg->barrier_low + eepfs_getposition(ip)) / pagesize; + lastpage = ((cfg->barrier_low + eepfs_getposition(ip) + n) - 1) / pagesize; + + written = 0; + /* data fitted in single page */ + if (firstpage == lastpage) { + len = n; + __fitted_write(ip, bp, len, &written); + bp += len; + return written; + } + else { + /* write first piece of data to first page boundary */ + len = ((firstpage + 1) * pagesize) - eepfs_getposition(ip); + len -= cfg->barrier_low; + __fitted_write(ip, bp, len, &written); + bp += len; + + /* now writes blocks at a size of pages (may be no one) */ + while ((n - written) > pagesize) { + len = pagesize; + if (__fitted_write(ip, bp, len, &written) != MSG_OK) // Fixed: Would increase bp forever and crash in case of timeouts... + return written; + + bp += len; + } + + + /* wrtie tail */ + len = n - written; + if (len == 0) + return written; + else { + __fitted_write(ip, bp, len, &written); + } + } + + return written; +} + +/** + * Read some bytes from current position in file. After successful + * read operation the position pointer will be increased by the number + * of read bytes. + */ +static size_t read(void *ip, uint8_t *bp, size_t n) { + + msg_t status = MSG_OK; + + osalDbgCheck((ip != NULL) && (((EepromFileStream *)ip)->vmt != NULL)); + + if (n == 0) + return 0; + + n = __clamp_size(ip, n); + if (n == 0) + return 0; + + /* call low level function */ + status = ll_eeprom_read(((SPIEepromFileStream *)ip)->cfg, + eepfs_getposition(ip), bp, n); + if (status != MSG_OK) + return 0; + else { + eepfs_lseek(ip, (eepfs_getposition(ip) + n)); + return n; + } +} + +static const struct EepromFileStreamVMT vmt = { + write, + read, + eepfs_put, + eepfs_get, + eepfs_close, + eepfs_geterror, + eepfs_getsize, + eepfs_getposition, + eepfs_lseek, +}; + +EepromDevice eepdev_25xx = { + EEPROM_DEV_25XX, + &vmt +}; + +#endif /* EEPROM_USE_EE25XX */ diff --git a/os/hal/src/eeprom.c b/os/hal/src/eeprom.c new file mode 100644 index 0000000..60d90ed --- /dev/null +++ b/os/hal/src/eeprom.c @@ -0,0 +1,197 @@ +/* + Copyright (c) 2013 Timon Wong + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* + Copyright 2012 Uladzimir Pylinski aka barthess. + You may use this work without restrictions, as long as this notice is included. + The work is provided "as is" without warranty of any kind, neither express nor implied. +*/ + +#include "eeprom.h" +#include + +#if defined(HAL_USE_EEPROM) && HAL_USE_EEPROM + +extern EepromDevice eepdev_24xx; +extern EepromDevice eepdev_25xx; + +EepromDevice *__eeprom_drv_table[] = { + /* I2C related. */ +#if HAL_USE_I2C + +# if EEPROM_USE_EE24XX + &eepdev_24xx, +# endif + +#endif /* HAL_USE_I2C */ + + /* SPI related. */ +#if HAL_USE_SPI + +# if EEPROM_USE_EE25XX + &eepdev_25xx, +# endif + +#endif /* HAL_USE_SPI */ +}; + + +/** + * @breif Find low level EEPROM device by id. + */ +const EepromDevice *EepromFindDevice(uint8_t id) { + + uint8_t i; + const EepromDevice *drv; + + for (i = 0; i < EEPROM_TABLE_SIZE; i++) { + drv = __eeprom_drv_table[i]; + if (drv->id == id) { + return drv; + } + } + + return NULL; +} + +/** + * Open EEPROM IC as file and return pointer to the file stream object + * @note Fucntion allways successfully open file. All checking makes + * in read/write functions. + */ +EepromFileStream *EepromFileOpen(EepromFileStream *efs, + const EepromFileConfig *eepcfg, + const EepromDevice *eepdev) { + + osalDbgAssert((efs != NULL) && (eepcfg != NULL) && (eepdev != NULL) && + (eepdev->efsvmt != NULL), "EepromFileOpen"); + osalDbgAssert(efs->vmt != eepdev->efsvmt, "File allready opened"); + osalDbgAssert(eepcfg->barrier_hi > eepcfg->barrier_low, "Low barrier exceeds High barrier"); + osalDbgAssert(eepcfg->pagesize < eepcfg->size, "Pagesize cannot be lager than EEPROM size"); + osalDbgAssert(eepcfg->barrier_hi <= eepcfg->size, "Barrier exceeds EEPROM size"); + + efs->vmt = eepdev->efsvmt; + efs->cfg = eepcfg; + efs->errors = FILE_OK; + efs->position = 0; + return (EepromFileStream *)efs; +} + +uint8_t EepromReadByte(EepromFileStream *efs) { + + uint8_t buf; + fileStreamRead(efs, &buf, sizeof(buf)); + return buf; +} + +uint16_t EepromReadHalfword(EepromFileStream *efs) { + + uint16_t buf; + fileStreamRead(efs, (uint8_t *)&buf, sizeof(buf)); + return buf; +} + +uint32_t EepromReadWord(EepromFileStream *efs) { + + uint32_t buf; + fileStreamRead(efs, (uint8_t *)&buf, sizeof(buf)); + return buf; +} + +size_t EepromWriteByte(EepromFileStream *efs, uint8_t data) { + + return fileStreamWrite(efs, &data, sizeof(data)); +} + +size_t EepromWriteHalfword(EepromFileStream *efs, uint16_t data) { + + return fileStreamWrite(efs, (uint8_t *)&data, sizeof(data)); +} + +size_t EepromWriteWord(EepromFileStream *efs, uint32_t data) { + + return fileStreamWrite(efs, (uint8_t *)&data, sizeof(data)); +} + +msg_t eepfs_getsize(void *ip) { + + uint32_t h, l; + + osalDbgCheck((ip != NULL) && (((EepromFileStream *)ip)->vmt != NULL) && + (((EepromFileStream *)ip)->cfg != NULL)); + + h = ((EepromFileStream *)ip)->cfg->barrier_hi; + l = ((EepromFileStream *)ip)->cfg->barrier_low; + return h - l; +} + +msg_t eepfs_getposition(void *ip) { + + osalDbgCheck((ip != NULL) && (((EepromFileStream *)ip)->vmt != NULL)); + + return ((EepromFileStream *)ip)->position; +} + +msg_t eepfs_lseek(void *ip, fileoffset_t offset) { + + uint32_t size; + + osalDbgCheck((ip != NULL) && (((EepromFileStream *)ip)->vmt != NULL)); + + size = eepfs_getsize(ip); + if (offset > size) + offset = size; + ((EepromFileStream *)ip)->position = offset; + return offset; +} + +msg_t eepfs_close(void *ip) { + + osalDbgCheck((ip != NULL) && (((EepromFileStream *)ip)->vmt != NULL)); + + ((EepromFileStream *)ip)->errors = FILE_OK; + ((EepromFileStream *)ip)->position = 0; + ((EepromFileStream *)ip)->vmt = NULL; + ((EepromFileStream *)ip)->cfg = NULL; + return FILE_OK; +} + +msg_t eepfs_geterror(void *ip) { + + osalDbgCheck((ip != NULL) && (((EepromFileStream *)ip)->vmt != NULL)); + return ((EepromFileStream *)ip)->errors; +} + +msg_t eepfs_put(void *ip, uint8_t b) { + + (void)ip; + (void)b; + return 0; +} + +msg_t eepfs_get(void *ip) { + + (void)ip; + return 0; +} + +#endif /* #if defined(HAL_USE_EEPROM) && HAL_USE_EEPROM */ -- cgit v1.2.3