Class to provide simple access to I2C EEPROM chiles like Microchip's 24LC range or AMTELS AT24C range. Chips up to 64Kb in size are directly supported. Updated to Mbed OS v 5.1

Dependents:   storage_test

Files at this revision

API Documentation at this revision

Comitter:
skyscraper
Date:
Sat Mar 28 18:03:39 2020 +0000
Parent:
11:c3609e691623
Commit message:
More documentation tidying and format wand

Changed in this revision

I2CEeprom.cpp Show annotated file Show diff for this revision Revisions of this file
I2CEeprom.h Show annotated file Show diff for this revision Revisions of this file
--- a/I2CEeprom.cpp	Sat Mar 28 17:01:58 2020 +0000
+++ b/I2CEeprom.cpp	Sat Mar 28 18:03:39 2020 +0000
@@ -22,6 +22,7 @@
 namespace
 {
 
+//return true if system is little-endian
 inline bool little_endian()
 {
     int n = 1;
@@ -29,6 +30,8 @@
     return(*(char *)&n == 1);
 }
 
+// Put EEprom address into 2 char array
+// in corrcet endiannness
 void convert_address(size_t const & addressIn, char* arOut)
 {
     constexpr size_t int_size = sizeof(size_t);
@@ -50,12 +53,12 @@
 }
 
 I2CEeprom::I2CEeprom(
-     I2C & i2c, 
-     int address, 
-     size_t pageSize, 
-     size_t chipSize,
-     uint8_t writeCycleTime_ms
-     ):
+    I2C & i2c,
+    int address,
+    size_t pageSize,
+    size_t chipSize,
+    uint8_t writeCycleTime_ms
+):
     m_i2c{i2c},
     m_i2cAddress(address),
     m_chipSize(chipSize),
@@ -65,14 +68,13 @@
 
 size_t I2CEeprom::read(size_t address, char &value)
 {
-    // Check the address and size fit onto the chip.
-    if (!checkSpace(address, 1))
-        return 0;
-    char values[2];
-    convert_address(address,values);
-    if (m_i2c.write(m_i2cAddress, values, 2) == 0) {
-        if (m_i2c.read(m_i2cAddress, &value, 1) == 0) {
-            return 1;
+    if (checkSpace(address, 1)) {
+        char values[2];
+        convert_address(address,values);
+        if (m_i2c.write(m_i2cAddress, values, 2) == 0) {
+            if (m_i2c.read(m_i2cAddress, &value, 1) == 0) {
+                return 1;
+            }
         }
     }
     return 0;
@@ -80,14 +82,13 @@
 
 size_t I2CEeprom::read(size_t address, char *buffer, size_t size)
 {
-    // Check the address and size fit onto the chip.
-    if (!checkSpace(address, size))
-        return 0;
-    char values[2];
-    convert_address(address,values);
-    if (m_i2c.write(m_i2cAddress, values, 2) == 0) {
-        if (m_i2c.read(m_i2cAddress, buffer, size) == 0) {
-            return size;
+    if (checkSpace(address, size)) {
+        char values[2];
+        convert_address(address,values);
+        if (m_i2c.write(m_i2cAddress, values, 2) == 0) {
+            if (m_i2c.read(m_i2cAddress, buffer, size) == 0) {
+                return size;
+            }
         }
     }
     return 0;
@@ -95,62 +96,62 @@
 
 size_t I2CEeprom::write(size_t address, char value)
 {
-    // Check the address and size fit onto the chip.
-    if (!checkSpace(address, 1))
-        return 0;
-    char values[3];
-    convert_address(address,values);
-    values[2] = value;
-    if (m_i2c.write(m_i2cAddress, values, 3) != 0) {
+    if (checkSpace(address, 1)) {
+        char values[3];
+        convert_address(address,values);
+        values[2] = value;
+        if (m_i2c.write(m_i2cAddress, values, 3) != 0) {
+            return 0;
+        }
+        waitForWrite();
+        return 1;
+    } else {
         return 0;
     }
-
-    waitForWrite();
-    return 1;
 }
 
 size_t I2CEeprom::ll_write(size_t address, const char *buffer, size_t size)
 {
-    // TODO: change i2c address bits dependent on eeprom data address
-    // if size > 64k I 
-    if (m_i2c.write(m_i2cAddress, buffer, size) != 0) {
+    if (m_i2c.write(m_i2cAddress, buffer, size) == 0) {
+        waitForWrite();
+        return size;
+    } else {
         std::cout << "EE i2c write failed\n";
         return 0;
     }
-    waitForWrite();
-    return size;
 }
 
 size_t I2CEeprom::write(size_t address, const char *buffer, size_t size)
 {
-    if (!checkSpace(address, size)) {
-        return 0;
-    }
-    size_t const malloc_size = std::min(size,m_pageSize) + 2U;
-    char * tempBuffer = new char [malloc_size];
-    if ( tempBuffer == nullptr){
-        std::cout << "EE i2c buf malloc failed\n";
+    if (checkSpace(address, size)) {
+        size_t const malloc_size = std::min(size,m_pageSize) + 2U;
+        char * tempBuffer = new char [malloc_size];
+        if ( tempBuffer == nullptr) {
+            std::cout << "EE i2c buf malloc failed\n";
+            return 0;
+        }
+        size_t bytesLeft = size;
+        size_t numBytesToWrite
+            = std::min( size, m_pageSize - (address % m_pageSize));
+        while( bytesLeft ) {
+            convert_address(address,tempBuffer);
+            memcpy(tempBuffer + 2,buffer, numBytesToWrite);
+            if ( ll_write(address,tempBuffer, numBytesToWrite + 2U)
+                    == numBytesToWrite + 2U) {
+                buffer += numBytesToWrite;
+                address += numBytesToWrite;
+                bytesLeft -= numBytesToWrite;
+                numBytesToWrite = std::min(bytesLeft,m_pageSize);
+            } else {
+                std::cout << "EE i2c write failed\n";
+                break;
+            }
+        }
+        delete [] tempBuffer;
+        return size - bytesLeft;
+    } else {
         return 0;
     }
-    size_t bytesLeft = size;
-    size_t numBytesToWrite
-        = std::min( size, m_pageSize - (address % m_pageSize)); 
-    while(bytesLeft) {
-        convert_address(address,tempBuffer);
-        memcpy(tempBuffer + 2,buffer, numBytesToWrite);
-        if ( ll_write(address,tempBuffer, numBytesToWrite + 2U)
-           == numBytesToWrite + 2U) {
-            buffer += numBytesToWrite;
-            address += numBytesToWrite;
-            bytesLeft -= numBytesToWrite;
-            numBytesToWrite = std::min(bytesLeft,m_pageSize);
-        } else {
-            std::cout << "EE i2c write failed\n";
-            break;
-        }
-    }
-    delete [] tempBuffer;
-    return size - bytesLeft;
 }
 
 void I2CEeprom::waitForWrite()
@@ -163,4 +164,3 @@
         ThisThread::sleep_for(1);
     }
 }
-
--- a/I2CEeprom.h	Sat Mar 28 17:01:58 2020 +0000
+++ b/I2CEeprom.h	Sat Mar 28 18:03:39 2020 +0000
@@ -1,25 +1,25 @@
 
-/*! \file I2CEeprom.h */ 
+/*! \file I2CEeprom.h */
 /*! \class I2CEeprom */
 /*! \brief Simple access class for I2C EEPROM chips like Microchip 24LC
  */
- 
- /* Copyright (c) 2015 Robin Hourahane
- *  Copyright (c) 2020 Andy Little
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- 
+
+/* Copyright (c) 2015 Robin Hourahane
+*  Copyright (c) 2020 Andy Little
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
 #ifndef __I2CEEPROM_H__
 #define __I2CEEPROM_H__
 
@@ -27,106 +27,109 @@
 
 /// Based on the original Mbed I2CEeprom library by Robin Hourahane.
 ///
-/// Class to provide simple access to I2C EEPROM chips like Microchip's 24LC 
+/// Class to provide simple access to I2C EEPROM chips like Microchip's 24LC
 /// or AMTELS AT24C series. Chips up to 64Kb in size are directly supported.
-/// 
-/// The library was tested on a Microchip 24LC128. 
+///
+/// The library was tested on a Microchip 24LC128.
 ///
-/// The I2CEeprom class handles multiple page writes so any amount of data can 
-/// be written in a single call to write. 
+/// The I2CEeprom class handles multiple page writes so any amount of data can
+/// be written in a single call to write.
 ///
 /// The code is modified from the original to better support RTOS.
 /// At start of a write(addr,buffer,size), a buffer of up to pageSize + 2
 /// is allocated on the heap, and the data and address are copied to it.
-/// This allows the cuurent write chunk to proceed without unlocking, which 
+/// This allows the cuurent write chunk to proceed without unlocking, which
 /// prevents another device on the bus access and so aborting the write.
-/// 
+///
 /// This allocation per write fits my usecase, where eeeprom variables
 /// are written in a special menu mode at start up, but it may be better to
 /// preallocate a buffer once at startup, if writes are occurring at arbitrary
 /// times during execution, to prevent surprises with out of memory issues
 /// when trying to write during normal execution.
 ///
-/// The constructor takes the I2C bus by non-const reference argument. This 
+/// The constructor takes the I2C bus by non-const reference argument. This
 /// enables a single I2C bus to be shared among many i2c devices.
-/// Mbed OS enforces a lock on the bus during a bus read/write so reads 
-/// are atomic. Writes are split into separate atomic chunks that only write 
+/// Mbed OS enforces a lock on the bus during a bus read/write so reads
+/// are atomic. Writes are split into separate atomic chunks that only write
 /// one eeprom page. After a chunk is sent, the thread is sent to sleep for
-/// writeCycleTime_ms as in the constructor arg, and is then polled at 1 ms
-/// intervals to discover whether the write has completed.
+/// writeCycleTime_ms specified in the constructor arg, and is then polled
+/// at 1 ms intervals to discover whether the write has completed.
 
-class I2CEeprom {
+class I2CEeprom
+{
 public:
     /// Constructor to create a new instance of the class.
-    /// @param i2c A reference to the i2c bus the chip is connected to.
-    /// @param address The 8bit I2C address of the chip.
-    /// @param pageSize The size of the page used in writing to the chip.
-    /// @param chipSize The size of the memory in the chip for range check. 
-    /// @param writeCycleTime_ms The write cycle time in ms. 
+    /// @param i2c A reference to the i2c bus that the chip is connected to.
+    /// @param address The 8bit device I2C address
+    /// @param pageSize The device page size.
+    /// @param chipSize The device size for range check.
+    /// @param writeCycleTime_ms The device write cycle time in ms.
     I2CEeprom(
-            I2C& i2c, 
-            int address, 
-            size_t pageSize, 
-            size_t chipSize,
-            uint8_t writeCycleTime_ms);
-    
+        I2C& i2c,
+        int address,
+        size_t pageSize,
+        size_t chipSize,
+        uint8_t writeCycleTime_ms);
+
     /// Read a single byte from the EEprom.
-    /// @param address EEprom address to read from.
-    /// @param value Reference of char to read into.
+    /// @param address EEprom read address.
+    /// @param value Memory reference of char to read into.
     /// @returns Number of bytes read .
     size_t read(size_t address, char &value);
-    
-    /// Read multiple bytes starting from EEprom memory.
-    /// @param address EEprom Memory start read address.
-    /// @param buffer Pointer to buffer to hold bytes read.
+
+    /// Read multiple bytes from the EEprom.
+    /// @param address EEprom start read address.
+    /// @param buffer buffer to read into.
     /// @param size Number of bytes to read.
     /// @returns Number of bytes read.
     size_t read(size_t address, char *buffer, size_t size);
-    
+
     /// Deserialise object of type T from Eeprom memory.
-    /// @param address Start address of Object in EEprom.
-    /// @param value Reference to Object to deserialise into.
+    /// @param address EEprom start address
+    /// @param value Memory Reference of object to deserialise into .
     /// @returns Number of bytes read.
-    template<typename T> size_t read(size_t address, T &value) {
+    template<typename T> size_t read(size_t address, T &value)
+    {
         return read(address, reinterpret_cast<char *>(&value), sizeof(T));
     }
-    
+
     /// Write a char to EEprom.
-    /// @param address Eeprom address to write to.
-    /// @param value Value of char to write.
+    /// @param address Eeprom write address.
+    /// @param value Char value to write.
     /// @returns Number of bytes written.
     size_t write(size_t address, char value);
 
-    /// Write multiple bytes to EEprom
-    /// Note that in this implementation, the write is split into chunks
-    /// of up to pageSize and for each chunk a buffer of up to pageSize + 2   
-    /// is temporarily allocated on the heap while the write is in progress.
-    /// @param address Start EEprom address.
-    /// @param buffer Buffer holding the bytes to write.
+    /// Write multiple bytes to EEprom.
+    /// In this implementation, the write is split into chunks of up to pageSize
+    /// and for each chunk a buffer of up to pageSize + 2 is temporarily
+    /// allocated on the heap while the write is in progress.
+    /// @param address EEprom start address.
+    /// @param buffer Buffer to write.
     /// @param size Number of bytes to write.
     /// @returns Number of bytes written.
     size_t write(size_t address, const char *buffer, size_t size);
 
     /// Serialise an object of type T.
-    /// @param address EEprom write start address.
+    /// @param address EEprom start address.
     /// @param value Object to be serialised.
     /// @returns Number of bytes written.
-    template<typename T> size_t write(size_t address, const T &value) {
+    template<typename T> size_t write(size_t address, const T &value)
+    {
         return write(address, reinterpret_cast<const char *>(&value), sizeof(T));
     }
-        
+
 private:
     /// Sleep thread while write completes.
     void waitForWrite();
-    ///  atomic chunk up to page aize write
+    ///  atomic chunk up to page size write
     size_t ll_write(size_t address, const char *buffer, size_t size);
-    
+
     /// Validate that proposed operation is in bounds.
     bool checkSpace(size_t address, size_t size)
     {
-       return (address + size) < m_chipSize ;
+        return (address + size) < m_chipSize ;
     }
-    
+
 private:
     I2C & m_i2c;
     int const m_i2cAddress;