Официальный сайт компании Arduino по адресу arduino.cc
Всем спасибо за замечания. Кроме упомянутых, исправлена еще пара логических ошибок и недочетов. Добавлена очистка чипа. Актуальная версия:
#include "Wire.h" #define EEPROM_I2C_ADDR 0x57 class i2cEEPROM { public: i2cEEPROM(uint8_t addr) {_i2cAddr = addr; selfTest();} //~i2cEEPROM(); uint16_t write(uint16_t addr, void* buf, size_t len); // Запись в EEPROM. uint8_t write8(uint16_t addr, uint8_t dat); uint8_t write16(uint16_t addr, uint16_t dat); uint8_t write32(uint16_t addr, uint32_t dat); uint16_t read(uint16_t addr, void* buf, size_t len); uint8_t read8(uint16_t addr); uint16_t read16(uint16_t addr); uint32_t read32(uint16_t addr); void printDump(uint16_t pages = 0); uint8_t pageSize() {return _pageSize;} uint16_t maxAddress() {return _maxaddr;} void erase(uint8_t tmpl = 0); private: uint8_t _i2cAddr; uint16_t _maxaddr = 65535; uint8_t _pageSize; void selfTest(); uint16_t pageWrite(uint16_t addr, void* buf, size_t len); uint16_t pageRead(uint16_t addr, void* buf, size_t len); uint16_t firstPageAddr(uint16_t page); }; void i2cEEPROM::selfTest(){ //tnx 2 Logik uint8_t b0 = read8(0); // Save first byte uint8_t bn; uint8_t testVal = 123; uint16_t sz[] = {2047, 4095, 8191, 16383, 32767, 65535}; uint16_t mp[] = {16, 32, 32, 64, 64, 64}; write8(0, 0); // Set first bype to 0 for (uint8_t i = 0; i < (sizeof(sz)/sizeof(sz[0])); i++){ bn = read8(sz[i]+1); // Save test byte write8(sz[i]+1, testVal); // Trying to write bype to first "out of range" address if (read8(0) != 0 || read8(sz[i]+1) != testVal){ // Test write failed _maxaddr = sz[i]; _pageSize = mp[i]; write8(0, b0); // Restore 0 byte return; } else { // Trying next size write8(sz[i]+1, bn); // Restore test byte } } } uint16_t i2cEEPROM::write(uint16_t addr, void* buf, size_t len) { if ((addr + len) > _maxaddr) return 0; uint16_t thisPage = addr / _pageSize; uint16_t count = 0; if (thisPage == (addr + len) / _pageSize) { count = pageWrite(addr, buf, len); return count; } else { count = pageWrite(addr, buf, firstPageAddr(thisPage + 1) - addr); thisPage++; while ((len - count) > _pageSize) { count += pageWrite(firstPageAddr(thisPage), (uint8_t*)buf + count, _pageSize); thisPage++; } count += pageWrite(firstPageAddr(thisPage), (uint8_t*)buf + count, len - count); } return count; } uint8_t i2cEEPROM::write16(uint16_t addr, uint16_t dat) { if ((addr + sizeof(dat)) > _maxaddr) return 0; uint16_t thisPage = addr / _pageSize; uint8_t count = 0; if (thisPage == (addr + sizeof(dat)) / _pageSize) { count = pageWrite(addr, &dat, sizeof(dat)); return count; } else { count = pageWrite(addr, &dat, firstPageAddr(thisPage + 1) - addr); thisPage++; count += pageWrite(firstPageAddr(thisPage), &dat + count, sizeof(dat) - count); } return count; } uint8_t i2cEEPROM::write32(uint16_t addr, uint32_t dat) { if ((addr + sizeof(dat)) > _maxaddr) return 0; uint16_t thisPage = addr / _pageSize; uint8_t count = 0; if (thisPage == (addr + sizeof(dat)) / _pageSize) { count = pageWrite(addr, &dat, sizeof(dat)); return count; } else { count = pageWrite(addr, &dat, firstPageAddr(thisPage + 1) - addr); thisPage++; count += pageWrite(firstPageAddr(thisPage), &dat + count, sizeof(dat) - count); } return count; } uint8_t i2cEEPROM::write8(uint16_t addr, uint8_t dat) { if (addr > _maxaddr) return 0; uint8_t count = pageWrite(addr, &dat, sizeof(dat)); return count; } uint16_t i2cEEPROM::read(uint16_t addr, void* buf, size_t len) { if ((addr + len) > _maxaddr) return 0; uint16_t ctr = 0; if (len <= I2C_BUFFER_LENGTH - 2) { ctr = pageRead(addr, buf, len); return ctr; } else { uint16_t twiPages = 0; while ((len - ctr) > (I2C_BUFFER_LENGTH - 2)) { ctr += pageRead(addr + ((I2C_BUFFER_LENGTH - 2) * twiPages), (uint8_t*)buf + ctr, (I2C_BUFFER_LENGTH - 2)); twiPages++; } ctr += pageRead(addr + ((I2C_BUFFER_LENGTH - 2) * twiPages), (uint8_t*)buf + ctr, len - ctr); } return ctr; } uint8_t i2cEEPROM::read8(uint16_t addr) { Wire.beginTransmission(_i2cAddr); Wire.write(addr >> 8); Wire.write(addr & 0xFF); Wire.endTransmission(false); Wire.requestFrom(_i2cAddr, sizeof(uint8_t)); uint8_t ret = Wire.read(); Wire.endTransmission(); return ret; } uint16_t i2cEEPROM::read16(uint16_t addr) { Wire.beginTransmission(_i2cAddr); Wire.write(addr >> 8); Wire.write(addr & 0xFF); Wire.endTransmission(false); Wire.requestFrom(_i2cAddr, 2); uint16_t ret = 0; for (uint8_t i = 0; i < 2; i++) { *((uint8_t*)&ret + i) = Wire.read(); } Wire.endTransmission(); return ret; } uint32_t i2cEEPROM::read32(uint16_t addr) { Wire.beginTransmission(_i2cAddr); Wire.write(addr >> 8); Wire.write(addr & 0xFF); Wire.endTransmission(false); Wire.requestFrom(_i2cAddr, 4); uint32_t ret = 0; for (uint8_t i = 0; i < 4; i++) { *((uint8_t*)&ret + i) = Wire.read(); } Wire.endTransmission(); return ret; } uint16_t i2cEEPROM::pageWrite(uint16_t addr, void* buf, size_t len) { uint16_t ctr = 0; Wire.beginTransmission(_i2cAddr); Wire.write(addr >> 8); Wire.write(addr & 0xFF); for (uint8_t i = 0; i < len; i++) { ctr += Wire.write(*(((uint8_t*)buf) + i)); } Wire.endTransmission(); delay(5); return ctr; } uint16_t i2cEEPROM::pageRead(uint16_t addr, void* buf, size_t len) { uint8_t* dat = (uint8_t*)buf; Wire.beginTransmission(_i2cAddr); Wire.write(addr >> 8); Wire.write(addr & 0xFF); Wire.endTransmission(false); Wire.requestFrom(_i2cAddr, len); for (uint8_t i = 0; i < len; i++) { *(dat + i) = Wire.read(); } Wire.endTransmission(); return len; } // Печатаем на экран содержимое EEPROM для визуального контроля void i2cEEPROM::printDump(uint16_t pgs){ Serial.print("Memory dump of "); Serial.print(pgs);Serial.println(" pages:"); if (pgs == 0) pgs = _maxaddr / _pageSize; for (uint8_t r = 0; r < pgs; r++) { Serial.print(r, HEX); Serial.print(": "); uint16_t addr = r * _pageSize; Wire.beginTransmission(_i2cAddr); Wire.write(addr >> 8); Wire.write(addr & 0xFF); Wire.endTransmission(false); Wire.requestFrom((int)_i2cAddr, (int)_pageSize); for(uint8_t i = 0; i < _pageSize; i++){ Serial.print(Wire.read(), HEX); Serial.print(" "); } Serial.print('\n'); } Serial.print('\n'); } void i2cEEPROM::erase(uint8_t tmpl){ uint8_t arr[_maxaddr]; for (uint16_t i = 0; i<_maxaddr; i++){ arr[i] = tmpl; } write(0, arr, _maxaddr); } uint16_t i2cEEPROM::firstPageAddr(uint16_t page) { return (page * _pageSize); } void setup() { Wire.begin(); Serial.begin(115200); Serial.print('\n'); i2cEEPROM i2c(EEPROM_I2C_ADDR); i2c.erase(); Serial.print("Max address: "); Serial.println(i2c.maxAddress()); Serial.print("Page size: "); Serial.println(i2c.pageSize()); Serial.print('\n'); /* uint8_t ts[350]; uint8_t dta = 0; for (uint16_t i = 0; i < sizeof(ts); i++) { ts[i] = dta++; if (dta> 255) dta = 0; } uint16_t address = 20; Serial.print("Write to EEPROM: "); Serial.println(i2c.write(address, &ts, sizeof(ts))); uint8_t rs[350]; Serial.print("Read from EEPROM: "); Serial.println(i2c.read(address, &rs, sizeof(rs))); for (uint16_t i = 0; i < sizeof(rs); i++) { if ((i+1)%30) {Serial.print(rs[i]); Serial.print(" ");} else Serial.println(rs[i]); } Serial.print('\n'); i2c.write8(405, 123); Serial.println(i2c.read8(405)); i2c.write16(400, 16000); Serial.println(i2c.read16(400)); i2c.write32(420, 1234567); Serial.println(i2c.read32(420)); uint32_t tt= 12345678; i2c.write(440, &tt, sizeof(tt)); Serial.println(i2c.read32(440)); */ i2c.printDump(16); } void loop() {}
Если делаете return из под if, то else не нужен. Красивее выйдет.
Хотя, лично я стремлюсь к концепту единой точки выхода. В Си это будет понятней, а в асме оптимизатор один черт джампнет из середины, полагаю.
Это логично. Спасибо. У себя поправил. Перевыкладывать из-за косметики не буду пока.
Всем спасибо за замечания. Кроме упомянутых, исправлена еще пара логических ошибок и недочетов. Добавлена очистка чипа. Актуальная версия:
Если делаете return из под if, то else не нужен. Красивее выйдет.
Хотя, лично я стремлюсь к концепту единой точки выхода. В Си это будет понятней, а в асме оптимизатор один черт джампнет из середины, полагаю.
Это логично. Спасибо. У себя поправил. Перевыкладывать из-за косметики не буду пока.