Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: AT24C512 и ADuC848
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Все остальные микроконтроллеры
sls_
Всем привет, нужна помощь.
Память АТ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;
}
Буду благодарен за любую помощь.
DimaM
aduc848 не работал, но тем не менее кажется ошибка в его программе
функции типа i2c_rx(0); сам писал?
я когда то много времени потратил на i2c, пока application note не взял и не написал прерывание для i2c как в примере.
sls_
Цитата(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;
}
DimaM
извени лень с битиками разбиратся
просто попробуй задержки увеличить временно
sls_
Цитата(DimaM @ May 29 2007, 12:30) *
извени лень с битиками разбиратся
просто попробуй задержки увеличить временно

Понимаю.
задержки увеличивать пробовал, не помогло.
резисторы подтягивающие тоже менял от 4к до 100к разницы нет
DimaM
я использовал
http://www.silabs.com/public/documents/tpu...al/en/an113.pdf
Сергей Борщ
Цитата(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, я попробую проанализировать ваш исходник детально.
sls_
Да правильно:
MDO = ; //Data Output
MDE = ; //1-(Tx).0-(Rx).
MCO = ; //Clock Output
MDI = ; //Data Input
По поводу транзистора не уверен, в даташите не нашол. (ADuC848) хотя думаю что "i2c честный" - порты специальные
По данной Вами ссылке посмотрел но не очень понял, буду пробовать.
Сергей Борщ
Цитата(sls_ @ May 30 2007, 09:41) *
По поводу транзистора не уверен, в даташите не нашол. (ADuC848) хотя думаю что "i2c честный" - порты специальные
Мда, доку на цифровые микросхемы аналоговые девицы писать не умеют. Эта такой же ужас как и на ADuC70xx sad.gif В общем я просмотрел описание, единственное упоминание не внесло ясности:
Цитата
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 или он останется высоким.
sls_
Сделал как Вы сказали.
Подтягивающие убрал, единицу установил:
10к на +3 - уровень sda высокий
10к на землю - уровень sda низкий
Сергей Борщ
Цитата(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. попробуйте еще и прилагаемый вариант
sls_
Сергей, спасибо Вам огромное, с вашим примером все заработало, ошибку свою понял. Еще раз спасибо.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.