Update current library to accommodate small devices.

Committer:
jonebuckman
Date:
Fri Jan 13 15:30:12 2017 +0000
Revision:
8:e92faf840345
Parent:
7:3e1f751bcc81
Child:
10:839cd28531dd
Corrected waitForWrite.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jonebuckman 0:bcc1f1890330 1 /* Simple access class for I2C EEPROM chips like Microchip 24LC
jonebuckman 0:bcc1f1890330 2 * Copyright (c) 2016 Jon Buckman
jonebuckman 0:bcc1f1890330 3 * Copyright (c) 2015 Robin Hourahane
jonebuckman 0:bcc1f1890330 4 *
jonebuckman 0:bcc1f1890330 5 * Licensed under the Apache License, Version 2.0 (the "License");
jonebuckman 0:bcc1f1890330 6 * you may not use this file except in compliance with the License.
jonebuckman 0:bcc1f1890330 7 * You may obtain a copy of the License at
jonebuckman 0:bcc1f1890330 8 *
jonebuckman 0:bcc1f1890330 9 * http://www.apache.org/licenses/LICENSE-2.0
jonebuckman 0:bcc1f1890330 10 *
jonebuckman 0:bcc1f1890330 11 * Unless required by applicable law or agreed to in writing, software
jonebuckman 0:bcc1f1890330 12 * distributed under the License is distributed on an "AS IS" BASIS,
jonebuckman 0:bcc1f1890330 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
jonebuckman 0:bcc1f1890330 14 * See the License for the specific language governing permissions and
jonebuckman 0:bcc1f1890330 15 * limitations under the License.
jonebuckman 0:bcc1f1890330 16 */
jonebuckman 0:bcc1f1890330 17 #include "I2CEEPROM.h"
jonebuckman 0:bcc1f1890330 18
jonebuckman 0:bcc1f1890330 19 I2CEEPROM::I2CEEPROM(PinName sda, PinName scl, int address, size_t pageSize, size_t chipSize, int busSpeed):
jonebuckman 0:bcc1f1890330 20 m_i2c(sda, scl),
jonebuckman 0:bcc1f1890330 21 m_i2cAddress(address),
jonebuckman 0:bcc1f1890330 22 m_chipSize(chipSize),
jonebuckman 0:bcc1f1890330 23 m_pageSize(pageSize)
jonebuckman 0:bcc1f1890330 24 {
jonebuckman 0:bcc1f1890330 25 m_i2c.frequency(busSpeed);
jonebuckman 0:bcc1f1890330 26 }
jonebuckman 0:bcc1f1890330 27
jonebuckman 0:bcc1f1890330 28 size_t I2CEEPROM::read(size_t address, char &value) {
jonebuckman 0:bcc1f1890330 29 // Check the address and size fit onto the chip.
jonebuckman 0:bcc1f1890330 30 if (!checkSpace(address, 1))
jonebuckman 0:bcc1f1890330 31 return 0;
jonebuckman 7:3e1f751bcc81 32 if(m_chipSize == 256 || m_chipSize == 128 || m_chipSize == 16) {
jonebuckman 7:3e1f751bcc81 33 char values[] = { (address & 0xFF) };
jonebuckman 7:3e1f751bcc81 34 if (m_i2c.write(m_i2cAddress, values, 1) == 0) {
jonebuckman 7:3e1f751bcc81 35 if (m_i2c.read(m_i2cAddress, &value, 1) == 0) {
jonebuckman 7:3e1f751bcc81 36 return 1;
jonebuckman 7:3e1f751bcc81 37 }
jonebuckman 7:3e1f751bcc81 38 }
jonebuckman 7:3e1f751bcc81 39 }
jonebuckman 7:3e1f751bcc81 40 else {
jonebuckman 7:3e1f751bcc81 41 char values[] = { (address >> 8), (address & 0xFF) };
jonebuckman 7:3e1f751bcc81 42 if (m_i2c.write(m_i2cAddress, values, 2) == 0) {
jonebuckman 7:3e1f751bcc81 43 if (m_i2c.read(m_i2cAddress, &value, 1) == 0) {
jonebuckman 7:3e1f751bcc81 44 return 1;
jonebuckman 7:3e1f751bcc81 45 }
jonebuckman 0:bcc1f1890330 46 }
jonebuckman 0:bcc1f1890330 47 }
jonebuckman 0:bcc1f1890330 48
jonebuckman 0:bcc1f1890330 49 return 0;
jonebuckman 0:bcc1f1890330 50 }
jonebuckman 0:bcc1f1890330 51
jonebuckman 0:bcc1f1890330 52 size_t I2CEEPROM::read(size_t address, char *buffer, size_t size) {
jonebuckman 0:bcc1f1890330 53 // Check the address and size fit onto the chip.
jonebuckman 0:bcc1f1890330 54 if (!checkSpace(address, size))
jonebuckman 0:bcc1f1890330 55 return 0;
jonebuckman 0:bcc1f1890330 56
jonebuckman 7:3e1f751bcc81 57 if(m_chipSize == 256 || m_chipSize == 128 || m_chipSize == 16) {
jonebuckman 7:3e1f751bcc81 58 char values[] = { (address & 0xFF) };
jonebuckman 7:3e1f751bcc81 59 if (m_i2c.write(m_i2cAddress, values, 1) == 0) {
jonebuckman 7:3e1f751bcc81 60 if (m_i2c.read(m_i2cAddress, buffer, size) == 0) {
jonebuckman 7:3e1f751bcc81 61 return size;
jonebuckman 7:3e1f751bcc81 62 }
jonebuckman 7:3e1f751bcc81 63 }
jonebuckman 7:3e1f751bcc81 64 }
jonebuckman 7:3e1f751bcc81 65 else {
jonebuckman 7:3e1f751bcc81 66 char values[] = { (address >> 8), (address & 0xFF) };
jonebuckman 7:3e1f751bcc81 67 if (m_i2c.write(m_i2cAddress, values, 2) == 0) {
jonebuckman 7:3e1f751bcc81 68 if (m_i2c.read(m_i2cAddress, buffer, size) == 0) {
jonebuckman 7:3e1f751bcc81 69 return size;
jonebuckman 7:3e1f751bcc81 70 }
jonebuckman 0:bcc1f1890330 71 }
jonebuckman 0:bcc1f1890330 72 }
jonebuckman 0:bcc1f1890330 73
jonebuckman 0:bcc1f1890330 74 return 0;
jonebuckman 0:bcc1f1890330 75 }
jonebuckman 0:bcc1f1890330 76
jonebuckman 0:bcc1f1890330 77 size_t I2CEEPROM::write(size_t address, char value) {
jonebuckman 0:bcc1f1890330 78 // Check the address and size fit onto the chip.
jonebuckman 0:bcc1f1890330 79 if (!checkSpace(address, 1))
jonebuckman 0:bcc1f1890330 80 return 0;
jonebuckman 0:bcc1f1890330 81
jonebuckman 7:3e1f751bcc81 82 if(m_chipSize == 256 || m_chipSize == 128 || m_chipSize == 16) {
jonebuckman 7:3e1f751bcc81 83 char values[] = { (address & 0xFF), value };
jonebuckman 7:3e1f751bcc81 84 if (m_i2c.write(m_i2cAddress, values, 2) != 0) {
jonebuckman 7:3e1f751bcc81 85 return 0;
jonebuckman 7:3e1f751bcc81 86 }
jonebuckman 7:3e1f751bcc81 87 }
jonebuckman 7:3e1f751bcc81 88 else {
jonebuckman 7:3e1f751bcc81 89 char values[] = { (address >> 8), (address & 0xFF), value };
jonebuckman 7:3e1f751bcc81 90 if (m_i2c.write(m_i2cAddress, values, 3) != 0) {
jonebuckman 7:3e1f751bcc81 91 return 0;
jonebuckman 7:3e1f751bcc81 92 }
jonebuckman 0:bcc1f1890330 93 }
jonebuckman 0:bcc1f1890330 94
jonebuckman 0:bcc1f1890330 95 waitForWrite();
jonebuckman 0:bcc1f1890330 96
jonebuckman 0:bcc1f1890330 97 return 1;
jonebuckman 0:bcc1f1890330 98 }
jonebuckman 0:bcc1f1890330 99
jonebuckman 0:bcc1f1890330 100 size_t I2CEEPROM::write(size_t address, const char *buffer, size_t size) {
jonebuckman 0:bcc1f1890330 101 // Check the address and size fit onto the chip.
jonebuckman 7:3e1f751bcc81 102 if (!checkSpace(address, size))
jonebuckman 0:bcc1f1890330 103 return 0;
jonebuckman 0:bcc1f1890330 104
jonebuckman 0:bcc1f1890330 105 const char *page = buffer;
jonebuckman 0:bcc1f1890330 106 size_t left = size;
jonebuckman 0:bcc1f1890330 107
jonebuckman 0:bcc1f1890330 108 // Whle we have some more data to write.
jonebuckman 0:bcc1f1890330 109 while (left != 0) {
jonebuckman 0:bcc1f1890330 110 // Calculate the number of bytes we can write in the current page.
jonebuckman 0:bcc1f1890330 111 // If the address is not page aligned then write enough to page
jonebuckman 0:bcc1f1890330 112 // align it.
jonebuckman 0:bcc1f1890330 113 size_t toWrite;
jonebuckman 0:bcc1f1890330 114 if ((address % m_pageSize) != 0) {
jonebuckman 0:bcc1f1890330 115 toWrite = (((address / m_pageSize) + 1) * m_pageSize) - address;
jonebuckman 0:bcc1f1890330 116 if (toWrite > size) {
jonebuckman 0:bcc1f1890330 117 toWrite = size;
jonebuckman 0:bcc1f1890330 118 }
jonebuckman 0:bcc1f1890330 119 } else {
jonebuckman 0:bcc1f1890330 120 if (left <= m_pageSize) {
jonebuckman 0:bcc1f1890330 121 toWrite = left;
jonebuckman 0:bcc1f1890330 122 } else {
jonebuckman 0:bcc1f1890330 123 toWrite = m_pageSize;
jonebuckman 0:bcc1f1890330 124 }
jonebuckman 0:bcc1f1890330 125 }
jonebuckman 0:bcc1f1890330 126
jonebuckman 7:3e1f751bcc81 127 //printf("Writing [%.*s] at %d size %d\n\r", toWrite, page, address, toWrite);
jonebuckman 7:3e1f751bcc81 128 // Start the page write with the addres ine one write call.
jonebuckman 7:3e1f751bcc81 129 if(m_chipSize == 256 || m_chipSize == 128 || m_chipSize == 16) {
jonebuckman 7:3e1f751bcc81 130 char values[] = { (address & 0xFF) };
jonebuckman 7:3e1f751bcc81 131 if (m_i2c.write(m_i2cAddress, values, 1, true) != 0) {
jonebuckman 7:3e1f751bcc81 132 // Write failed to return bytes written so far.
jonebuckman 7:3e1f751bcc81 133 return size - left;
jonebuckman 7:3e1f751bcc81 134 }
jonebuckman 7:3e1f751bcc81 135 }
jonebuckman 7:3e1f751bcc81 136 else {
jonebuckman 7:3e1f751bcc81 137 char values[] = { (address >> 8), (address & 0xFF) };
jonebuckman 7:3e1f751bcc81 138 if (m_i2c.write(m_i2cAddress, values, 2, true) != 0) {
jonebuckman 7:3e1f751bcc81 139 // Write failed to return bytes written so far.
jonebuckman 7:3e1f751bcc81 140 return size - left;
jonebuckman 7:3e1f751bcc81 141 }
jonebuckman 7:3e1f751bcc81 142 }
jonebuckman 7:3e1f751bcc81 143
jonebuckman 7:3e1f751bcc81 144 // Write the bytes out one at a time to avoid having to copy them to
jonebuckman 7:3e1f751bcc81 145 // another buffer.
jonebuckman 6:8dc89c3b4718 146 for (int count = 0; count != toWrite; ++count) {
jonebuckman 7:3e1f751bcc81 147 if (m_i2c.write(*page) == 0) {
jonebuckman 6:8dc89c3b4718 148 // Write failed to return bytes written so far.
jonebuckman 6:8dc89c3b4718 149 return size - left;
jonebuckman 0:bcc1f1890330 150 }
jonebuckman 6:8dc89c3b4718 151 ++page;
jonebuckman 0:bcc1f1890330 152 }
jonebuckman 0:bcc1f1890330 153
jonebuckman 7:3e1f751bcc81 154 // Stop the transaction now we've completed the page
jonebuckman 7:3e1f751bcc81 155 // write.
jonebuckman 7:3e1f751bcc81 156 m_i2c.stop();
jonebuckman 7:3e1f751bcc81 157
jonebuckman 7:3e1f751bcc81 158 waitForWrite();
jonebuckman 7:3e1f751bcc81 159
jonebuckman 0:bcc1f1890330 160 // Update the counters with the amount we've just written
jonebuckman 0:bcc1f1890330 161 left -= toWrite;
jonebuckman 0:bcc1f1890330 162 address += toWrite;
jonebuckman 0:bcc1f1890330 163 }
jonebuckman 7:3e1f751bcc81 164
jonebuckman 0:bcc1f1890330 165 return size;
jonebuckman 0:bcc1f1890330 166 }
jonebuckman 0:bcc1f1890330 167
jonebuckman 0:bcc1f1890330 168 size_t I2CEEPROM::fill(size_t address, char value, size_t size) {
jonebuckman 0:bcc1f1890330 169 // Check the address and size fit onto the chip.
jonebuckman 0:bcc1f1890330 170 if (!checkSpace(address, size))
jonebuckman 0:bcc1f1890330 171 return 0;
jonebuckman 0:bcc1f1890330 172
jonebuckman 0:bcc1f1890330 173 size_t left = size;
jonebuckman 7:3e1f751bcc81 174
jonebuckman 0:bcc1f1890330 175 while (left != 0) {
jonebuckman 7:3e1f751bcc81 176 size_t toWrite;
jonebuckman 0:bcc1f1890330 177 if ((address % m_pageSize) != 0) {
jonebuckman 0:bcc1f1890330 178 toWrite = (((address / m_pageSize) + 1) * m_pageSize) - address;
jonebuckman 0:bcc1f1890330 179 if (toWrite > size) {
jonebuckman 0:bcc1f1890330 180 toWrite = size;
jonebuckman 0:bcc1f1890330 181 }
jonebuckman 0:bcc1f1890330 182 } else {
jonebuckman 0:bcc1f1890330 183 if (left <= m_pageSize) {
jonebuckman 0:bcc1f1890330 184 toWrite = left;
jonebuckman 0:bcc1f1890330 185 } else {
jonebuckman 0:bcc1f1890330 186 toWrite = m_pageSize;
jonebuckman 0:bcc1f1890330 187 }
jonebuckman 0:bcc1f1890330 188 }
jonebuckman 0:bcc1f1890330 189
jonebuckman 0:bcc1f1890330 190 //printf("Writing %d at %d size %d\n\r", value, address, toWrite);
jonebuckman 7:3e1f751bcc81 191 if(m_chipSize == 256 || m_chipSize == 128 || m_chipSize == 16) {
jonebuckman 7:3e1f751bcc81 192 char values[] = { (address & 0xFF) };
jonebuckman 7:3e1f751bcc81 193 if (m_i2c.write(m_i2cAddress, values, 1, true) != 0) {
jonebuckman 7:3e1f751bcc81 194 return size - left;
jonebuckman 7:3e1f751bcc81 195 }
jonebuckman 7:3e1f751bcc81 196 }
jonebuckman 7:3e1f751bcc81 197 else {
jonebuckman 7:3e1f751bcc81 198 char values[] = { (address >> 8), (address & 0xFF) };
jonebuckman 7:3e1f751bcc81 199 if (m_i2c.write(m_i2cAddress, values, 2, true) != 0) {
jonebuckman 6:8dc89c3b4718 200 return size - left;
jonebuckman 0:bcc1f1890330 201 }
jonebuckman 0:bcc1f1890330 202 }
jonebuckman 0:bcc1f1890330 203
jonebuckman 7:3e1f751bcc81 204 for (int count = 0; count != toWrite; ++count) {
jonebuckman 7:3e1f751bcc81 205 if (m_i2c.write(value) == 0)
jonebuckman 7:3e1f751bcc81 206 return size - left;
jonebuckman 7:3e1f751bcc81 207 }
jonebuckman 7:3e1f751bcc81 208
jonebuckman 7:3e1f751bcc81 209 m_i2c.stop();
jonebuckman 7:3e1f751bcc81 210
jonebuckman 7:3e1f751bcc81 211 waitForWrite();
jonebuckman 7:3e1f751bcc81 212
jonebuckman 0:bcc1f1890330 213 left -= toWrite;
jonebuckman 0:bcc1f1890330 214 address += toWrite;
jonebuckman 0:bcc1f1890330 215 }
jonebuckman 0:bcc1f1890330 216
jonebuckman 0:bcc1f1890330 217 return size;
jonebuckman 0:bcc1f1890330 218 }
jonebuckman 0:bcc1f1890330 219
jonebuckman 0:bcc1f1890330 220 void I2CEEPROM::waitForWrite() {
jonebuckman 0:bcc1f1890330 221 // The chip doesn't ACK while writing to the actual EEPROM
jonebuckman 0:bcc1f1890330 222 // so loop trying to do a zero byte write until it is ACKed
jonebuckman 0:bcc1f1890330 223 // by the chip.
jonebuckman 8:e92faf840345 224 while (m_i2c.write(m_i2cAddress, 0, 1) != 0) {
jonebuckman 0:bcc1f1890330 225 // Wait for ack.
jonebuckman 5:02908f98dca1 226 wait_ms(1);
jonebuckman 5:02908f98dca1 227 }
jonebuckman 0:bcc1f1890330 228 }
jonebuckman 0:bcc1f1890330 229
jonebuckman 0:bcc1f1890330 230 bool I2CEEPROM::checkSpace(size_t address, size_t size) {
jonebuckman 0:bcc1f1890330 231 // Only check if chip size is non-zero.
jonebuckman 0:bcc1f1890330 232 if (m_chipSize != 0) {
jonebuckman 0:bcc1f1890330 233 // Check that the address start in the chip and doesn't
jonebuckman 0:bcc1f1890330 234 // extend past.
jonebuckman 0:bcc1f1890330 235 if ((address >= m_chipSize) || ((address + size) >= m_chipSize))
jonebuckman 0:bcc1f1890330 236 return false;
jonebuckman 0:bcc1f1890330 237 else
jonebuckman 0:bcc1f1890330 238 return true;
jonebuckman 0:bcc1f1890330 239 }
jonebuckman 0:bcc1f1890330 240
jonebuckman 0:bcc1f1890330 241 return true;
jonebuckman 0:bcc1f1890330 242 }