Проблемы чтения и записи внешнего EEPROM: ненужные значения в коммуникации I2C

У меня есть контроллер ESP32, и я использую AT24C1024 для связи. В моём коде я пытаюсь обратиться к внешней памяти EEPROM в позициях записи данных от 0 до 10000, где данные позиции = '1'. Однако при чтении данных из позиции '1' иногда возникают ненужные значения, такие как 0, 255 или старые записанные значения. Я уже пробовал менять тактовую частоту с помощью Wire.setClock(100000) и несколько раз записывал данные в эту ячейку, но эти изменения не решили проблему.

#include <Wire.h>

#define EEPROM_ADDR 0x50  
#define SDA_PIN 21        
#define SCL_PIN 22        
#define DATA_LIMIT 10000   
#define VALUE 1   

void setup() {
  Serial.begin(115200);  
  // Wire.begin(SDA_PIN, SCL_PIN);  

  Wire.begin();        


  for (uint16_t i = 0; i < DATA_LIMIT; i++) {
    writeEEPROM(i, VALUE);  
  }

  for (uint16_t i = 0; i < DATA_LIMIT; i++) {
    uint8_t value = readEEPROM(i);
      Serial.print(i);
      Serial.print(" -> ");
      Serial.println(value);
    delay(30);
  }
  Serial.println("End");
}

void loop() {
}

void writeEEPROM(uint16_t memAddress, uint8_t data) {
  Wire.beginTransmission(EEPROM_ADDR);
  Wire.write((int)(memAddress >> 8));   
  Wire.write((int)(memAddress & 0xFF)); 
  Wire.write(data);                     
  uint8_t result = Wire.endTransmission();

  if (result != 0) {
    Serial.print("'W'- F : ");
  }
  delay(10);  
}


uint8_t readEEPROM(uint16_t memAddress) {
  Wire.beginTransmission(EEPROM_ADDR);
  Wire.write((int)(memAddress >> 8));   // MSB of memory address
  Wire.write((int)(memAddress & 0xFF)); // LSB of memory address
  Wire.endTransmission();
  
  Wire.requestFrom(EEPROM_ADDR, 1);
  if (Wire.available()) {
    return Wire.read();  
  }
  
  return 0;
}

, 👍1


1 ответ


1

Wire.beginTransmission(EEPROM_ADDR);

Хотя этот код может работать при адресации первой страницы памяти, однако, если вы внимательно прочитаете техническое описание в разделе Адресация устройств и Рисунок 7 Адресация устройств,

|  1 |  0 |  1 |  0 |  0 | A1 | Pg | R/W |
  MSB                                LSB

Адресация I2C включает бит адреса страницы памяти и состояние вывода A1. Поэтому, если предположить, что A1 равен 0 при внутреннем подтягивании вниз или отсутствии аппаратного обеспечения, правильная адресация должна быть такой.

Wire.beginTransmission((uint8_t)(EPROM_ADDR | (uint8_t) (dataAddress >> 16));

Сама библиотека Wire будет отвечать за преобразование 7-битной адресации I2C в 8-битную адресацию I2C и бит чтения/записи.

Кстати, хотя код типа Wire.write((int)(memAddress >> 8)); может быть использован компилятором, но поскольку Wire.write() принимает в качестве параметра аргумент uint8_t, преобразование типа должно быть (uint8_t) (memAddress >> 8) вместо (int) (memAddress >> 8).

,

Поскольку диапазон memAddress — [0, 9999], все биты выше 2^13 равны нулю. Поэтому это не может быть причиной проблемы., @the busybee

@thebusybee, в техническом описании (стр. 3) говорится, что память «внутренне организована как 512 страниц по 256 байт каждая»., @hcheung

Wire.beginTransmission ((uint8_t)(EPROM_ADDR | (uint8_t) (dataAddress >> 16)); и (uint8_t) (memAddress >> 8) . Я изменил эту конфигурацию, она верна, но теперь также данные с позиции 0 до 10000 записываются как «1», при этом появляется нежелательный символ (0, 255 и старые данные), только данные примерно 9500 верны, другие данные содержат нежелательный символ., @Gopal

Внесли ли вы соответствующие изменения в readEEPROM(uint16_t memAddress) и Wire.requestFrom(EEPROM_ADDR, 1);?, @hcheung

"_512 страниц по 256 байт_" Да, и для 10 000 байт требуется 40 страниц. Поэтому номер страницы, вычисленный по memAddress, никогда не изменит старший бит P0, который всегда равен 0., @the busybee

@hcheung, я уже изменил метод readEEPROM(uint16_t memAddress), а также ссылку [AT24C1024_lib] (https://github.com/jwhiddon/AT24C1024/blob/master/AT24C1024.cpp), это также мусорное значение приходит, и мое соединение esp32 и AT24C1024 [NC, A1, NC, GND, WP - GND ] [VCC - 5 В] [СКЛ - 22] [ПДД - 21], @Gopal