Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Помогите по i2c, вопрос по asm
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
V000va
Разбираюсь с протоколом i2c, нашел доку (апноут) AVR 300: Software I2C™ Master Interface и файлик на асме к нему. Пытаюсь сделать програмно эмуляцию i2c под tiny2313. Так вот файлик на асме обзывается:

Title : I2C (Single) Master Implementation
;* Version : 1.0 (BETA)
;* Last updated : 97.08.27
;* Target : AT90Sxxxx (any AVR device)

Есть 2 вопроса по тексту программы:
1. Дока пишет, что частоты i2c могут быть 100 и 400кгц.
И в программе-примере соответсвенно используются специальне циклы задержки:
;* FUNCTION
;* i2c_hp_delay 100khz
;* i2c_qp_delay 100khz
;*
;* DESCRIPTION
;* hp - half i2c clock period delay (normal: 5.0us / fast: 1.3us)
;* qp - quarter i2c clock period delay (normal: 2.5us / fast: 0.6us)

В каких случаях применятся задержка на полпериода, а в каких случаях на четверть периода?

2. В первом же куске кода реализуется повторный старт, например.

_________________________________
Кусочек кода из программы для пояснения 2-го вопроса.
....
.equ SCLP = 1 ; SCL Pin number (port D)
.equ SDAP = 0 ; SDA Pin number (port D)
....

i2c_rep_start:
sbi DDRD,SCLP ; force SCL low
cbi DDRD,SDAP ; release SDA
rcall i2c_hp_delay ; half period delay
cbi DDRD,SCLP ; release SCL
rcall i2c_qp_delay ; quarter period delay

_________________________________

Берем первую команду sbi - установить бит. Регистр DDRD ведь управляет направлением работы порта ввода-вывода, каким образом реаизуется установка SCL в ноль? В тексте проги пишут :

sbi DDRD,SCLP ; force SCL low

Ну и далее по тексту идет cbi и т.д. Не понятно каким образом управляя только DDRD на выводах контроллера реализуются логические уровни? Поясните плз. Ведь чтоб на выводах что-то появилось нужно вывести порт с помощью out, например. Даже если в PORTD что-то есть, и мы конфигурируем порт на ввод, в PORTD нужно что-то положить, чтоб там было что-то и на выводе порта появилась 0 или 1. Поясните плз или подскажите плз, как по другому можно реализовать работу порта для управления только одним выводом.

PS Буду очень признателен, если кто-то поделится кусочком кода на asm, релизующего програмно i2c

---------------------------------------------------------------------
Kalina
Цитата(V000va @ Jun 23 2008, 21:02) *
Берем первую команду sbi - установить бит. Регистр DDRD ведь управляет направлением работы порта ввода-вывода, каким образом реаизуется установка SCL в ноль? В тексте проги пишут :

sbi DDRD,SCLP ; force SCL low

Ну и далее по тексту идет cbi и т.д. Не понятно каким образом управляя только DDRD на выводах контроллера реализуются логические уровни? Поясните плз.


В схеме на пине SCLP порта D должен весеть подтягивающий резистор, примерно 4,7к на питание.
1. Когда направление (по умолчанию) порта Д как вход, на SCLP логическая еденица.
2. Когда направление порта конфигурируется как выход( sbi DDRD,SCLP ), вывод SCLP коротит резистор на землю, отсюда появляется лог. еденица
V000va
Цитата(Kalina @ Jun 23 2008, 20:12) *
В схеме на пине SCLP порта D должен весеть подтягивающий резистор, примерно 4,7к на питание.
1. Когда направление (по умолчанию) порта Д как вход, на SCLP логическая еденица.
2. Когда направление порта конфигурируется как выход( sbi DDRD,SCLP ), вывод SCLP коротит резистор на землю, отсюда появляется лог. еденица


да , резистор в схеме апноута присутсвует, в пункте 2 Вашего ответа, вы хотели сказать, появляется логический 0?
Kalina
Цитата(V000va @ Jun 23 2008, 21:20) *
в пункте 2 Вашего ответа, вы хотели сказать, появляется логический 0?

Да именно так оно и есть, когда пин SCLP порта PORTD равен 0!!!!, командой sbi DDRD,SCLP вы выводите этот ноль...
_Pasha
Цитата(V000va @ Jun 23 2008, 20:02) *
В каких случаях применятся задержка на полпериода, а в каких случаях на четверть периода?

В первом же куске кода реализуется повторный старт, например.

Берем первую команду sbi - установить бит. Регистр DDRD ведь управляет направлением работы порта ввода-вывода, каким образом реаизуется установка SCL в ноль? В тексте проги пишут :

sbi DDRD,SCLP ; force SCL low
Ну и далее по тексту идет cbi и т.д. Не понятно каким образом управляя только DDRD на выводах контроллера реализуются логические уровни?


По пунктам.
1. В данном случае длительность задержки i2c_hp_delay совпала с минимальным временем паузы после старта (в доках оно называется Tsu_sta - для старта, Tsu_sto - для стопа) оно должно быть не менее 4,7мкс.
2. Поскольку i2c подразумевает выходы с открытым коллектором, во избежание неприятностей на пинах под i2c не должна появляться комбинация например DDRD.SCLP=1 и PORTD.SCLP=1. То же и SDA касается. Таким образом, весь изврат с DDRx предназначен для эмуляции выхода с открытым коллектором
V000va
Цитата(_Pasha @ Jun 23 2008, 20:29) *
По пунктам.
1. В данном случае длительность задержки i2c_hp_delay совпала с минимальным временем паузы после старта (в доках оно называется Tsu_sta - для старта, Tsu_sto - для стопа) оно должно быть не менее 4,7мкс.
2. Поскольку i2c подразумевает выходы с открытым коллектором, во избежание неприятностей на пинах под i2c не должна появляться комбинация например DDRD.SCLP=1 и PORTD.SCLP=1. То же и SDA касается. Таким образом, весь изврат с DDRx предназначен для эмуляции выхода с открытым коллектором


Со вторым пунктом вроде разобрался, а по задержкам можете пояснить подробнее?

Например в другой подпрограмме этого же дока так же используются задержки, но не понятно когда какая.


____________________________________
i2c_get_ack:
sbi DDRD,SCLP ; force SCL low
cbi DDRD,SDAP ; release SDA
rcall i2c_hp_delay ; half period delay
cbi DDRD,SCLP ; release SCL

i2c_get_ack_wait:
sbis PIND,SCLP ; wait SCL high
;(In case wait states are inserted)
rjmp i2c_get_ack_wait

clc ; clear carry flag
sbic PIND,SDAP ; if SDA is high
sec ; set carry flag
rcall i2c_hp_delay ; half period delay
ret

________________________________________________


подозреваю, что они берутся исходя из временных диаграмм обмена, но уверенности нет.
ILYAUL
Цитата(V000va @ Jun 23 2008, 21:48) *
Со вторым пунктом вроде разобрался, а по задержкам можете пояснить подробнее?


Даю забудь ты про эадержки
Вот тебе небольшой примерчик работы с шиной

Код
Начни с простого
; **************************************************
; *                                                *
; *   Init Bit Rate fot TWI                        *
; *                                                *
; **************************************************
    
       ldi temp,SYSCLK/(2*SCL_Freq)-8;TWI Bit Rate Register - TWBR
        sts        TWBR,temp


Так ты определишь скорость передачи

где SYSCLK - твой кварц SCL_FREQ - cкорость шины

Всё начинается с формирования START
Код
; *************************************************
; *                                               *
; *       Подпрограмма Init TWI_START             *
; *     Формирование START и проверка ответа.     *
; *                                               *
; *                                               *
; *************************************************

TWI_START:
        
        ldi      temp, (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)  
    sts      TWCR, temp; формирование режима START
        
waitST:
        lds      temp,TWCR   ; Проверка бита TWINT
        sbrs     temp,TWINT
        rjmp     waitST            ; Не получен -цикл
        lds    temp,TWSR     ; Проверка кода ответа    ;
        cpi    temp,START
        breq    RETURN         ; Правильный код -выход из подпрограммы
        brne    TWI_START         ; Нет - повтор.
RETURN:    ret


В первой строке ты формируешь режим старт - в момент начала передачи ( от тебя не зависит) бит TWINT сбрасывается -ты просто ждёшь когда он станет 1 , а в регистр TWSR получаем код 08H если всё хорошо. Если всё плохо - всё надо начинать с начала.
я вложил файл - посмотри - в таком режиме я работаю с DS 400Кгц без формирования задержек
V000va
Дык я так понимаю для серии Mega все просто и понятно, т.к. в ней есть Byte-oriented Two-wire Serial Interface (аналог I2c), а в tiny его нет.
Александр Куличок
По задержкам - смотри у автора стандарта
http://www.semiconductors.philips.com/acro...98/39340011.pdf,
страница 32-33, STANDART MODE

Или аппноут атмела (правда, на сайте атмела я его чего-то не нашел)
http://www.eetchina.com/ARTICLES/2003APR/P...OURCES=DOWNLOAD

Хотя, если сравнить эти 2 pdf'а, то оказывается, что у атмела quarter_period равен 2,5мкс, а соответствующие временные задержки у филипса (su-sto hd-sta) - не менее 4 мкс. Более того, филипс рекомендует удержание линии SDA минимум 300нс после спада SCL при записи данных на шину (NOTE 2, страница 32). У Атмела задержка - только 3 такта (i2c_write), что было приемлимо только для серии AT90 (до 8МГц)
Думаю, что логичнне всего взять атмеловский avr300 за основу и подкорректировать тайминги по официальной спецификации от филипса.
Dopler
Цитата(V000va @ Jun 25 2008, 15:38) *
Дык я так понимаю для серии Mega все просто и понятно, т.к. в ней есть Byte-oriented Two-wire Serial Interface (аналог I2c), а в tiny его нет.



В tiny2313 есть Universal Serial Interface (USI), который может работать в режиме I2C. Соответствующий appnote также имеется
V000va
Поковырял AVR 300: Software I2C™ Master Interface, разобрался, микросхему читает и пишет, но при чтении все ок, кроме последних 4-х бит данных, получаемых от микросхемы slave. Читаются постоянно с ошибками. Буду еще разбираться с чтением.
Александр Куличок
Не забывай перед вызовом каждой операцией чтения устанавливать корректное значение флага переноса, который здесь используется для передачи ACK/NACK. Также не следует забывать о том,что между стопом и последующим стартом должно пройти минимум 5,7 мкс (это с учетом времени наростания SDA 1 мкс и минимального времени Bus free 4.7 мкс). Данную задержку нужно делать самому, т.к в авр300 ни перед стартом, ни после стопа ее нет.
V000va
Цитата(Александр Куличок @ Jun 29 2008, 20:39) *
Не забывай перед вызовом каждой операцией чтения устанавливать корректное значение флага переноса, который здесь используется для передачи ACK/NACK. Также не следует забывать о том,что между стопом и последующим стартом должно пройти минимум 5,7 мкс (это с учетом времени наростания SDA 1 мкс и минимального времени Bus free 4.7 мкс). Данную задержку нужно делать самому, т.к в авр300 ни перед стартом, ни после стопа ее нет.


Эмулирую работу программы в Proteus. Анализатор i2c выдает вот что :


Где s - старт, d0 - адрес устройства slave + бит записи (0), А- подтверждение от slave, 00 - пишем адрес откуда будем читать. Sr - повторный старт d1 - адрес slave + бит чтения (1), послендие 00 перед N - это сами данные. N - подтверждение приема от master ( nack). После первого nack идут единицы сплошные, пока на них внимания не обращаю. Р- это стоп. Что интересно, если поменять адрес slave (указать неверный), то slave его не понимает и данных не дает. Т.е. можно предположить, что часть обмена до получения данных проходит верно. При приеме же данных, корректно принимаются только цифры 4 и 5, 0 и 1 в первых 4-х битах принимаемых. Цифры 3 и 2 не принимаются почему-то вообще. В последних 4 битах, правильно принимаются только цифры 0 и 1.

Осциллограф показывает вот что:



где 1 - это аск от slave и начало даннных, 2 - это nack от master. В промежутке между 1 и 2 должна была передаться цифра 08. А реально передался 00.
Александр Куличок
Цитата
После первого nack идут единицы сплошные, пока на них внимания не обращаю.

И правильно идут, так как мастер после чтения 00 выдает nack, сигнаизируя о том, что это был последний запрашиваемый байт (после которого мастер обычно выдает "стоп"). В авр300 ACK/NACK выставляется ПЕРЕД вызовом процедуры чтения последнего байта (i2c_read или i2c_do_transfer). Иными словами, процедура чтения нескольких байт выглядит так:
Код
            .......
    ldi    i2cadr,$A0+i2crd; Set device address and read
    rcall    i2c_rep_start; Send repeated start condition and address

    clc        ; ACK
    rcall    i2c_do_transfer; Execute transfer (read)
    .........                                  . . . .
    clc        ; ACK
    rcall    i2c_do_transfer; Execute transfer (read)
    sec        ; **NACK**  - читаем последний байт
    rcall    i2c_do_transfer; Execute transfer (read)
    rcall    i2c_stop; Send stop condition - releases bus


Цитата
Эмулирую работу программы в Proteus

C протеусом не работал, поэтому вопрос - в протеусе учитывается, что пины контроллера подтянуты к питанию? Так как со стороны контроллера сигналы SDA/SCL либо садятся на "0", либо отпускаются в третье состояние (откуда их внешние резисторы "вытягивают" на логичекую "1" ).
V000va
Цитата(Александр Куличок @ Jul 1 2008, 22:02) *
И правильно идут, так как мастер после чтения 00 выдает nack, сигнаизируя о том, что это был последний запрашиваемый байт (после которого мастер обычно выдает "стоп").


Вы несколько не поняли. Прочли 00 выдали nack в конце, это ясно. Далее после nack, если верить анализатору, идут: ff - nack - stop. Зачем после 00 идет nack понятно - это конец чтения. Почему же после 00 - nack идет ещё и ff - nack (т.е. сплошные единицы) -stop пока не ясно. Но с этим я разберусь. Важно другое, почему данные читаются не правильно, т.е. вместо 08, читается 00. Если взглянуть на осциллограмму (scl белая, sda синяя линия), то видно, что между цифрами 1 и 2 на ней, проходит один импульс. Т.е. если данные сдвинуть немного правее, чтоб импульс попал под лог "1" , на пятый слева импульс начала приема линии scl, то получится ожидаемая комбинация 08. Впечатление такое, что данные slave выдает не синхронизируясь с scl.



Цитата(Александр Куличок @ Jul 1 2008, 22:02) *
C протеусом не работал, поэтому вопрос - в протеусе учитывается, что пины контроллера подтянуты к питанию? Так как со стороны контроллера сигналы SDA/SCL либо садятся на "0", либо отпускаются в третье состояние (откуда их внешние резисторы "вытягивают" на логичекую "1" ).


Подтянуты пины к 1-це. Подозреваю что это глюк Proteus. А в чем работаете Вы, в чем моделируете схемы?
ChYM
В свое время разбирался с I2C и в атмеловском avr300 нашел ошибку. Точно в каком месте уже не помню. В конце концов все заработало. На шине висели часы DS1307 и AT24C512. Максимальная частота шины для часов 100 кГц, поэтому все устройства на шине работали на 100 кГц.
Пристегиваю кусок ассемблерного кода (почти аналог avr300). Может поможет разобраться.
Александр Куличок
Цитата
то получится ожидаемая комбинация 08

Не получается, так как слишком уж короткий импульс. А здесь либо глюк протеуса, либо что-то в Вашей программе. Попробуйте сначала выяснить, почему программа запрашивает лишний байт по i2c. Возможно, в процессе и предыдущую ошибку устраните.

Цитата
А в чем работаете Вы, в чем моделируете схемы?

JTAG + осциллограф (При написании кода своих ошибок достаточно. А вылавливать глюки еще и симуляторов не охота smile.gif )
Цитата
В свое время разбирался с I2C и в атмеловском avr300 нашел ошибку

Подтверждаю, ошибка была. Тоже исправлял. Правда, давно это было. Позавчера бегло сравнивал авр300 со своим (немного переработанным) кодом - различий с ходу не нашел. Поэтому предположил, что ее исправили. Но на всякий случай еще раз пересмотрю

Добавлено:
Пересмотрел, нашел ошибку в авр300. Она приводит к тому, при чтении что все байты, кроме первого (после адреса слейва) читаются как 0x00. Это связано с тем, что при выдачи мастером ACK в ответ на чтение 1-го байта линия SDA засаживается контроллером на "0" и остается в этом состоянии на протяжении всех последующих чтений.
Для исправления этой ошибки в i2c_read "отпускаю" SDA после спада SCL
Код
  
i2c_read:
    rol    i2cstat; store acknowledge
; (used by i2c_put_ack)
    ldi    i2cdata,0x01; data = 0x01
i2c_read_bit:; do
    sbi    DDRD,SCLP;     force SCL low

;******** Добавлено******************************
    nop; даем время опуститься SCL (300ns)
    nop
    cbi    DDRD,SDAP; отпускаем SDA
;******** ***************************************

    rcall    i2c_hp_delay;    half period delay

    cbi    DDRD,SCLP;    release SCL
    rcall    i2c_hp_delay;    half period delay

    clc;    clear carry flag
    sbic    PIND,SDAP;    if SDA is high
    sec;        set carry flag

    rol    i2cdata;     store data bit
    brcc    i2c_read_bit; while receive register not full


2 V000va:
А почему у Вас над цифрой 1 сигнал SCL "затянут" в сосоянии лог."1"? Вы что, между выдачей на шину адреса slave+i2crd и чтением байта от slave делаете паузу порядка 1/2 такта SCL?
V000va
Цитата(Александр Куличок @ Jul 2 2008, 22:34) *
А почему у Вас над цифрой 1 сигнал SCL "затянут" в сосоянии лог."1"? Вы что, между выдачей на шину адреса slave+i2crd и чтением байта от slave делаете паузу порядка 1/2 такта SCL?


Нет не далаю я пауз. Это ожидание ack от slave, это он тормозит видимо, а может и Proteus . Nack от master идет без пауз. Спасибо за советы всем откликнувшимся smile.gif . Буду собирать рабочий макет и тестить.
Александр Куличок a14.gif
Александр Куличок
Цитата
Это ожидание ack от slave, это он тормозит видимо

Если слейв не успевает (вводит цикл одидания), то он затягивает низкий уровень на сигнале SCK, и мастер должен считывать ACK/NACK только после того, как вырастет сигнал на SCL. То есть, схема чтения ACK/NACK выглядит так:

Мастер
1. садит SCL на "0"
2. отпускает SDA
3. задержка 1/2 периода
4. отпускает SCL
5. ждет, когда состояние пина SCL станет равным 1
6. Считывает SDA (собственно ACK/NACK от слейва)
7. задержка 1/2 периода
Слейв, если не успевает обработать запрос, удерживает сигнал SCL в "0", то есть отпускание мастером SCL на 4 шаге НЕ приводит фронту сигнала на физической линии SCL. Поэтому мастер на 5 шаге и ждет, когда слейв отпустит SCL. Это, кстати, может привести к "зависанию" микроконтроллера на данном участке кода, если по каким-либо причинам линия SCL удерживается в "0"

Дальше вопрос к знающим. Сам не разбирался, а подробно перечитывать документацию от филипса было лень smile.gif :
Слейв в соответствии со стандартом может затягивать SCL только при выдаче ACK/NACK или же когда ему вздумается (например, в процессе чтения из него битов данных)?
V000va
Спасибо за подробный ответ. smile.gif
V000va
Подскажите, пишу прогу для работы с ds1307. ПО должно читать время из 1307 и выводить его на дисплей. Собрал аппаратную часть уже. Прогу разбил на 2 части : вывод на дисплей и собственно процедура получения данных по i2c от 1307. Подпрограмму индикации проверил - работает. Добавил туда еще подпрограмму для чтения по i2c - ничего не выодит. Даже подпрограмма индикации не работает. Эмуляция в Proteus кое-как работает, но выводит не понятно что. На аппаратной платформе проверяю - совсем другой результат. Как можно посмотреть чего там по i2c принимается, чего в голове у процессора происходит? Слышал про Jtag, но как и через что его с tiny2313 связать, пока не знаю. Подскажите плз.
MTh
Цитата(V000va @ Jul 25 2008, 15:44) *
Подскажите, пишу прогу для работы с ds1307. ПО должно читать время из 1307 и выводить его на дисплей. Собрал аппаратную часть уже. Прогу разбил на 2 части : вывод на дисплей и собственно процедура получения данных по i2c от 1307. Подпрограмму индикации проверил - работает. Добавил туда еще подпрограмму для чтения по i2c - ничего не выодит. Даже подпрограмма индикации не работает. Эмуляция в Proteus кое-как работает, но выводит не понятно что. На аппаратной платформе проверяю - совсем другой результат. Как можно посмотреть чего там по i2c принимается, чего в голове у процессора происходит? Слышал про Jtag, но как и через что его с tiny2313 связать, пока не знаю. Подскажите плз.


С тинькой будут проблемы... Там USI полусофтовый полужелезный монстр. Он не особо хорош в отладке. Рекомендую посмотреть вот этот проект и его исходники: http://ahtoxa.net/micros/tiny/leds/

Там есть "ошибочка"... а потому посмотрите вот тут: http://electronix.ru/forum/index.php?showtopic=50210
Там ведомый но думаю направление будет ясно ))
Также рекомендую сходить на AVRFreaks.net
AHTOXA
Цитата(MTh @ Jul 25 2008, 20:16) *
Там есть "ошибочка"... а потому посмотрите вот тут: http://electronix.ru/forum/index.php?showtopic=50210


Я уже поправилsmile.gif
V000va
Эээ, да мне бы с отладкой разобраться, софт та у меня уже написан. Как можно проверить чего там по i2c передается?
SasaVitebsk
Шина простая до безобразия и, фактически статическая, (если не использовать мультимастер и всё такое что вам не нужно). Наверное поэтому и завоевала такую популярность. Реализовывал на всех процах. Никаких проблем не вызывает. Обычно пишешь - работает.

Если отсутствуют средства отладки, то делашь просто. Паяешь два светодиода, точку останова программную и кнопочку. И пошла родная..... Ещё проще в отладчике - ставишь точку останова и смотришь соответствующие биты порта. Реализация простейшая если программная (аппаратная под AVR фактически не сложнее).

Пишешь Start, Stop, AskW, AskR, ReadB, WriteB + задержку. Далее работа с любым IIC устройством составляется из данных кирпичиков.
MTh
Цитата(AHTOXA @ Jul 25 2008, 17:22) *
Я уже поправилsmile.gif


Я для подстраховки smile.gif
V000va
Все пофиксил, работает. Всем спасибо biggrin.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.