реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Проблемы с EEPROM 24LC16B, Чтение и запись данных с N-го раза
Grigorij
сообщение May 19 2008, 12:32
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 71
Регистрация: 10-03-07
Пользователь №: 26 038



Здравствуйте.

Возникла необходимость записывать данные в EEPROM 24LC16B. Для реализации интерфейса I2C взял исходник из примеров от HI-TECH-а, предварительно убрав некоторые ф-ции и подкорректировав под PIC16F690 (исправил номера портов и добавил ф-цию настройки SSP). Чтение и запись данных из/в EEPROM осуществляется с помощью следующих ф-ций:
Код
void WriteI2CEEPROM(unsigned char data)
{
       StartI2C();
       SendByteI2C(0xA0 | (EEPROMBlock << 1));
    
       I2CReadAck();
    
       SendByteI2C(EEPROMAddr);
    
       I2CReadAck();
    
       SendByteI2C(data);
       I2CReadAck();
        
       StopI2C();
}

//чтение данных из EEPROM
int ReadI2CEEPROM(void)
{
      int data = -1;    
    
      StartI2C();
      SendByteI2C(0xA0 | (EEPROMBlock << 1));
      I2CReadAck();
      
      SendByteI2C(EEPROMAddr);
      I2CReadAck();
      
      StartI2C();
      SendByteI2C(0xA0 | (EEPROMBlock << 1) | 0x01);
      I2CReadAck();
      
      data = ReadByteI2C();
      StopI2C();
      
       return data;
}


Далее в основной программе пытаюсь записать данные в EEPROM и прочить их:
Код
...
     EEPROMAddr  = 0x04; //адрес для записи данных
     EEPROMBlock = 0;

     WriteI2CEEPROM(21);

     DelayMs(10); //задержка на время записи данных

     EEPROMAddr  = 0x04; //адрес для чтения данных
     EEPROMBlock = 0;
    
     IntNumber = ReadI2CEEPROM();
...

При выполении кода, в IntNumber все время получаю число 255. Однако если вызвать несколько раз ф-цию WriteI2CEEPROM(21) (точное число раз не скажу, т.к. ф-цию вызывал в основном цикле программы для проверки правильности передачи данных с помощью осциллографа), то данные все ж таки в EEPROM записывают и их можно прочитать.

В чем может быть проблема?
Go to the top of the page
 
+Quote Post
rezident
сообщение May 19 2008, 12:41
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Может быть проблема в том, что в вашей процедуре не реализована проверка готовности EEPROM для записи? ACK вы читаете, но почему-то не анализируете.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение May 19 2008, 12:55
Сообщение #3


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(Grigorij @ May 19 2008, 15:32) *
Код
      
      data = ReadByteI2C();
      StopI2C();
      
       return data;
}
В чем может быть проблема?
Не знаю, как у вас реализована ReadByteI2C(), но между чтением последнего байта и StopI2C() должен посылаться NACK. Проверьте, делает ли это ваша ReadByteI2C(). И, согласен с rezident, анализировать результат I2CReadAck() нужно обязательно. При этом можно не делать паузу после записи - память начнет давать ACK как только закончит запись.
В железе все нормально (подтяжки есть?) ?


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Grigorij
сообщение May 19 2008, 13:46
Сообщение #4


Участник
*

Группа: Участник
Сообщений: 71
Регистрация: 10-03-07
Пользователь №: 26 038



Цитата(Сергей Борщ @ May 19 2008, 16:55) *
Не знаю, как у вас реализована ReadByteI2C(), но между чтением последнего байта и StopI2C() должен посылаться NACK. Проверьте, делает ли это ваша ReadByteI2C(). И, согласен с rezident, анализировать результат I2CReadAck() нужно обязательно. При этом можно не делать паузу после записи - память начнет давать ACK как только закончит запись.
В железе все нормально (подтяжки есть?) ?

Анализ результата I2CReadAck() есть (в приведенных примерах я его вырезал для того, чтобы было понятно в какой последовательности и что я делаю, иначе было бы еще куча if-else - ов). В железе проблем вроде как не замеченно. Линии подтянуты к питанию, ноги A0-A2 на земле, WP подключен к выводу МК и на нем установлен 0. Смотрел осциллографом состояние линий SDA, SCL на них именно те сигналы, которые я посылаю (по крайней мере для WriteI2CEEPROM() ).

Возможно проблема действительно в отсутствие сигнала NACK, завтра посмотрю и за одно выложу код ф-ции ReadByteI2C().
Go to the top of the page
 
+Quote Post
Grigorij
сообщение May 22 2008, 11:09
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 71
Регистрация: 10-03-07
Пользователь №: 26 038



Если кому будет интересно. Проблема решилась.

Оказалось, что ошибка была в примере работы с I2C из HI-TECH, который я взял за основу. В нем ф-ция после записи байта не отпускала линию SCL тем самым не завершался импульс тактирования Acknowledge-а. В итоге это приводило к тому, что линия SDA оставалась притянутой к нулю и не формировался сигнал Stop (к сожалению я не сразу на это обратил внимание, хотя на осциллографе это было хорошо видно). Ну а как следствие всего этого, запись в EEPROM не происходила.

Чтобы было понято, приведу кусок кода из HI-TECH (можно найти в папке samples\i2c\):
Код
signed char i2c_PutByte(unsigned char data)
{
     if(i2c_SendByte(data))
          return I2C_ERROR;
     return i2c_ReadAcknowledge();    /* returns ack, ~ack */
}

signed char i2c_ReadAcknowledge(void)
{
     unsigned char ack;

     SCL_LOW();                                          /* make clock is low */
     SDA_DIR = I2C_INPUT;                         /* disable data line - listen for ack */
     DelayUs(I2C_TM_SCL_TO_DATA);          /* SCL low to data out valid */
     SCL_DIR = I2C_INPUT;                         /* float clock high */
     DelayUs(I2C_TM_DATA_SU);
     ack = SDA;                                        /* read the acknowledge */

     /* wait for slave to release clock line after processing byte */
     if(i2c_WaitForSCL())
          return I2C_ERROR;
     return ack;
}

unsigned char i2c_SendByte(unsigned char byte)
{
     signed char i;

     for(i=7; i>=0; i--)
     {
          SCL_LOW();                                     /* drive clock low */        
          SDA_DIR = ((byte>>i)&0x01);
          if ((byte>>i)&0x01) {        /* bit to send */
               SDA_HIGH();
          }else {
               SDA_LOW();
          }
          DelayUs(I2C_TM_DATA_SU);
          SCL_DIR = I2C_INPUT;        /* float clock high */

          if(i2c_WaitForSCL())        /* wait for clock release */
               return TRUE;        /* bus error */

          DelayUs(I2C_TM_SCL_HIGH);    /* clock high time */
      }
    
      return FALSE;
}

После добавления в ф-цию i2c_ReadAcknowledge команды SCL_LOW() перед выходом из нее все прекрасно заработало.

Всем откликнувшися спасибо.

P.S. В коде, который я приводил в первом сообщении, ф-ции I2CReadAck() соответствует ф-ция i2c_ReadAcknowledge() из примера HI-TECH, SendByteI2C() - i2c_SendByte().

P.S.S. На эту ошибку указал dynaco на форуме microchip.ru еще в 2005 году (см. последнее сообщение на странице) smile.gif
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 14:22
Рейтинг@Mail.ru


Страница сгенерированна за 0.0141 секунд с 7
ELECTRONIX ©2004-2016