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.

Dependents:   Nucleo_praktyki

Fork of I2CEeprom by Robin Hourahane

Committer:
rhourahane
Date:
Sun Jul 19 09:34:04 2015 +0000
Revision:
1:b23f5561266c
Child:
2:b7877755371e
Updates to make library more generic to allow support for more I2C EEPROM chips.

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 */
rhourahane 1:b23f5561266c 16 #include "I2CEeprom.h"
rhourahane 1:b23f5561266c 17
rhourahane 1:b23f5561266c 18 I2CEeprom::I2CEeprom(PinName sda, PinName scl, int address, size_t pageSize, size_t chipSize, int busSpeed):
rhourahane 1:b23f5561266c 19 m_i2c(sda, scl),
rhourahane 1:b23f5561266c 20 m_i2cAddress(address),
rhourahane 1:b23f5561266c 21 m_chipSize(chipSize),
rhourahane 1:b23f5561266c 22 m_pageSize(pageSize)
rhourahane 1:b23f5561266c 23 {
rhourahane 1:b23f5561266c 24 m_i2c.frequency(busSpeed);
rhourahane 1:b23f5561266c 25 }
rhourahane 1:b23f5561266c 26
rhourahane 1:b23f5561266c 27 size_t I2CEeprom::read(size_t address, char &value) {
rhourahane 1:b23f5561266c 28 // Check the address and size fit onto the chip.
rhourahane 1:b23f5561266c 29 if (!checkSpace(address, 1))
rhourahane 1:b23f5561266c 30 return 0;
rhourahane 1:b23f5561266c 31
rhourahane 1:b23f5561266c 32 char values[] = { (address >> 8), (address & 0xFF) };
rhourahane 1:b23f5561266c 33 if (m_i2c.write(m_i2cAddress, values, 2) == 0) {
rhourahane 1:b23f5561266c 34 if (m_i2c.read(m_i2cAddress, &value, 1) == 0) {
rhourahane 1:b23f5561266c 35 return 1;
rhourahane 1:b23f5561266c 36 }
rhourahane 1:b23f5561266c 37 }
rhourahane 1:b23f5561266c 38
rhourahane 1:b23f5561266c 39 return 0;
rhourahane 1:b23f5561266c 40 }
rhourahane 1:b23f5561266c 41
rhourahane 1:b23f5561266c 42 size_t I2CEeprom::read(size_t address, char *buffer, size_t size) {
rhourahane 1:b23f5561266c 43 // Check the address and size fit onto the chip.
rhourahane 1:b23f5561266c 44 if (!checkSpace(address, size))
rhourahane 1:b23f5561266c 45 return 0;
rhourahane 1:b23f5561266c 46
rhourahane 1:b23f5561266c 47 char values[] = { (address >> 8), (address & 0xFF) };
rhourahane 1:b23f5561266c 48 if (m_i2c.write(m_i2cAddress, values, 2) == 0) {
rhourahane 1:b23f5561266c 49 if (m_i2c.read(m_i2cAddress, buffer, size) == 0) {
rhourahane 1:b23f5561266c 50 return size;
rhourahane 1:b23f5561266c 51 }
rhourahane 1:b23f5561266c 52 }
rhourahane 1:b23f5561266c 53
rhourahane 1:b23f5561266c 54 return 0;
rhourahane 1:b23f5561266c 55 }
rhourahane 1:b23f5561266c 56
rhourahane 1:b23f5561266c 57 size_t I2CEeprom::write(size_t address, char value) {
rhourahane 1:b23f5561266c 58 // Check the address and size fit onto the chip.
rhourahane 1:b23f5561266c 59 if (!checkSpace(address, 1))
rhourahane 1:b23f5561266c 60 return 0;
rhourahane 1:b23f5561266c 61
rhourahane 1:b23f5561266c 62 char values[] = { (address >> 8), (address & 0xFF), value };
rhourahane 1:b23f5561266c 63 if (m_i2c.write(m_i2cAddress, values, 3) != 0) {
rhourahane 1:b23f5561266c 64 return 0;
rhourahane 1:b23f5561266c 65 }
rhourahane 1:b23f5561266c 66
rhourahane 1:b23f5561266c 67 waitForWrite();
rhourahane 1:b23f5561266c 68
rhourahane 1:b23f5561266c 69 return 1;
rhourahane 1:b23f5561266c 70 }
rhourahane 1:b23f5561266c 71
rhourahane 1:b23f5561266c 72 size_t I2CEeprom::write(size_t address, const char *buffer, size_t size) {
rhourahane 1:b23f5561266c 73 // Check the address and size fit onto the chip.
rhourahane 1:b23f5561266c 74 if (!checkSpace(address, size))
rhourahane 1:b23f5561266c 75 return 0;
rhourahane 1:b23f5561266c 76
rhourahane 1:b23f5561266c 77 const char *page = buffer;
rhourahane 1:b23f5561266c 78 size_t left = size;
rhourahane 1:b23f5561266c 79
rhourahane 1:b23f5561266c 80 // Whle we have some more data to write.
rhourahane 1:b23f5561266c 81 while (left != 0) {
rhourahane 1:b23f5561266c 82 // Calculate the number of bytes we can write in the current page.
rhourahane 1:b23f5561266c 83 // If the address is not page aligned then write enough to page
rhourahane 1:b23f5561266c 84 // align it.
rhourahane 1:b23f5561266c 85 size_t toWrite;
rhourahane 1:b23f5561266c 86 if ((address % m_pageSize) != 0) {
rhourahane 1:b23f5561266c 87 toWrite = (((address / m_pageSize) + 1) * m_pageSize) - address;
rhourahane 1:b23f5561266c 88 if (toWrite > size) {
rhourahane 1:b23f5561266c 89 toWrite = size;
rhourahane 1:b23f5561266c 90 }
rhourahane 1:b23f5561266c 91 } else {
rhourahane 1:b23f5561266c 92 if (left <= m_pageSize) {
rhourahane 1:b23f5561266c 93 toWrite = left;
rhourahane 1:b23f5561266c 94 } else {
rhourahane 1:b23f5561266c 95 toWrite = m_pageSize;
rhourahane 1:b23f5561266c 96 }
rhourahane 1:b23f5561266c 97 }
rhourahane 1:b23f5561266c 98
rhourahane 1:b23f5561266c 99 //printf("Writing [%.*s] at %d size %d\n\r", toWrite, page, address, toWrite);
rhourahane 1:b23f5561266c 100 // Start the page write with the addres ine one write call.
rhourahane 1:b23f5561266c 101 char values[] = { (address >> 8), (address & 0xFF) };
rhourahane 1:b23f5561266c 102 if (m_i2c.write(m_i2cAddress, values, 2, true) != 0) {
rhourahane 1:b23f5561266c 103 // Write failed to return bytes written so far.
rhourahane 1:b23f5561266c 104 return size - left;
rhourahane 1:b23f5561266c 105 }
rhourahane 1:b23f5561266c 106
rhourahane 1:b23f5561266c 107 // Write the bytes out one at a time to avoid having to copy them to
rhourahane 1:b23f5561266c 108 // another buffer.
rhourahane 1:b23f5561266c 109 for (int count = 0; count != toWrite; ++count) {
rhourahane 1:b23f5561266c 110 if (m_i2c.write(*page) == 0) {
rhourahane 1:b23f5561266c 111 // Write failed to return bytes written so far.
rhourahane 1:b23f5561266c 112 return size - left;
rhourahane 1:b23f5561266c 113 }
rhourahane 1:b23f5561266c 114 ++page;
rhourahane 1:b23f5561266c 115 }
rhourahane 1:b23f5561266c 116
rhourahane 1:b23f5561266c 117 // Stop the transaction now we've completed the page
rhourahane 1:b23f5561266c 118 // write.
rhourahane 1:b23f5561266c 119 m_i2c.stop();
rhourahane 1:b23f5561266c 120
rhourahane 1:b23f5561266c 121 waitForWrite();
rhourahane 1:b23f5561266c 122
rhourahane 1:b23f5561266c 123 // Update the counters with the amount we've just written
rhourahane 1:b23f5561266c 124 left -= toWrite;
rhourahane 1:b23f5561266c 125 address += toWrite;
rhourahane 1:b23f5561266c 126 }
rhourahane 1:b23f5561266c 127
rhourahane 1:b23f5561266c 128 return size;
rhourahane 1:b23f5561266c 129 }
rhourahane 1:b23f5561266c 130
rhourahane 1:b23f5561266c 131 size_t I2CEeprom::fill(size_t address, char value, size_t size) {
rhourahane 1:b23f5561266c 132 // Check the address and size fit onto the chip.
rhourahane 1:b23f5561266c 133 if (!checkSpace(address, size))
rhourahane 1:b23f5561266c 134 return 0;
rhourahane 1:b23f5561266c 135
rhourahane 1:b23f5561266c 136 size_t left = size;
rhourahane 1:b23f5561266c 137
rhourahane 1:b23f5561266c 138 while (left != 0) {
rhourahane 1:b23f5561266c 139 size_t toWrite;
rhourahane 1:b23f5561266c 140 if ((address % m_pageSize) != 0) {
rhourahane 1:b23f5561266c 141 toWrite = (((address / m_pageSize) + 1) * 64) - address;
rhourahane 1:b23f5561266c 142 if (toWrite > size) {
rhourahane 1:b23f5561266c 143 toWrite = size;
rhourahane 1:b23f5561266c 144 }
rhourahane 1:b23f5561266c 145 } else {
rhourahane 1:b23f5561266c 146 if (left <= m_pageSize) {
rhourahane 1:b23f5561266c 147 toWrite = left;
rhourahane 1:b23f5561266c 148 } else {
rhourahane 1:b23f5561266c 149 toWrite = m_pageSize;
rhourahane 1:b23f5561266c 150 }
rhourahane 1:b23f5561266c 151 }
rhourahane 1:b23f5561266c 152
rhourahane 1:b23f5561266c 153 //printf("Writing %d at %d size %d\n\r", value, address, toWrite);
rhourahane 1:b23f5561266c 154 char values[] = { (address >> 8), (address & 0xFF) };
rhourahane 1:b23f5561266c 155 if (m_i2c.write(m_i2cAddress, values, 2, true) != 0) {
rhourahane 1:b23f5561266c 156 return size - left;
rhourahane 1:b23f5561266c 157 }
rhourahane 1:b23f5561266c 158
rhourahane 1:b23f5561266c 159 for (int count = 0; count != toWrite; ++count) {
rhourahane 1:b23f5561266c 160 if (m_i2c.write(value) == 0)
rhourahane 1:b23f5561266c 161 return size - left;
rhourahane 1:b23f5561266c 162 }
rhourahane 1:b23f5561266c 163
rhourahane 1:b23f5561266c 164 m_i2c.stop();
rhourahane 1:b23f5561266c 165
rhourahane 1:b23f5561266c 166 waitForWrite();
rhourahane 1:b23f5561266c 167
rhourahane 1:b23f5561266c 168 left -= toWrite;
rhourahane 1:b23f5561266c 169 address += toWrite;
rhourahane 1:b23f5561266c 170 }
rhourahane 1:b23f5561266c 171
rhourahane 1:b23f5561266c 172 return size;
rhourahane 1:b23f5561266c 173 }
rhourahane 1:b23f5561266c 174
rhourahane 1:b23f5561266c 175 void I2CEeprom::waitForWrite() {
rhourahane 1:b23f5561266c 176 // The chip doesn't ACK while writing to the actual EEPROM
rhourahane 1:b23f5561266c 177 // so loop trying to do a zero byte write until it is ACKed
rhourahane 1:b23f5561266c 178 // by the chip.
rhourahane 1:b23f5561266c 179 while (m_i2c.write(m_i2cAddress, 0, 0) != 0) {
rhourahane 1:b23f5561266c 180 // Wait for ack.
rhourahane 1:b23f5561266c 181 wait_ms(1);
rhourahane 1:b23f5561266c 182 }
rhourahane 1:b23f5561266c 183 }
rhourahane 1:b23f5561266c 184
rhourahane 1:b23f5561266c 185 bool I2CEeprom::checkSpace(size_t address, size_t size) {
rhourahane 1:b23f5561266c 186 // Only check if chip size is non-zero.
rhourahane 1:b23f5561266c 187 if (m_chipSize != 0) {
rhourahane 1:b23f5561266c 188 // Check that the address start in the chip and doesn't
rhourahane 1:b23f5561266c 189 // extend past.
rhourahane 1:b23f5561266c 190 if ((address >= m_chipSize) || ((address + size) >= m_chipSize))
rhourahane 1:b23f5561266c 191 return false;
rhourahane 1:b23f5561266c 192 else
rhourahane 1:b23f5561266c 193 return true;
rhourahane 1:b23f5561266c 194 }
rhourahane 1:b23f5561266c 195
rhourahane 1:b23f5561266c 196 return true;
rhourahane 1:b23f5561266c 197 }
rhourahane 1:b23f5561266c 198