Не удается прочитать записанные данные из 24AA1025

У меня есть PIC18F с MSSP, который я подключаю к 24AA1025. Я использую MPLAB 8 и функции из C18, чтобы облегчить себе жизнь. Единственная проблема в том, что я (предположительно) записал байт в 24AA1025, но когда я его считываю, я получаю 0xFF вместо записанного байта.

Вот как у меня подключена EEPROM:

A0 - GND
A1 - GND
A2 - Vcc
Vss - GND
SDA - pulled up to +5 via 2.2k resistor, and connected to SDA on PIC
SCL - pulled up to +5 via 2.2k resistor, and connected to SCL on PIC
WP - Vss
Vcc - 5V

Вот моя функция записи (теперь отредактированная с рабочим кодом):

bool I2CWriteByte( long address, unsigned char data)
{
    unsigned char ret;
    unsigned char control_byte;
    unsigned char high_address_byte;
    unsigned char low_address_byte;

    control_byte = (address >= 65536) ? 0b10101000 : 0b10100000;
    high_address_byte = (char)((address & 0x0000FF00) >> 8);
    low_address_byte = (char)(address & 0x000000FF);

    IdleI2C();

    // perform ack polling around control byte sending every time
    ret = SendControlByte( control_byte);
    if( ret == -1)
        return false;

    ret = WriteI2C( high_address_byte);
    if( ret == -1)
        return false;
    ret = WriteI2C( low_address_byte);
    if( ret == -1)
        return false;
    ret = WriteI2C( data);
    if( ret == -1)
        return false;

    StopI2C();
    return true;
}

Вот моя функция чтения (теперь отредактированная с рабочим кодом):

bool I2CReadByte( long address, unsigned char* data)
{
    unsigned char ret;
    // to do a read, first do part of a write but don't send the data byte, then send a new control byte with bit 0 set to 1 for read.
    // see 24AA1025 datasheet page 12
    unsigned char control_byte;
    unsigned char high_address_byte;
    unsigned char low_address_byte;

    control_byte = (address >= 65536) ? 0b10101000 : 0b10100000;
    high_address_byte = (char)((address & 0x0000FF00) >> 8);
    low_address_byte = (char)(address & 0x000000FF);

    IdleI2C();
    ret = SendControlByte( control_byte);
    if( ret == -1)
        return false;

    ret = WriteI2C( high_address_byte);
    if( ret == -1)
        return false;
    ret = WriteI2C( low_address_byte);
    if( ret == -1)
        return false;

    control_byte = (address >= 65536) ? 0b10101001 : 0b10100001;
    ret = SendControlByte( control_byte);
    if( ret == -1)
        return false;

    // now return value
    *data = ReadI2C();
    StopI2C();
    return true;
}

РЕДАКТИРОВАТЬ - Важнейшая функция SendControlByte(), которая выполняет необходимый опрос подтверждения:

bool SendControlByte( unsigned char control_byte)
{
    bool nack;
    bool ret;

    nack = true;

    while( nack) {
        StartI2C();
        ret = WriteI2C( control_byte);
        if( ret == -1)
            return false;
        if( SSPCON2bits.ACKSTAT == 0)
            nack = false;
    }
}

WriteI2C никогда не возвращает ошибку, поэтому я предполагаю, что это действительно сработало...

Я использовал инструмент анализа протокола I2C моего логического сниффера, и, похоже, все данные отправляются/получаются правильно:

введите описание изображения здесь

Может ли кто-нибудь предложить что-то делать дальше для отладки? Управляющий байт выглядит правильно, так как он равен 0b1010 после START, за которым следует идентификатор блока, A0, A1 и R/!W. Я проверил адреса> 64 КБ и подтвердил, что B1 установлен правильно. В моем EEPROM A0 и A1 заземлены, так что это тоже выглядит правильно. R/!W имеет низкий уровень для записи и высокий уровень непосредственно перед чтением. Единственное, что я еще не сделал, это добавил задержку после записи, но завтра попробую.

РЕДАКТИРОВАТЬ. Опция анализа I2C показывает, что вы, ребята, говорили:

введите описание изображения здесь

Вам, безусловно, нужна задержка после записи данных (попробуйте для начала 10 мс, хотя я бы порекомендовал использовать описанный опрос подтверждения, когда вы будете полировать его позже). Без него чтение, скорее всего, никогда не будет выполнено, так как устройство не будет отвечать на команды во время цикла записи. Я предполагаю, что он возвращает 0xff, потому что SDA остается высоким (поскольку устройство никогда не тянет его вниз - оно занято!).
@Dave Привет, Дэйв, ты проделал похвальную работу с инструментами тщательного анализа, которые у тебя есть. Можете ли вы рассказать, какие инструменты вы использовали для отладки I2c и захвата сигналов отправки и отображения, как показано выше. И я также хотел бы объяснить, как работает SendControlByte, я знаю, что он работает с опросом подтверждения, но когда я попытался скомпилировать код, который вы разместили ... это не сработало. Я пробовал с c18. И какие значения вы дали для истинного и ложного? Спасибо.
Привет @ Rookie91, это было давно, так что позвольте мне попытаться вспомнить. Программное обеспечение из проекта Open Logic Sniffer. Год назад мне было трудно получить работающую сборку, но последние сборки кажутся довольно хорошими. Попробуйте эту тему, чтобы получить ссылку для скачивания: опасные прототипы.com/forum/… . Что касается истинности и ложности, технически вы можете использовать все, что захотите, но типичными являются 0 для ложных и 1 для истинных. Или включите <stdbool.h> и используйте его определение.

Ответы (1)

Я предполагаю, что проблема действительно в том, что вам нужно отложить запись после записи.

Устройство будет занято примерно 3-5 миллисекунд после записи, в течение которых оно не будет отвечать ни на какие команды. Если вы выполните чтение в течение этого периода времени, устройство проигнорирует его, а линия SDA останется на высоком уровне, что действительно приведет к тому, что все будут считаны на тактовых импульсах.

Во-первых, попробуйте добавить задержку после записи, возможно, 10 миллисекунд или около того.
Если это работает, проверьте главу таблицы данных о подтверждении опроса, чтобы улучшить производительность. Короче говоря, опрос подтверждения означает отправку команды записи снова и снова, пока устройство не подтвердит ее, и в этот момент вы узнаете, что цикл записи завершен.

На самом деле следует подождать, пока EEPROM подтвердит запись. В спецификациях это описано (это называется опросом ACK ). Таким образом, вы избегаете фиксированной задержки и ждете только до тех пор, пока запись действительно занимает (но OTOH - это занятое ожидание, и ему нужна шина I2C).
Соглашаться. Вы также должны убедиться, что устройство подтверждает запрос на чтение, прежде чем продолжить чтение байта(ов) данных.
Да, из трассировки логического анализатора ясно, что чип не подтверждает байты команды/адреса для чтения. Это именно та деталь, которую должен помочь вам найти анализатор; убедитесь, что вы используете его в полной мере. Кроме того, подпрограммы прошивки I2C (в частности, WriteI2C()) должны были обнаруживать отсутствие ACK и возвращать ошибку. Ясно, что и там что-то не так.
Спасибо, ребята, сейчас поправлю код (и файлы библиотеки).
@hli Я упоминал об этом.
@exscape еще раз спасибо, хотя задержку было полезно добавить, чтобы убедиться, что код EEPROM в целом работает, ключевым моментом был опрос подтверждения. Я полностью упустил эту деталь, когда просматривал техническое описание... очень небрежно с моей стороны.
@exscape извините, после всех разговоров о задержках я полностью пропустил это :( Я просто проанализировал текст для «ACK» и пропустил это ...