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

Committer:
skyscraper
Date:
Sat Mar 28 01:50:44 2020 +0000
Revision:
4:d8f51b136dbd
Parent:
3:b2a132553b02
Child:
12:d9a44fb3b9a6
Streamline EEprom and remove some unneded functionality

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rhourahane 1:b23f5561266c 1 /* Simple access class for I2C EEPROM chips like Microchip 24LC
rhourahane 1:b23f5561266c 2 * Copyright (c) 2015 Robin Hourahane
rhourahane 1:b23f5561266c 3 *
rhourahane 1:b23f5561266c 4 * Licensed under the Apache License, Version 2.0 (the "License");
rhourahane 1:b23f5561266c 5 * you may not use this file except in compliance with the License.
rhourahane 1:b23f5561266c 6 * You may obtain a copy of the License at
rhourahane 1:b23f5561266c 7 *
rhourahane 1:b23f5561266c 8 * http://www.apache.org/licenses/LICENSE-2.0
rhourahane 1:b23f5561266c 9 *
rhourahane 1:b23f5561266c 10 * Unless required by applicable law or agreed to in writing, software
rhourahane 1:b23f5561266c 11 * distributed under the License is distributed on an "AS IS" BASIS,
rhourahane 1:b23f5561266c 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rhourahane 1:b23f5561266c 13 * See the License for the specific language governing permissions and
rhourahane 1:b23f5561266c 14 * limitations under the License.
rhourahane 1:b23f5561266c 15 */
skyscraper 2:f3188aaccf80 16
skyscraper 2:f3188aaccf80 17 #include <iostream>
skyscraper 2:f3188aaccf80 18 #include <algorithm>
skyscraper 2:f3188aaccf80 19
rhourahane 1:b23f5561266c 20 #include "I2CEeprom.h"
rhourahane 1:b23f5561266c 21
skyscraper 2:f3188aaccf80 22 namespace
skyscraper 2:f3188aaccf80 23 {
skyscraper 2:f3188aaccf80 24
skyscraper 2:f3188aaccf80 25 inline bool little_endian()
skyscraper 2:f3188aaccf80 26 {
skyscraper 2:f3188aaccf80 27 int n = 1;
skyscraper 2:f3188aaccf80 28 // little endian if true
skyscraper 2:f3188aaccf80 29 return(*(char *)&n == 1);
skyscraper 2:f3188aaccf80 30 }
skyscraper 2:f3188aaccf80 31
skyscraper 2:f3188aaccf80 32 void convert_address(size_t const & addressIn, char* arOut)
skyscraper 2:f3188aaccf80 33 {
skyscraper 2:f3188aaccf80 34 constexpr size_t int_size = sizeof(size_t);
skyscraper 2:f3188aaccf80 35 union uu {
skyscraper 2:f3188aaccf80 36 uu(size_t a) : address{a} {}
skyscraper 2:f3188aaccf80 37 size_t address;
skyscraper 2:f3188aaccf80 38 const char ar[int_size];
skyscraper 2:f3188aaccf80 39 } u{addressIn};
skyscraper 2:f3188aaccf80 40 static_assert(sizeof(u) == int_size,"");
skyscraper 2:f3188aaccf80 41 if( little_endian()) {
skyscraper 2:f3188aaccf80 42 arOut[1] = u.ar[0];
skyscraper 2:f3188aaccf80 43 arOut[0] = u.ar[1];
skyscraper 2:f3188aaccf80 44 } else {
skyscraper 2:f3188aaccf80 45 // std::cout << "big endian\n";
skyscraper 2:f3188aaccf80 46 arOut[1] = u.ar[int_size - 1]; // lsb
skyscraper 2:f3188aaccf80 47 arOut[0] = u.ar[int_size - 2]; //nextsb
skyscraper 2:f3188aaccf80 48 }
skyscraper 2:f3188aaccf80 49 }
skyscraper 2:f3188aaccf80 50 }
skyscraper 2:f3188aaccf80 51
skyscraper 2:f3188aaccf80 52 I2CEeprom::I2CEeprom(
skyscraper 2:f3188aaccf80 53 I2C & i2c,
skyscraper 2:f3188aaccf80 54 int address,
skyscraper 2:f3188aaccf80 55 size_t pageSize,
skyscraper 2:f3188aaccf80 56 size_t chipSize,
skyscraper 2:f3188aaccf80 57 uint8_t writeCycleTime_ms
skyscraper 2:f3188aaccf80 58 ):
skyscraper 2:f3188aaccf80 59 m_i2c{i2c},
rhourahane 1:b23f5561266c 60 m_i2cAddress(address),
rhourahane 1:b23f5561266c 61 m_chipSize(chipSize),
skyscraper 2:f3188aaccf80 62 m_pageSize(pageSize),
skyscraper 2:f3188aaccf80 63 m_writeCycleTime_ms{writeCycleTime_ms}
skyscraper 2:f3188aaccf80 64 {}
skyscraper 2:f3188aaccf80 65
skyscraper 2:f3188aaccf80 66 size_t I2CEeprom::read(size_t address, char &value)
rhourahane 1:b23f5561266c 67 {
rhourahane 1:b23f5561266c 68 // Check the address and size fit onto the chip.
rhourahane 1:b23f5561266c 69 if (!checkSpace(address, 1))
rhourahane 1:b23f5561266c 70 return 0;
skyscraper 2:f3188aaccf80 71 char values[2];
skyscraper 2:f3188aaccf80 72 convert_address(address,values);
rhourahane 1:b23f5561266c 73 if (m_i2c.write(m_i2cAddress, values, 2) == 0) {
rhourahane 1:b23f5561266c 74 if (m_i2c.read(m_i2cAddress, &value, 1) == 0) {
rhourahane 1:b23f5561266c 75 return 1;
rhourahane 1:b23f5561266c 76 }
rhourahane 1:b23f5561266c 77 }
rhourahane 1:b23f5561266c 78 return 0;
rhourahane 1:b23f5561266c 79 }
rhourahane 1:b23f5561266c 80
skyscraper 2:f3188aaccf80 81 size_t I2CEeprom::read(size_t address, char *buffer, size_t size)
skyscraper 2:f3188aaccf80 82 {
rhourahane 1:b23f5561266c 83 // Check the address and size fit onto the chip.
rhourahane 1:b23f5561266c 84 if (!checkSpace(address, size))
rhourahane 1:b23f5561266c 85 return 0;
skyscraper 2:f3188aaccf80 86 char values[2];
skyscraper 2:f3188aaccf80 87 convert_address(address,values);
rhourahane 1:b23f5561266c 88 if (m_i2c.write(m_i2cAddress, values, 2) == 0) {
rhourahane 1:b23f5561266c 89 if (m_i2c.read(m_i2cAddress, buffer, size) == 0) {
rhourahane 1:b23f5561266c 90 return size;
rhourahane 1:b23f5561266c 91 }
rhourahane 1:b23f5561266c 92 }
rhourahane 1:b23f5561266c 93 return 0;
rhourahane 1:b23f5561266c 94 }
skyscraper 4:d8f51b136dbd 95
skyscraper 2:f3188aaccf80 96 size_t I2CEeprom::write(size_t address, char value)
skyscraper 2:f3188aaccf80 97 {
rhourahane 1:b23f5561266c 98 // Check the address and size fit onto the chip.
rhourahane 1:b23f5561266c 99 if (!checkSpace(address, 1))
rhourahane 1:b23f5561266c 100 return 0;
skyscraper 2:f3188aaccf80 101 char values[3];
skyscraper 2:f3188aaccf80 102 convert_address(address,values);
skyscraper 2:f3188aaccf80 103 values[2] = value;
rhourahane 1:b23f5561266c 104 if (m_i2c.write(m_i2cAddress, values, 3) != 0) {
rhourahane 1:b23f5561266c 105 return 0;
rhourahane 1:b23f5561266c 106 }
skyscraper 2:f3188aaccf80 107
rhourahane 1:b23f5561266c 108 waitForWrite();
rhourahane 1:b23f5561266c 109 return 1;
rhourahane 1:b23f5561266c 110 }
rhourahane 1:b23f5561266c 111
skyscraper 2:f3188aaccf80 112 size_t I2CEeprom::ll_write(size_t address, const char *buffer, size_t size)
skyscraper 2:f3188aaccf80 113 {
skyscraper 2:f3188aaccf80 114 // TODO: change i2c address bits dependent on eeprom data address
skyscraper 3:b2a132553b02 115 // if size > 64k I
skyscraper 3:b2a132553b02 116 if (m_i2c.write(m_i2cAddress, buffer, size) != 0) {
skyscraper 2:f3188aaccf80 117 std::cout << "EE i2c write failed\n";
skyscraper 2:f3188aaccf80 118 return 0;
rhourahane 1:b23f5561266c 119 }
skyscraper 2:f3188aaccf80 120 waitForWrite();
rhourahane 1:b23f5561266c 121 return size;
rhourahane 1:b23f5561266c 122 }
rhourahane 1:b23f5561266c 123
skyscraper 2:f3188aaccf80 124 size_t I2CEeprom::write(size_t address, const char *buffer, size_t size)
skyscraper 2:f3188aaccf80 125 {
skyscraper 2:f3188aaccf80 126 if (!checkSpace(address, size)) {
rhourahane 1:b23f5561266c 127 return 0;
skyscraper 2:f3188aaccf80 128 }
skyscraper 3:b2a132553b02 129 size_t const malloc_size = std::min(size,m_pageSize) + 2U;
skyscraper 3:b2a132553b02 130 char * tempBuffer = new char [malloc_size];
skyscraper 3:b2a132553b02 131 if ( tempBuffer == nullptr){
skyscraper 3:b2a132553b02 132 std::cout << "EE i2c buf malloc failed\n";
skyscraper 3:b2a132553b02 133 return 0;
skyscraper 3:b2a132553b02 134 }
skyscraper 2:f3188aaccf80 135 size_t bytesLeft = size;
skyscraper 2:f3188aaccf80 136 size_t numBytesToWrite
skyscraper 3:b2a132553b02 137 = std::min( size, m_pageSize - (address % m_pageSize));
skyscraper 2:f3188aaccf80 138 while(bytesLeft) {
skyscraper 3:b2a132553b02 139 convert_address(address,tempBuffer);
skyscraper 3:b2a132553b02 140 memcpy(tempBuffer + 2,buffer, numBytesToWrite);
skyscraper 3:b2a132553b02 141 if ( ll_write(address,tempBuffer, numBytesToWrite + 2U)
skyscraper 3:b2a132553b02 142 == numBytesToWrite + 2U) {
skyscraper 2:f3188aaccf80 143 buffer += numBytesToWrite;
skyscraper 2:f3188aaccf80 144 address += numBytesToWrite;
skyscraper 2:f3188aaccf80 145 bytesLeft -= numBytesToWrite;
skyscraper 2:f3188aaccf80 146 numBytesToWrite = std::min(bytesLeft,m_pageSize);
rhourahane 1:b23f5561266c 147 } else {
skyscraper 3:b2a132553b02 148 std::cout << "EE i2c write failed\n";
skyscraper 2:f3188aaccf80 149 break;
rhourahane 1:b23f5561266c 150 }
rhourahane 1:b23f5561266c 151 }
skyscraper 3:b2a132553b02 152 delete [] tempBuffer;
skyscraper 2:f3188aaccf80 153 return size - bytesLeft;
rhourahane 1:b23f5561266c 154 }
rhourahane 1:b23f5561266c 155
skyscraper 2:f3188aaccf80 156 void I2CEeprom::waitForWrite()
skyscraper 2:f3188aaccf80 157 {
skyscraper 2:f3188aaccf80 158 ThisThread::sleep_for(m_writeCycleTime_ms);
rhourahane 1:b23f5561266c 159 // The chip doesn't ACK while writing to the actual EEPROM
rhourahane 1:b23f5561266c 160 // so loop trying to do a zero byte write until it is ACKed
rhourahane 1:b23f5561266c 161 // by the chip.
rhourahane 1:b23f5561266c 162 while (m_i2c.write(m_i2cAddress, 0, 0) != 0) {
skyscraper 2:f3188aaccf80 163 ThisThread::sleep_for(1);
rhourahane 1:b23f5561266c 164 }
rhourahane 1:b23f5561266c 165 }
rhourahane 1:b23f5561266c 166