aboutsummaryrefslogtreecommitdiffstats
path: root/os
diff options
context:
space:
mode:
authorFabien Poussin <fabien.poussin@gmail.com>2016-02-16 00:22:40 +0100
committerFabien Poussin <fabien.poussin@gmail.com>2016-02-16 00:22:40 +0100
commit9028916e8b89dcf9f8b41cefbd075efdf80cbac6 (patch)
tree22546566b72e2a8f17e950383412e3a5c02850b7 /os
parent771feb098db86458340ab2665dfb23bef970ace6 (diff)
downloadChibiOS-Contrib-9028916e8b89dcf9f8b41cefbd075efdf80cbac6.tar.gz
ChibiOS-Contrib-9028916e8b89dcf9f8b41cefbd075efdf80cbac6.tar.bz2
ChibiOS-Contrib-9028916e8b89dcf9f8b41cefbd075efdf80cbac6.zip
EEPROM: Initial commit
Diffstat (limited to 'os')
-rw-r--r--os/hal/hal.mk5
-rw-r--r--os/hal/include/ee24xx.h64
-rw-r--r--os/hal/include/ee25xx.h63
-rw-r--r--os/hal/include/eeprom.h147
-rw-r--r--os/hal/include/hal_community.h1
-rw-r--r--os/hal/src/ee24xx.c353
-rw-r--r--os/hal/src/ee25xx.c404
-rw-r--r--os/hal/src/eeprom.c197
8 files changed, 1233 insertions, 1 deletions
diff --git a/os/hal/hal.mk b/os/hal/hal.mk
index 2802a09..0fcced7 100644
--- a/os/hal/hal.mk
+++ b/os/hal/hal.mk
@@ -11,6 +11,9 @@ HALSRC += ${CHIBIOS_CONTRIB}/os/hal/src/hal_community.c \
${CHIBIOS_CONTRIB}/os/hal/src/usbh/usbh_hub.c \
${CHIBIOS_CONTRIB}/os/hal/src/usbh/usbh_msd.c \
${CHIBIOS_CONTRIB}/os/hal/src/usbh/usbh_ftdi.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/usbh/usbh_uvc.c
+ ${CHIBIOS_CONTRIB}/os/hal/src/usbh/usbh_uvc.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/ee24xx.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/ee25xx.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/eeprom.c
HALINC += ${CHIBIOS_CONTRIB}/os/hal/include
diff --git a/os/hal/include/ee24xx.h b/os/hal/include/ee24xx.h
new file mode 100644
index 0000000..ab12fd1
--- /dev/null
+++ b/os/hal/include/ee24xx.h
@@ -0,0 +1,64 @@
+/*
+ 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.
+*/
+
+#ifndef EE24XX_H
+#define EE24XX_H
+
+#include "hal.h"
+
+#if defined(HAL_USE_EEPROM) && HAL_USE_EEPROM && EEPROM_USE_EE24XX
+
+#define EEPROM_DEV_24XX 24
+
+/**
+ * @extends EepromFileConfig
+ */
+typedef struct {
+ _eeprom_file_config_data
+ /**
+ * Driver connected to IC.
+ */
+ I2CDriver *i2cp;
+ /**
+ * Address of IC on I2C bus.
+ */
+ i2caddr_t addr;
+ /**
+ * Pointer to write buffer. The safest size is (pagesize + 2)
+ */
+ uint8_t *write_buf;
+} I2CEepromFileConfig;
+
+/**
+ * @brief @p I2CEepromFileStream specific data.
+ */
+#define _eeprom_file_stream_data_i2c \
+ _eeprom_file_stream_data
+
+/**
+ * @extends EepromFileStream
+ *
+ * @brief EEPROM file stream driver class for I2C device.
+ */
+typedef struct {
+ const struct EepromFileStreamVMT *vmt;
+ _eeprom_file_stream_data_i2c
+ /* Overwritten parent data member. */
+ const I2CEepromFileConfig *cfg;
+} I2CEepromFileStream;
+
+
+/**
+ * Open I2C 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.
+ */
+#define I2CEepromFileOpen(efs, eepcfg, eepdev) \
+ EepromFileOpen((EepromFileStream *)efs, (EepromFileConfig *)eepcfg, eepdev);
+
+#endif /* #if defined(EEPROM_USE_EE24XX) && EEPROM_USE_EE24XX */
+
+#endif // EE24XX_H
diff --git a/os/hal/include/ee25xx.h b/os/hal/include/ee25xx.h
new file mode 100644
index 0000000..fc2ad6f
--- /dev/null
+++ b/os/hal/include/ee25xx.h
@@ -0,0 +1,63 @@
+/*
+ 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.
+*/
+
+#ifndef EE25XX_H
+#define EE25XX_H
+
+#include "hal.h"
+
+#if defined(HAL_USE_EEPROM) && HAL_USE_EEPROM && EEPROM_USE_EE25XX
+
+#define EEPROM_DEV_25XX 25
+
+/**
+ * @extends EepromFileConfig
+ */
+typedef struct {
+ _eeprom_file_config_data
+ /**
+ * Driver connected to IC.
+ */
+ SPIDriver *spip;
+ /**
+ * Config associated with SPI driver.
+ */
+ const SPIConfig *spicfg;
+} SPIEepromFileConfig;
+
+/**
+ * @brief @p SPIEepromFileStream specific data.
+ */
+#define _eeprom_file_stream_data_spi \
+ _eeprom_file_stream_data
+
+/**
+ * @extends EepromFileStream
+ *
+ * @brief EEPROM file stream driver class for SPI device.
+ */
+typedef struct {
+ const struct EepromFileStreamVMT *vmt;
+ _eeprom_file_stream_data_spi
+ /* Overwritten parent data member. */
+ const SPIEepromFileConfig *cfg;
+} SPIEepromFileStream;
+
+/**
+ * Open SPI 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 *SPIEepromFileOpen(SPIEepromFileStream *efs,
+ const SPIEepromFileConfig *eepcfg,
+ const EepromDevice *eepdev);
+
+#define SPIEepromFileOpen(efs, eepcfg, eepdev) \
+ EepromFileOpen((EepromFileStream *)efs, (EepromFileConfig *)eepcfg, eepdev);
+
+#endif /* #if defined(EEPROM_USE_EE25XX) && EEPROM_USE_EE25XX */
+
+#endif // EE25XX_H
diff --git a/os/hal/include/eeprom.h b/os/hal/include/eeprom.h
new file mode 100644
index 0000000..b0fd360
--- /dev/null
+++ b/os/hal/include/eeprom.h
@@ -0,0 +1,147 @@
+/*
+ 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.
+*/
+
+#ifndef __EEPROM_H__
+#define __EEPROM_H__
+
+#include "ch.h"
+#include "hal.h"
+
+#ifndef HAL_USE_EEPROM
+#define HAL_USE_EEPROM FALSE
+#endif
+
+#ifndef EEPROM_USE_EE25XX
+#define EEPROM_USE_EE25XX FALSE
+#endif
+
+#ifndef EEPROM_USE_EE24XX
+#define EEPROM_USE_EE24XX FALSE
+#endif
+
+#if HAL_USE_EEPROM
+
+#if EEPROM_USE_EE25XX && EEPROM_USE_EE24XX
+#define EEPROM_TABLE_SIZE 2
+#elif EEPROM_USE_EE25XX || EEPROM_USE_EE24XX
+#define EEPROM_TABLE_SIZE 1
+#else
+#error "No EEPROM device selected!"
+#endif
+
+#if EEPROM_USE_EE25XX && !HAL_USE_SPI
+#error "25xx enabled but SPI driver is disabled!"
+#endif
+
+#if EEPROM_USE_EE24XX && !HAL_USE_I2C
+#error "24xx enabled but I2C driver is disabled!"
+#endif
+
+#define _eeprom_file_config_data \
+ /* Lower barrier of file in EEPROM memory array. */ \
+ uint32_t barrier_low; \
+ /* Higher barrier of file in EEPROM memory array. */ \
+ uint32_t barrier_hi; \
+ /* Size of memory array in bytes. */ \
+ uint32_t size; \
+ /* Size of single page in bytes. */ \
+ uint16_t pagesize; \
+ /* Time needed by IC for single byte/page writing. */ \
+ systime_t write_time;
+
+typedef uint32_t fileoffset_t;
+
+typedef struct {
+ _eeprom_file_config_data
+} EepromFileConfig;
+
+/**
+ * @brief @p EepromFileStream specific data.
+ */
+#define _eeprom_file_stream_data \
+ _base_sequential_stream_data \
+ uint32_t errors; \
+ uint32_t position; \
+
+/**
+ * @extends BaseFileStreamVMT
+ *
+ * @brief @p EepromFileStream virtual methods table.
+ */
+struct EepromFileStreamVMT {
+ _file_stream_methods
+};
+
+/**
+ * @extends BaseFileStream
+ *
+ * @brief EEPROM file stream driver class.
+ * @details This class extends @p BaseFileStream by adding some fields.
+ */
+typedef struct {
+ /** @brief Virtual Methods Table.*/
+ const struct EepromFileStreamVMT *vmt;
+ _eeprom_file_stream_data
+ /** pointer to config object, must be overwritten by all derived classes.*/
+ const EepromFileConfig *cfg;
+} EepromFileStream;
+
+/**
+ * @brief Low level device descriptor.
+ */
+typedef struct {
+ const uint8_t id;
+ const struct EepromFileStreamVMT *efsvmt;
+} EepromDevice;
+
+const EepromDevice *EepromFindDevice(uint8_t id);
+
+EepromFileStream *EepromFileOpen(EepromFileStream *efs,
+ const EepromFileConfig *eepcfg,
+ const EepromDevice *eepdev);
+
+uint8_t EepromReadByte(EepromFileStream *efs);
+uint16_t EepromReadHalfword(EepromFileStream *efs);
+uint32_t EepromReadWord(EepromFileStream *efs);
+size_t EepromWriteByte(EepromFileStream *efs, uint8_t data);
+size_t EepromWriteHalfword(EepromFileStream *efs, uint16_t data);
+size_t EepromWriteWord(EepromFileStream *efs, uint32_t data);
+
+msg_t eepfs_getsize(void *ip);
+msg_t eepfs_getposition(void *ip);
+msg_t eepfs_lseek(void *ip, fileoffset_t offset);
+msg_t eepfs_close(void *ip);
+msg_t eepfs_geterror(void *ip);
+msg_t eepfs_put(void *ip, uint8_t b);
+msg_t eepfs_get(void *ip);
+
+#include "ee24xx.h"
+#include "ee25xx.h"
+
+#endif /* #if defined(HAL_USE_EEPROM) && HAL_USE_EEPROM */
+#endif /* __EEPROM_H__ */
diff --git a/os/hal/include/hal_community.h b/os/hal/include/hal_community.h
index 8a17765..5ed561f 100644
--- a/os/hal/include/hal_community.h
+++ b/os/hal/include/hal_community.h
@@ -37,6 +37,7 @@
/* Complex drivers.*/
#include "onewire.h"
#include "crc.h"
+#include "eeprom.h"
/*===========================================================================*/
/* Driver constants. */
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 <string.h>
+
+#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 <string.h>
+
+#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 <string.h>
+
+#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 */