Как правильно писать в I2C EEPROM?

Программирование микроконтроллеров AVR, PIC, ARM.
Разработка и изготовление печатных плат для модулей.

Как правильно писать в I2C EEPROM?

Сообщение blindman » 20 апр 2011, 07:08

Пытаюсь читать/писать I2C EEPROM (AT24C256). I2C программный, контроллер ATMega8.

Код (сокращенный, полностью в архиве):

eeprom.c
Код: Выделить всё
uint8_t eeprom_read(uint16_t address, void* buf, uint16_t count)
{
   uint8_t *b = buf;
   I2C_START;
   uint8_t ack = i2c_write(EEPROM_ADDRESS);
   if (ack) {
      I2C_STOP;
      return ack;
   }
   ack = i2c_write(address >> 8);
   if (ack) {
      I2C_STOP;
      return ack;
   }
   ack = i2c_write(address & 0xFF);
   if (ack) {
      I2C_STOP;
      return ack;
   }
   I2C_STOP;
   I2C_START;
   ack = i2c_write(EEPROM_ADDRESS | 1);
   if (ack) {
      I2C_STOP;
      return ack;
   }
   while (count) {
      *b = i2c_read(count > 1);
      b++;
      count--;
   }
   I2C_STOP;
   return ack;
}

uint8_t eeprom_write(uint16_t address, void* buf, uint16_t count)
{
   uint8_t *b = buf;
   uint8_t ack = 0;
   while (count) {
      PORTC ^= 2;
      uint8_t nbytes = 64 - (address & 63);
      if (nbytes > count) nbytes = count;
      uint8_t attempts = 100;
      while (attempts--) {
         I2C_START;
         ack = i2c_write(EEPROM_ADDRESS);
         if (!ack) break;
         else I2C_STOP;
      }
      if (ack) {
         return ack;
      }
      ack = i2c_write(address >> 8);
      if (ack) {
         I2C_STOP;
         return ack;
      }
      ack = i2c_write(address & 0xFF);
      if (ack) {
         I2C_STOP;
         return ack;
      }
      count -= nbytes;
      while (nbytes) {
         ack = i2c_write(*b);
         if (ack) {
            I2C_STOP;
            return ack;
         }
         b++;
         nbytes--;
      }
      I2C_STOP;
      address += nbytes;
   }
   uint8_t attempts = 100;
   while (attempts--) {
      I2C_START;
      uint8_t ack = i2c_write(EEPROM_ADDRESS);
      I2C_STOP;
      if (!ack) break;
   }
   return ack;
}


test.c:
Код: Выделить всё
uint8_t buf[8] = {
   1, 2, 3, 4, 5, 6, 7,
};

FILE serial = FDEV_SETUP_STREAM(fputchar, NULL, _FDEV_SETUP_WRITE);

int main(void)
{
   stdout = &serial;
   UBRRH = 0;
   UBRRL = 197;
   DDRD = (1 << 1); // TXD
   DDRC = 2;        // debug
   UCSRB = (1 << TXEN);
   if (eeprom_write(0, buf, 8)) printf("WRITE FAIL!\n\n");
   if (!eeprom_read(0, buf, 8)) {
      printf("%02X ", buf[0]);
      printf("%02X ", buf[1]);
      printf("%02X ", buf[2]);
      printf("%02X ", buf[3]);
      printf("%02X ", buf[4]);
      printf("%02X ", buf[5]);
      printf("%02X ", buf[6]);
      printf("%02X\n", buf[7]);
   }
   for(;;);
}


Чтение проходит нормально. ПЗУ поставил с записанными данными, в терминале их вижу. А новые не записываются. Когда пытаюсь писать не 8 байт, а больше, по импульсам на ноге PORTC.1 вижу, что цикл записи страницы занимает ровно столько времени, сколько нужно для вывода 67 байт (адрес I2c, 2 байта адреса памяти, 64 байта данных). По идее оно должно быть больше, так как ПЗУ после стоп-бита нужно до 5 мс для записи данных.

Подтяжку на шине I2C проверил. Нога WP притянута к земле. Что я делаю не так?
Вложения
eeprom.zip
(1.72 КиБ) Скачиваний: 0
Проект [[Open Robotics]] - универсальные модули для построения роботов
Модули Open Robotics можно приобрести в магазине shop.roboforum.ru

Day OFF? You must be pulling my leg! Stop making humor before someone sees you, fool!

Аватара пользователя
blindman
 
Сообщения: 4130
Зарегистрирован: 29 апр 2008, 21:15
Откуда: Хабаровск
прог. языки: C,C++,Assembler,PHP,Javascript,Ruby, SPIN,Java(?)
ФИО: Андрей Юрьевич

Re: Как правильно писать в I2C EEPROM?

Сообщение Radist » 20 апр 2011, 08:55

Попробуйте записать один байт для начала.
Аватара пользователя
Radist
 
Сообщения: 2253
Зарегистрирован: 01 июл 2009, 08:59
Откуда: Екатеринбург
прог. языки: асемблер AVR

Re: Как правильно писать в I2C EEPROM?

Сообщение blindman » 20 апр 2011, 09:05

Пробовал, не пишется

Добавлено спустя 5 минут 42 секунды:
Нашел косяк - неправильно формировал стоп-бит

Было вот так:
Код: Выделить всё
#define I2C_STOP {PULL_SCL; I2C_DELAY; RELEASE_SCL;  I2C_DELAY; RELEASE_SDA; I2C_DELAY;}

Сделал так - все заработало
Код: Выделить всё
#define I2C_STOP {PULL_SCL; PULL_SDA; I2C_DELAY; RELEASE_SCL;  I2C_DELAY; RELEASE_SDA; I2C_DELAY;}
Проект [[Open Robotics]] - универсальные модули для построения роботов
Модули Open Robotics можно приобрести в магазине shop.roboforum.ru

Day OFF? You must be pulling my leg! Stop making humor before someone sees you, fool!

Аватара пользователя
blindman
 
Сообщения: 4130
Зарегистрирован: 29 апр 2008, 21:15
Откуда: Хабаровск
прог. языки: C,C++,Assembler,PHP,Javascript,Ruby, SPIN,Java(?)
ФИО: Андрей Юрьевич

Re: Как правильно писать в I2C EEPROM?

Сообщение Vooon » 20 апр 2011, 09:17

А что ты так избегаешь goto? Обработка nack много раз повторяется.
Linux user | Firefox user
Аватара пользователя
Vooon
Site Admin
 
Сообщения: 3339
Зарегистрирован: 09 фев 2006, 15:36
Откуда: Москва
Skype: vooon341
прог. языки: Python, C, Bash, JavaScript, C++, PHP
ФИО: Владимир Ермаков

Re: Как правильно писать в I2C EEPROM?

Сообщение blindman » 20 апр 2011, 09:57

Не понял, откуда goto взяться?

Добавлено спустя 7 минут 29 секунд:
А, понял о чем речь. По моему, компилятор прекрасно сам с этим справляется - там паттерн {I2C_STOP; return ack;} четко выделяется.
Проект [[Open Robotics]] - универсальные модули для построения роботов
Модули Open Robotics можно приобрести в магазине shop.roboforum.ru

Day OFF? You must be pulling my leg! Stop making humor before someone sees you, fool!

Аватара пользователя
blindman
 
Сообщения: 4130
Зарегистрирован: 29 апр 2008, 21:15
Откуда: Хабаровск
прог. языки: C,C++,Assembler,PHP,Javascript,Ruby, SPIN,Java(?)
ФИО: Андрей Юрьевич

Re: Как правильно писать в I2C EEPROM?

Сообщение AVRus » 20 апр 2011, 23:11

Я вот тоже тут изучаю eeprom'ки только использую BR24C32 и параллельно ему еще I2c дисплйчик, решил не плодить темы - в CodeWizardAVR есть панелька I2c и панелька 2 wire(i2c), объясните пожалуйста в чем разница между ними ?
AVRus
 
Сообщения: 41
Зарегистрирован: 03 фев 2011, 03:23
Откуда: Новгород

Re: Как правильно писать в I2C EEPROM?

Сообщение Drunya » 22 апр 2011, 08:45

Кажись один - железный TWI, а второй - софтовый.
Глюк по-немецки означает "счастье"...
Аватара пользователя
Drunya
 
Сообщения: 196
Зарегистрирован: 05 июн 2007, 12:20
Откуда: Киев
прог. языки: C/C++, ASSEMBLER

Re: Как правильно писать в I2C EEPROM?

Сообщение AVRus » 22 апр 2011, 13:48

софтовый как я понял можно настроить на ножки любые, и есть готовая библиотека i2c.h так ?
а у железного есть такая библиотека или можно пользоваться i2c.h и в том и в том случае ?
AVRus
 
Сообщения: 41
Зарегистрирован: 03 фев 2011, 03:23
Откуда: Новгород

Re: Как правильно писать в I2C EEPROM?

Сообщение AVRus » 04 май 2011, 03:18

Апну тему новым вопросом - в каких случаях софтовый i2c с использованием i2c.h может работать намного медленней чем предполагаемые 400кГц ? например мониторчик обновляется так что я вижу как появляется строка за строкой и все 8 строк на нем обновляются примерно за 1 секунду :)
AVRus
 
Сообщения: 41
Зарегистрирован: 03 фев 2011, 03:23
Откуда: Новгород


Вернуться в Микроконтроллеры

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 22