Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
I2CEeprom.cpp@3:b2a132553b02, 2020-03-28 (annotated)
- Committer:
- skyscraper
- Date:
- Sat Mar 28 01:38:00 2020 +0000
- Revision:
- 3:b2a132553b02
- Parent:
- 2:f3188aaccf80
- Child:
- 4:d8f51b136dbd
minor mods and clean up
Who changed what in which revision?
| User | Revision | Line number | New 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 | 2:f3188aaccf80 | 95 | // works ok | 
| 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 | |
| skyscraper | 2:f3188aaccf80 | 113 | size_t I2CEeprom::ll_write(size_t address, const char *buffer, size_t size) | 
| skyscraper | 2:f3188aaccf80 | 114 | { | 
| skyscraper | 2:f3188aaccf80 | 115 | // TODO: change i2c address bits dependent on eeprom data address | 
| skyscraper | 3:b2a132553b02 | 116 | // if size > 64k I | 
| skyscraper | 3:b2a132553b02 | 117 | if (m_i2c.write(m_i2cAddress, buffer, size) != 0) { | 
| skyscraper | 2:f3188aaccf80 | 118 | std::cout << "EE i2c write failed\n"; | 
| skyscraper | 2:f3188aaccf80 | 119 | return 0; | 
| rhourahane | 1:b23f5561266c | 120 | } | 
| skyscraper | 2:f3188aaccf80 | 121 | waitForWrite(); | 
| rhourahane | 1:b23f5561266c | 122 | return size; | 
| rhourahane | 1:b23f5561266c | 123 | } | 
| rhourahane | 1:b23f5561266c | 124 | |
| skyscraper | 2:f3188aaccf80 | 125 | // ret num written | 
| skyscraper | 2:f3188aaccf80 | 126 | size_t I2CEeprom::write(size_t address, const char *buffer, size_t size) | 
| skyscraper | 2:f3188aaccf80 | 127 | { | 
| skyscraper | 2:f3188aaccf80 | 128 | if (!checkSpace(address, size)) { | 
| rhourahane | 1:b23f5561266c | 129 | return 0; | 
| skyscraper | 2:f3188aaccf80 | 130 | } | 
| skyscraper | 3:b2a132553b02 | 131 | size_t const malloc_size = std::min(size,m_pageSize) + 2U; | 
| skyscraper | 3:b2a132553b02 | 132 | char * tempBuffer = new char [malloc_size]; | 
| skyscraper | 3:b2a132553b02 | 133 | if ( tempBuffer == nullptr){ | 
| skyscraper | 3:b2a132553b02 | 134 | std::cout << "EE i2c buf malloc failed\n"; | 
| skyscraper | 3:b2a132553b02 | 135 | return 0; | 
| skyscraper | 3:b2a132553b02 | 136 | } | 
| skyscraper | 2:f3188aaccf80 | 137 | size_t bytesLeft = size; | 
| skyscraper | 2:f3188aaccf80 | 138 | size_t numBytesToWrite | 
| skyscraper | 3:b2a132553b02 | 139 | = std::min( size, m_pageSize - (address % m_pageSize)); | 
| skyscraper | 2:f3188aaccf80 | 140 | while(bytesLeft) { | 
| skyscraper | 3:b2a132553b02 | 141 | convert_address(address,tempBuffer); | 
| skyscraper | 3:b2a132553b02 | 142 | memcpy(tempBuffer + 2,buffer, numBytesToWrite); | 
| skyscraper | 3:b2a132553b02 | 143 | if ( ll_write(address,tempBuffer, numBytesToWrite + 2U) | 
| skyscraper | 3:b2a132553b02 | 144 | == numBytesToWrite + 2U) { | 
| skyscraper | 2:f3188aaccf80 | 145 | buffer += numBytesToWrite; | 
| skyscraper | 2:f3188aaccf80 | 146 | address += numBytesToWrite; | 
| skyscraper | 2:f3188aaccf80 | 147 | bytesLeft -= numBytesToWrite; | 
| skyscraper | 2:f3188aaccf80 | 148 | numBytesToWrite = std::min(bytesLeft,m_pageSize); | 
| rhourahane | 1:b23f5561266c | 149 | } else { | 
| skyscraper | 3:b2a132553b02 | 150 | std::cout << "EE i2c write failed\n"; | 
| skyscraper | 2:f3188aaccf80 | 151 | break; | 
| rhourahane | 1:b23f5561266c | 152 | } | 
| rhourahane | 1:b23f5561266c | 153 | } | 
| skyscraper | 3:b2a132553b02 | 154 | delete [] tempBuffer; | 
| skyscraper | 2:f3188aaccf80 | 155 | return size - bytesLeft; | 
| rhourahane | 1:b23f5561266c | 156 | } | 
| rhourahane | 1:b23f5561266c | 157 | |
| skyscraper | 2:f3188aaccf80 | 158 | void I2CEeprom::waitForWrite() | 
| skyscraper | 2:f3188aaccf80 | 159 | { | 
| skyscraper | 3:b2a132553b02 | 160 | |
| skyscraper | 2:f3188aaccf80 | 161 | ThisThread::sleep_for(m_writeCycleTime_ms); | 
| rhourahane | 1:b23f5561266c | 162 | // The chip doesn't ACK while writing to the actual EEPROM | 
| rhourahane | 1:b23f5561266c | 163 | // so loop trying to do a zero byte write until it is ACKed | 
| rhourahane | 1:b23f5561266c | 164 | // by the chip. | 
| rhourahane | 1:b23f5561266c | 165 | while (m_i2c.write(m_i2cAddress, 0, 0) != 0) { | 
| rhourahane | 1:b23f5561266c | 166 | // Wait for ack. | 
| skyscraper | 2:f3188aaccf80 | 167 | ThisThread::sleep_for(1); | 
| rhourahane | 1:b23f5561266c | 168 | } | 
| rhourahane | 1:b23f5561266c | 169 | } | 
| rhourahane | 1:b23f5561266c | 170 | |
| skyscraper | 2:f3188aaccf80 | 171 | bool I2CEeprom::checkSpace(size_t address, size_t size) | 
| skyscraper | 2:f3188aaccf80 | 172 | { | 
| skyscraper | 2:f3188aaccf80 | 173 | // Only check, if chip size is non-zero. | 
| rhourahane | 1:b23f5561266c | 174 | if (m_chipSize != 0) { | 
| rhourahane | 1:b23f5561266c | 175 | // Check that the address start in the chip and doesn't | 
| rhourahane | 1:b23f5561266c | 176 | // extend past. | 
| rhourahane | 1:b23f5561266c | 177 | if ((address >= m_chipSize) || ((address + size) >= m_chipSize)) | 
| rhourahane | 1:b23f5561266c | 178 | return false; | 
| rhourahane | 1:b23f5561266c | 179 | else | 
| rhourahane | 1:b23f5561266c | 180 | return true; | 
| rhourahane | 1:b23f5561266c | 181 | } | 
| skyscraper | 2:f3188aaccf80 | 182 | |
| rhourahane | 1:b23f5561266c | 183 | return true; | 
| rhourahane | 1:b23f5561266c | 184 | } |