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:
amateusz
Date:
Wed Jan 31 11:54:02 2018 +0000
Revision:
2:b7877755371e
Parent:
1:b23f5561266c
Do not pass SDA & SCL pins but rather already-existing I2C object. It makes more sense when you have multiple devices on the bus (as you are supposed to in case of I2C anyway)

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
amateusz 2:b7877755371e 18 I2CEeprom::I2CEeprom(I2C *i2c_inst, int address, size_t pageSize, size_t chipSize, int busSpeed):
amateusz 2:b7877755371e 19 m_i2c(i2c_inst),
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 {
amateusz 2:b7877755371e 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) };
amateusz 2:b7877755371e 33 if (m_i2c->write(m_i2cAddress, values, 2) == 0) {
amateusz 2:b7877755371e 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) };
amateusz 2:b7877755371e 48 if (m_i2c->write(m_i2cAddress, values, 2) == 0) {
amateusz 2:b7877755371e 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 };
amateusz 2:b7877755371e 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) };
amateusz 2:b7877755371e 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) {
amateusz 2:b7877755371e 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.
amateusz 2:b7877755371e 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) };
amateusz 2:b7877755371e 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) {
amateusz 2:b7877755371e 160 if (m_i2c->write(value) == 0)
rhourahane 1:b23f5561266c 161 return size - left;
rhourahane 1:b23f5561266c 162 }
rhourahane 1:b23f5561266c 163
amateusz 2:b7877755371e 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.
amateusz 2:b7877755371e 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