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
I2CEeprom.cpp@12:d9a44fb3b9a6, 2020-03-28 (annotated)
- Committer:
- skyscraper
- Date:
- Sat Mar 28 18:03:39 2020 +0000
- Revision:
- 12:d9a44fb3b9a6
- Parent:
- 4:d8f51b136dbd
More documentation tidying and format wand
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 | 12:d9a44fb3b9a6 | 25 | //return true if system is little-endian |
skyscraper | 2:f3188aaccf80 | 26 | inline bool little_endian() |
skyscraper | 2:f3188aaccf80 | 27 | { |
skyscraper | 2:f3188aaccf80 | 28 | int n = 1; |
skyscraper | 2:f3188aaccf80 | 29 | // little endian if true |
skyscraper | 2:f3188aaccf80 | 30 | return(*(char *)&n == 1); |
skyscraper | 2:f3188aaccf80 | 31 | } |
skyscraper | 2:f3188aaccf80 | 32 | |
skyscraper | 12:d9a44fb3b9a6 | 33 | // Put EEprom address into 2 char array |
skyscraper | 12:d9a44fb3b9a6 | 34 | // in corrcet endiannness |
skyscraper | 2:f3188aaccf80 | 35 | void convert_address(size_t const & addressIn, char* arOut) |
skyscraper | 2:f3188aaccf80 | 36 | { |
skyscraper | 2:f3188aaccf80 | 37 | constexpr size_t int_size = sizeof(size_t); |
skyscraper | 2:f3188aaccf80 | 38 | union uu { |
skyscraper | 2:f3188aaccf80 | 39 | uu(size_t a) : address{a} {} |
skyscraper | 2:f3188aaccf80 | 40 | size_t address; |
skyscraper | 2:f3188aaccf80 | 41 | const char ar[int_size]; |
skyscraper | 2:f3188aaccf80 | 42 | } u{addressIn}; |
skyscraper | 2:f3188aaccf80 | 43 | static_assert(sizeof(u) == int_size,""); |
skyscraper | 2:f3188aaccf80 | 44 | if( little_endian()) { |
skyscraper | 2:f3188aaccf80 | 45 | arOut[1] = u.ar[0]; |
skyscraper | 2:f3188aaccf80 | 46 | arOut[0] = u.ar[1]; |
skyscraper | 2:f3188aaccf80 | 47 | } else { |
skyscraper | 2:f3188aaccf80 | 48 | // std::cout << "big endian\n"; |
skyscraper | 2:f3188aaccf80 | 49 | arOut[1] = u.ar[int_size - 1]; // lsb |
skyscraper | 2:f3188aaccf80 | 50 | arOut[0] = u.ar[int_size - 2]; //nextsb |
skyscraper | 2:f3188aaccf80 | 51 | } |
skyscraper | 2:f3188aaccf80 | 52 | } |
skyscraper | 2:f3188aaccf80 | 53 | } |
skyscraper | 2:f3188aaccf80 | 54 | |
skyscraper | 2:f3188aaccf80 | 55 | I2CEeprom::I2CEeprom( |
skyscraper | 12:d9a44fb3b9a6 | 56 | I2C & i2c, |
skyscraper | 12:d9a44fb3b9a6 | 57 | int address, |
skyscraper | 12:d9a44fb3b9a6 | 58 | size_t pageSize, |
skyscraper | 12:d9a44fb3b9a6 | 59 | size_t chipSize, |
skyscraper | 12:d9a44fb3b9a6 | 60 | uint8_t writeCycleTime_ms |
skyscraper | 12:d9a44fb3b9a6 | 61 | ): |
skyscraper | 2:f3188aaccf80 | 62 | m_i2c{i2c}, |
rhourahane | 1:b23f5561266c | 63 | m_i2cAddress(address), |
rhourahane | 1:b23f5561266c | 64 | m_chipSize(chipSize), |
skyscraper | 2:f3188aaccf80 | 65 | m_pageSize(pageSize), |
skyscraper | 2:f3188aaccf80 | 66 | m_writeCycleTime_ms{writeCycleTime_ms} |
skyscraper | 2:f3188aaccf80 | 67 | {} |
skyscraper | 2:f3188aaccf80 | 68 | |
skyscraper | 2:f3188aaccf80 | 69 | size_t I2CEeprom::read(size_t address, char &value) |
rhourahane | 1:b23f5561266c | 70 | { |
skyscraper | 12:d9a44fb3b9a6 | 71 | if (checkSpace(address, 1)) { |
skyscraper | 12:d9a44fb3b9a6 | 72 | char values[2]; |
skyscraper | 12:d9a44fb3b9a6 | 73 | convert_address(address,values); |
skyscraper | 12:d9a44fb3b9a6 | 74 | if (m_i2c.write(m_i2cAddress, values, 2) == 0) { |
skyscraper | 12:d9a44fb3b9a6 | 75 | if (m_i2c.read(m_i2cAddress, &value, 1) == 0) { |
skyscraper | 12:d9a44fb3b9a6 | 76 | return 1; |
skyscraper | 12:d9a44fb3b9a6 | 77 | } |
rhourahane | 1:b23f5561266c | 78 | } |
rhourahane | 1:b23f5561266c | 79 | } |
rhourahane | 1:b23f5561266c | 80 | return 0; |
rhourahane | 1:b23f5561266c | 81 | } |
rhourahane | 1:b23f5561266c | 82 | |
skyscraper | 2:f3188aaccf80 | 83 | size_t I2CEeprom::read(size_t address, char *buffer, size_t size) |
skyscraper | 2:f3188aaccf80 | 84 | { |
skyscraper | 12:d9a44fb3b9a6 | 85 | if (checkSpace(address, size)) { |
skyscraper | 12:d9a44fb3b9a6 | 86 | char values[2]; |
skyscraper | 12:d9a44fb3b9a6 | 87 | convert_address(address,values); |
skyscraper | 12:d9a44fb3b9a6 | 88 | if (m_i2c.write(m_i2cAddress, values, 2) == 0) { |
skyscraper | 12:d9a44fb3b9a6 | 89 | if (m_i2c.read(m_i2cAddress, buffer, size) == 0) { |
skyscraper | 12:d9a44fb3b9a6 | 90 | return size; |
skyscraper | 12:d9a44fb3b9a6 | 91 | } |
rhourahane | 1:b23f5561266c | 92 | } |
rhourahane | 1:b23f5561266c | 93 | } |
rhourahane | 1:b23f5561266c | 94 | return 0; |
rhourahane | 1:b23f5561266c | 95 | } |
skyscraper | 4:d8f51b136dbd | 96 | |
skyscraper | 2:f3188aaccf80 | 97 | size_t I2CEeprom::write(size_t address, char value) |
skyscraper | 2:f3188aaccf80 | 98 | { |
skyscraper | 12:d9a44fb3b9a6 | 99 | if (checkSpace(address, 1)) { |
skyscraper | 12:d9a44fb3b9a6 | 100 | char values[3]; |
skyscraper | 12:d9a44fb3b9a6 | 101 | convert_address(address,values); |
skyscraper | 12:d9a44fb3b9a6 | 102 | values[2] = value; |
skyscraper | 12:d9a44fb3b9a6 | 103 | if (m_i2c.write(m_i2cAddress, values, 3) != 0) { |
skyscraper | 12:d9a44fb3b9a6 | 104 | return 0; |
skyscraper | 12:d9a44fb3b9a6 | 105 | } |
skyscraper | 12:d9a44fb3b9a6 | 106 | waitForWrite(); |
skyscraper | 12:d9a44fb3b9a6 | 107 | return 1; |
skyscraper | 12:d9a44fb3b9a6 | 108 | } else { |
rhourahane | 1:b23f5561266c | 109 | return 0; |
rhourahane | 1:b23f5561266c | 110 | } |
rhourahane | 1:b23f5561266c | 111 | } |
rhourahane | 1:b23f5561266c | 112 | |
skyscraper | 2:f3188aaccf80 | 113 | size_t I2CEeprom::ll_write(size_t address, const char *buffer, size_t size) |
skyscraper | 2:f3188aaccf80 | 114 | { |
skyscraper | 12:d9a44fb3b9a6 | 115 | if (m_i2c.write(m_i2cAddress, buffer, size) == 0) { |
skyscraper | 12:d9a44fb3b9a6 | 116 | waitForWrite(); |
skyscraper | 12:d9a44fb3b9a6 | 117 | return size; |
skyscraper | 12:d9a44fb3b9a6 | 118 | } else { |
skyscraper | 2:f3188aaccf80 | 119 | std::cout << "EE i2c write failed\n"; |
skyscraper | 2:f3188aaccf80 | 120 | return 0; |
rhourahane | 1:b23f5561266c | 121 | } |
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 | 12:d9a44fb3b9a6 | 126 | if (checkSpace(address, size)) { |
skyscraper | 12:d9a44fb3b9a6 | 127 | size_t const malloc_size = std::min(size,m_pageSize) + 2U; |
skyscraper | 12:d9a44fb3b9a6 | 128 | char * tempBuffer = new char [malloc_size]; |
skyscraper | 12:d9a44fb3b9a6 | 129 | if ( tempBuffer == nullptr) { |
skyscraper | 12:d9a44fb3b9a6 | 130 | std::cout << "EE i2c buf malloc failed\n"; |
skyscraper | 12:d9a44fb3b9a6 | 131 | return 0; |
skyscraper | 12:d9a44fb3b9a6 | 132 | } |
skyscraper | 12:d9a44fb3b9a6 | 133 | size_t bytesLeft = size; |
skyscraper | 12:d9a44fb3b9a6 | 134 | size_t numBytesToWrite |
skyscraper | 12:d9a44fb3b9a6 | 135 | = std::min( size, m_pageSize - (address % m_pageSize)); |
skyscraper | 12:d9a44fb3b9a6 | 136 | while( bytesLeft ) { |
skyscraper | 12:d9a44fb3b9a6 | 137 | convert_address(address,tempBuffer); |
skyscraper | 12:d9a44fb3b9a6 | 138 | memcpy(tempBuffer + 2,buffer, numBytesToWrite); |
skyscraper | 12:d9a44fb3b9a6 | 139 | if ( ll_write(address,tempBuffer, numBytesToWrite + 2U) |
skyscraper | 12:d9a44fb3b9a6 | 140 | == numBytesToWrite + 2U) { |
skyscraper | 12:d9a44fb3b9a6 | 141 | buffer += numBytesToWrite; |
skyscraper | 12:d9a44fb3b9a6 | 142 | address += numBytesToWrite; |
skyscraper | 12:d9a44fb3b9a6 | 143 | bytesLeft -= numBytesToWrite; |
skyscraper | 12:d9a44fb3b9a6 | 144 | numBytesToWrite = std::min(bytesLeft,m_pageSize); |
skyscraper | 12:d9a44fb3b9a6 | 145 | } else { |
skyscraper | 12:d9a44fb3b9a6 | 146 | std::cout << "EE i2c write failed\n"; |
skyscraper | 12:d9a44fb3b9a6 | 147 | break; |
skyscraper | 12:d9a44fb3b9a6 | 148 | } |
skyscraper | 12:d9a44fb3b9a6 | 149 | } |
skyscraper | 12:d9a44fb3b9a6 | 150 | delete [] tempBuffer; |
skyscraper | 12:d9a44fb3b9a6 | 151 | return size - bytesLeft; |
skyscraper | 12:d9a44fb3b9a6 | 152 | } else { |
skyscraper | 3:b2a132553b02 | 153 | return 0; |
skyscraper | 3:b2a132553b02 | 154 | } |
rhourahane | 1:b23f5561266c | 155 | } |
rhourahane | 1:b23f5561266c | 156 | |
skyscraper | 2:f3188aaccf80 | 157 | void I2CEeprom::waitForWrite() |
skyscraper | 2:f3188aaccf80 | 158 | { |
skyscraper | 2:f3188aaccf80 | 159 | ThisThread::sleep_for(m_writeCycleTime_ms); |
rhourahane | 1:b23f5561266c | 160 | // The chip doesn't ACK while writing to the actual EEPROM |
rhourahane | 1:b23f5561266c | 161 | // so loop trying to do a zero byte write until it is ACKed |
rhourahane | 1:b23f5561266c | 162 | // by the chip. |
rhourahane | 1:b23f5561266c | 163 | while (m_i2c.write(m_i2cAddress, 0, 0) != 0) { |
skyscraper | 2:f3188aaccf80 | 164 | ThisThread::sleep_for(1); |
rhourahane | 1:b23f5561266c | 165 | } |
rhourahane | 1:b23f5561266c | 166 | } |