|
|
  |
AT24C512 и ADuC848, проблемма с чтением |
|
|
|
May 29 2007, 07:35
|
Участник

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

|
Всем привет, нужна помощь. Память АТ24С512 и часы D1340 подключены к ADuC848 по I2C. Проблемма: при чтении из памяти по байтно при единичном чтении из любой ячейки чтение корректно, но как только начинаю читать этой же функцией несколько байт подряд значения зависят от прдидущего прочитанного байта. Т.е. если предидущий прочитанный байт содержит чотное число следующее читается верно, если не четное то прочитанное число на 128 больше. Пример: Ячейка Записываю Считываю ----0-----------0------------0 ----1-----------1------------1 ----2-----------2----------130 ----3-----------3------------3 ----4-----------4----------132 Такое ощущение что младший бит предидущего байта попадает в старший последующего. Пробовал читать страницами эфект тотже. С часов висящих на том же порту читаю все значения корректны. функции для чтения записи: #define EEPROM_BUS_ADDRESS 0xA0 void write_byte_eeprom (unsigned int address, unsigned char datas) { i2c_start(); i2c_tx(EEPROM_BUS_ADDRESS); i2c_tx((unsigned char)address>>8); i2c_tx((unsigned char)address); i2c_tx(datas); i2c_stop(); } unsigned char read_byte_eeprom (unsigned int address) { unsigned char datas; i2c_start(); i2c_tx(EEPROM_BUS_ADDRESS); i2c_tx((unsigned char)address>>8); i2c_tx((unsigned char)address); i2c_start(); i2c_tx(EEPROM_BUS_ADDRESS | 1); datas = i2c_rx(0); i2c_stop(); return datas; } Буду благодарен за любую помощь.
|
|
|
|
|
May 29 2007, 08:08
|
Участник

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

|
Цитата(DimaM @ May 29 2007, 11:59)  aduc848 не работал, но тем не менее кажется ошибка в его программе функции типа i2c_rx(0); сам писал? я когда то много времени потратил на i2c, пока application note не взял и не написал прерывание для i2c как в примере. Эти функции опробованы на часах и на двух рахличных датчиках: void i2c_dly (void) { } void i2c_start (void) { MDE=1; MDO=1;//bSDA = 1; i2c_dly (); MCO=1;//bSCL = 1; i2c_dly (); MDE=1; MDO=0;//bSDA = 0; i2c_dly (); MCO=0;//bSCL = 0; i2c_dly (); } void i2c_stop (void) { MDE=1; MDO=0;//bSDA = 0; i2c_dly (); MCO=1;//bSCL = 1; i2c_dly (); MDE=1; MDO=1;//bSDA = 1; i2c_dly (); } char i2c_rx(char ack) { char x, d=0; MDE=1; MDO=1;//bSDA = 1; for(x=0; x<8; x++) { d <<= 1; do { MCO=1;//bSCL = 1; i2c_dly (); } while(MCO==0); //SCL_IN==0 i2c_dly(); MDE=0; if(MDI) d |= 1; //SDA_IN MCO=0;//bSCL = 0; } if(ack){MDE=1; MDO=0;}// bSDA = 0; else {MDE=1; MDO=1;}//bSDA = 1; MCO=1;//bSCL = 1; i2c_dly(); MCO=0;//bSCL = 0; MDE=1; MDO=1;//bSDA = 1; return d; } bit i2c_tx(unsigned char d) { char x; static bit b; for(x=8; x; x--) { if(d&0x80) {MDE=1; MDO=1;}//bSDA = 1; else {MDE=1; MDO=0;}//bSDA = 0; MCO=1;//bSCL = 1; d <<= 1; i2c_dly (); MCO=0;//bSCL = 0; i2c_dly (); } MDE=1; MDO=1;//bSDA = 1; MCO=1;//bSCL = 1; i2c_dly(); MDE=0; b = MDI;//b = bSDA; //SDA_IN MCO=0;//bSCL = 0; return b; }
|
|
|
|
|
May 29 2007, 08:37
|
Участник

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

|
Цитата(DimaM @ May 29 2007, 12:30)  извени лень с битиками разбиратся просто попробуй задержки увеличить временно Понимаю. задержки увеличивать пробовал, не помогло. резисторы подтягивающие тоже менял от 4к до 100к разницы нет
|
|
|
|
|
May 29 2007, 18:41
|

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

|
Цитата(sls_ @ May 29 2007, 10:35)  datas = i2c_rx(0); i2c_stop(); Вот тут у вас ошибка. При приеме последнего байта вы должны ответить NACK, иначе при определенных условиях не сможете сформировать стоп. Условие просто - если в следующем байте в памяти старший бит равен нулю. Память начнет выдавать его на шину сразу после ACK и не даст вам сформировать стоп - высокий уровень на SDA не появится. Не работал с 848, поэтому запутался в MDO/MDE в вашем исходнике. На всякий случай посмотрите еще вот это сообщение. P.S. ой, извиняюсь, не обратил внимания на строчки Код if(ack){MDE=1; MDO=0;}// bSDA = 0; else {MDE=1; MDO=1;}//bSDA = 1; Ответ снимаю... А правильно ли я понимаю, что MDE=1 настраивает ногу на вывод? И правильно ли я догадываюсь, что этот порт у 848 "честный", т.е. с верхним транзистором? Тогда в сообщении по ссылке скорее всего и описан корень вашей проблемы. Если нет, объясните кратенько назначение MDE и MDO, я попробую проанализировать ваш исходник детально.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
May 30 2007, 06:41
|
Участник

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

|
Да правильно: MDO = ; //Data Output MDE = ; //1-(Tx).0-(Rx). MCO = ; //Clock Output MDI = ; //Data Input По поводу транзистора не уверен, в даташите не нашол. ( ADuC848) хотя думаю что "i2c честный" - порты специальные По данной Вами ссылке посмотрел но не очень понял, буду пробовать.
|
|
|
|
|
May 30 2007, 07:35
|

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

|
Цитата(sls_ @ May 30 2007, 09:41)  По поводу транзистора не уверен, в даташите не нашол. ( ADuC848) хотя думаю что "i2c честный" - порты специальные Мда, доку на цифровые микросхемы аналоговые девицы писать не умеют. Эта такой же ужас как и на ADuC70xx  В общем я просмотрел описание, единственное упоминание не внесло ясности: Цитата Serial Interface Clock for the I2C Interface. As an input, this pin is a Schmitt- triggered input. A weak internal pull-up is present on this pin unless it is outputting logic low. This pin can also be controlled in software as a digital output pin.
Serial Data Pin for the I2C Interface. As an input, this pin has a weak internal pull-up present unless it is outputting logic low. Так в режиме вывода он пуш-пульный или открытый сток??? Если я понял все правильно, и в режиме мастера эти ноги работают в пуш-пульном режиме, то, похоже, и о работе I2C инженера этого модуля знают весьма поверхностно. Придется вам проделать эксперимент - отпаяйте подтяжку на SDATA, выдайте единицу на эту ногу и подключая 10К резистор с этой ноги на плюс и на землю посмотрите, будет ли также меняться уровень на SDATA или он останется высоким.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
May 30 2007, 07:56
|
Участник

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

|
Сделал как Вы сказали. Подтягивающие убрал, единицу установил: 10к на +3 - уровень sda высокий 10к на землю - уровень sda низкий
|
|
|
|
|
May 30 2007, 11:34
|

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

|
Цитата(sls_ @ May 30 2007, 10:56)  Подтягивающие убрал, единицу установил: 10к на +3 - уровень sda высокий 10к на землю - уровень sda низкий Значит там открытый сток. Это хорошо. Просмотрел ваш код, не нашел криминала. Только я бы в начале i2c_rx в начале вместо MDE=1; MDO=1;//bSDA = 1; пренес бы сюда MDE = 0; из цикла и выкинул бы из конца функции MDE=1; MDO=1;//bSDA = 1; т.е. в паузах держал бы линию SDA настроенной на ввод. То же и в передаче - в общем я бы их написал так: Код char i2c_rx(char ack) { char x, d=0; MDE=0; for(x=0; x<8; x++) { d <<= 1; do { MCO=1; // bSCL = 1; i2c_dly (); } while(MCO==0); // SCL_IN==0
i2c_dly(); if(MDI) d |= 1; // SDA_IN
MCO=0; // bSCL = 0; } MDE=1; // bSDA = out if(ack) MDO=0; // bSDA = 0; else MDO=1; // bSDA = 1;
MCO=1; // bSCL = 1; i2c_dly(); MCO=0; // bSCL = 0; MDE=0; // bSDA = in; return d; }
bit i2c_tx(unsigned char d) { char x; static bit b; MDE = 1; // bSDA = out for(x=0; x < 8; x++) { if(d & 0x80) MDO=1; // bSDA = 1; else MDO=0; // bSDA = 0;
MCO=1; // bSCL = 1; d <<= 1; i2c_dly (); MCO=0; // bSCL = 0; i2c_dly (); } MDE=0; // bSDA = in MCO=1; // bSCL = 1; i2c_dly(); b = MDI; // b = bSDA; //SDA_IN MCO=0; // bSCL = 0; return b; } и еще - вы уверены, что проблема именно в чтении, а не в записи? P.S. попробуйте еще и прилагаемый вариант
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
May 31 2007, 06:13
|
Участник

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

|
Сергей, спасибо Вам огромное, с вашим примером все заработало, ошибку свою понял. Еще раз спасибо.
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|