Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: PIC16F628A + 24LC512 + HT-PICC + i2c sample
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Все остальные микроконтроллеры > PIC
stas00n
Добрый день, коллеги. Подскажите, что не так я делаю? Имеется PIC16LF628A (мастер) и 24LC512 (слейв); программный i2c из примеров HT-PICC 9.80. Пытаюсь записать один байт по адресу, скажем, 0:
1. Посылаю старт-условие и управляющий байт (0b10100000);
2. Посылаю 2 байта адреса (нули);
3. Посылаю байт данных (например, 0xAA);
4. Посылаю стоп-условие.
Прием байтов (пп. 1-3) слейв подтверждает, затем контроллер генерит стоп-условие, однако память почему-то в это время держит SDA в нуле, поэтому стоп условия не получает. Зациклил для наблюдений такой кусочек кода:
CODE
while(1){
t = i2c_WriteTo(I2C_DEVICE_ADDRESS);
t = i2c_PutByte (0);
t = i2c_PutByte (0);
t = i2c_PutByte (0xAA);
i2c_Stop();
__delay_ms(10);
}

Симуляция в протеусе показывает, что слейв не отпускает SDA:

В реальном железе наблюдаю настоящим осциллографом то же самое. в линиях включены резисторы по 150 Ом, со стороны контроллера "стоповый" импульс примерно 2 В, со стороны памяти совсем маленький...
В даташите процесс записи нарисован так:

Вроде все правильно делаю, а работает неправильно.
Прилагаю модель для протеуса и прошивку, хелп!

rezident
Я извиняюсь за такой вопрос, но есть ли у вас на линиях шины I2C pull-up резисторы? Если есть, то какого номинала? "в линиях включены резисторы по 150 Ом" - это о них или о резисторах, включенных последовательно с линией?
И еще. Вы зря сразу стали пробовать запись. Попробуйте вначале проверить алгоритм работы I2C на чтении EEPROM.
stas00n
Подтяжка, естественно есть, по 10 кОм; 150 Ом последовательно в линиях SDA, SCL между памятью и МК. С чтением тоже проблемы, но еще глубоко не копал в чем дело, сейчас этим занимаюсь. Кстати, забыл сказать - все тайминги в хайтековском модуле i2c.h увеличил в 100 раз, чтоб удобней было осциллографом смотреть.
paskal
Цитата(stas00n @ Jan 10 2011, 17:07) *
Симуляция в протеусе показывает, что слейв не отпускает SDA:

Слейв может держать SDA если хочет выдать на шину данные, либо выдать бит ACK. Так как вы туда записываете, то остается последний вариант. Может вы на шине CLK не додаете 1 такт чтоб слейв закончил выдавать acknowledge? (Т.е. он выдает ACK, а фронт по CLK который заканчивает эту операцию, слейв не получает)

p.s.
А подтяжка должна быть посильнее 10 кОм
stas00n
Такты считал - ровно 9 штук:
А резисторы 10кОм рекомендованы для частоты 100 кГц, у меня будет намного меньше.
paskal
Цитата(stas00n @ Jan 10 2011, 18:58) *
Такты считал - ровно 9 штук

9-й такт должен закончится нулем. В единичном состоянии CLK, слейв не имеет права менять сигнал на SDA. попробуйте дернуть CLK еще раз, посмотрите что поменяется.
stas00n
Да! так заработало! Подправил макрос i2c_Stop() и вуаля, все пишется и читается! Спасибище огромное! cheers.gif А ведь исходник-то "фирмовый" хайтековский, вот ведь как бывает..
rezident
Кстати, напряжение половины уровня лог.1 может также свидетельствовать о некорректности реализации алгоритма I2C, когда лог.1 выдается мастером не ОК или Z-состоянием выхода SDA, а нормальной лог.1. При этом к питанию линию "тянет" транзисторный выходной каскад, а не внешний pull-up резистор. Проверьте, что это не так.
stas00n
rezident, да есть такое дело, для дергания выводами в хайтековском модуле применяются макросы SDA_HIGH(); SDA_LOW() и т.д.:
CODE

/* Change port as required - defaults to port b */
#define SCL RA1 /* clock on port A bit 1 */
#define SCL_DIR TRISA1
#define SDA RA0 /* data on port A bit 0 */
#define SDA_DIR TRISA0
#define I2CTRIS TRISA
#define I2C_INPUT 1 /* data direction input */
#define I2C_OUTPUT 0 /* data direction output */
//....
#define SCL_HIGH() SCL = 1; SCL_DIR = I2C_OUTPUT
#define SCL_LOW() SCL = 0; SCL_DIR = I2C_OUTPUT
#define SDA_HIGH() SDA = 1; SDA_DIR = I2C_OUTPUT
#define SDA_LOW() SDA = 0; SDA_DIR = I2C_OUTPUT

Может, стоит изменить их на такие:
CODE

//....
#define SCL_HIGH() SCL_DIR = I2C_INPUT
#define SCL_LOW() SCL = 0; SCL_DIR = I2C_OUTPUT
#define SDA_HIGH() SDA_DIR = I2C_INPUT
#define SDA_LOW() SDA = 0; SDA_DIR = I2C_OUTPUT
?
paskal
Цитата(rezident @ Jan 11 2011, 03:13) *
Кстати, напряжение половины уровня лог.1 может также свидетельствовать о некорректности реализации алгоритма I2C, когда лог.1 выдается мастером не ОК или Z-состоянием выхода SDA, а нормальной лог.1. При этом к питанию линию "тянет" транзисторный выходной каскад, а не внешний pull-up резистор. Проверьте, что это не так.

В том месте мастер должен быть неактивен, а 24LC512 выводить бит ACK. Может быть там на короткий момент происходит конфликт на шине когда слейв выдает 0, а мастер тянет к логической 1.


Цитата(stas00n @ Jan 11 2011, 13:56) *
Может, стоит изменить их на такие:
CODE

//....
#define SCL_HIGH() SCL_DIR = I2C_INPUT
#define SCL_LOW() SCL = 0; SCL_DIR = I2C_OUTPUT
#define SDA_HIGH() SDA_DIR = I2C_INPUT
#define SDA_LOW() SDA = 0; SDA_DIR = I2C_OUTPUT

Теоретически так и надо
rezident
Цитата(paskal @ Jan 11 2011, 22:54) *
когда слейв выдает 0, а мастер тянет к логической 1
Дык это уже криминал. Никто на шине I2C не имеет права тянуть ее принудительно к лог.1 ни в какой момент времени.
stas00n
Тем не менее, такие вот фокусы подсовывает хайтек. Реализация i2c из папки с примерами из комплекта компилятора. Уже начинаю думать - не проще ли было бы самому с нуля написать?
rezident
Цитата(stas00n @ Jan 12 2011, 03:05) *
Уже начинаю думать - не проще ли было бы самому с нуля написать?
Может и не проще, но уж точно полезнее. Вылавливать глюки в чужих программах сложнее, особенно когда для них нет никакой внятной документации (хотя бы в виде описания алгоритмов).
stas00n
Цитата(paskal @ Jan 11 2011, 19:54) *
В том месте мастер должен быть неактивен, а 24LC512 выводить бит ACK. Может быть там на короткий момент происходит конфликт на шине когда слейв выдает 0, а мастер тянет к логической 1.

Да нет, ACK нормально проходил, мастер переключался на вход, конфликт возникал позже, когда мастер пытался послать стоп-условие установкой выхода SDA в "1" (к тому же, как выяснилось, - некорректно), а слейв держал SDA в нуле из-за того что отрицательный фронт не поступал на SCL после передачи ACK.
Сейчас все исправил, работает sm.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.