Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Проблема с TWI
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Страницы: 1, 2, 3, 4, 5, 6
Igor26
Цитата(Moks @ Dec 1 2005, 23:10) *
Добрый вечер!
Вот нужна какая помощь: Я передаю три байта как Master Transmitter , а вот четвёртый и пятый байты мне нужно принять как Master Receiver. После третьего байта только Acknowledge , а следующий такт уже я должен начать принимать данные. В регистре TWDR - последнее отосланное мной значение.

Ну не знаю я что делать. Помогите! Желательно на СИ!

Помоему, после передачи третьего байта Вам нужно давать STOP.
Petka
Цитата(Igor26 @ Dec 2 2005, 09:21) *
Цитата(Moks @ Dec 1 2005, 23:10) *

Добрый вечер!
Вот нужна какая помощь: Я передаю три байта как Master Transmitter , а вот четвёртый и пятый байты мне нужно принять как Master Receiver. После третьего байта только Acknowledge , а следующий такт уже я должен начать принимать данные. В регистре TWDR - последнее отосланное мной значение.

Ну не знаю я что делать. Помогите! Желательно на СИ!

Помоему, после передачи третьего байта Вам нужно давать STOP.

Не обязательно выдавать STOP, необходимо выдать новый START+SLA-R.
недавно боролся с slave-mode TWI. после того, как сделал всё по datasheet, всё прекрасно заработало. если надо могу поделиться кодом на CV для m16.
proba
интересно, как кто решил TWI slave, я переписал twi_int от AVR311 в такои вид, нужен был максмалный скорость, в сеттингах ИАР надо резервировать R13,R14,R15 для TWI_int.

NAME twi_slave_asm
#include "iom8.h" ; file must be within the module
public TWI_statusReg
public TWI_state
public TWI_buf
public byte_count ;


RSEG TWIBUF
TWI_buf DS 66 ; TWI buf is 64 bytes long + 2 byte aadress
TWI_statusReg DS 1; TWI_buf must start from xx00 aadress ( low byte = 0)
TWI_state DS 1;

twi_int_end MACRO
OUT 0x3F,R13
LD R16,Y+
LD R30,Y+
LD R31,Y+
RETI
ENDM


COMMON INTVEC:CODE:ROOT(1)
ORG 0x22
RJMP TWI_ISR

RSEG CODE ; This code is relocatable, RSEG

byte_count: ; returns how many bytes are in receive buffer
MOVW R17 : R16,R15 : R14
RET


; ORG 0x1E00 ; lower adres byte must be 0 !
RSEG TWIASM

TWITAB:
RJMP TWI_ISR_7 ;0x00 bus error , illegal START or STOP
RJMP TWI_ISR_7 ;0x08 TWI_START, MASTER only
RJMP TWI_ISR_7 ;0x10 TWI_REP_start , MASTER only
RJMP TWI_ISR_7 ;0x18 MASTER only: SLA+W trx-d, ACK rec-d
RJMP TWI_ISR_7 ;0x20 "" : SLA+W trx-d,NACK rec-d
RJMP TWI_ISR_7 ;0x28 "" : DATA trx-d, ACK rec-d
RJMP TWI_ISR_7 ;0x30 "" : DATA trx-d, NACK rec-d
RJMP TWI_ISR_7 ;0x38 TWI_ARB_LOST
RJMP TWI_ISR_7 ;0x40 MASTER only: SLA+R trx-d,ACK rec-d
RJMP TWI_ISR_7 ;0x48 "" SLA+R trx-d, NACK rec
RJMP TWI_ISR_7 ;0x50 "" DATA trx-d, ACK rec
RJMP TWI_ISR_7 ;0x58 "" DATA trx-d, NACK rec-d
RJMP TWI_ISR_6 ;0x60 own SLA+W rec-d,ACK ret-d
RJMP TWI_ISR_7 ;0x68 "" in slave mode
RJMP TWI_ISR_7 ;0x70 General call rec-d, ACK ret-d
RJMP TWI_ISR_7 ;0x78 "" sama in slave mode
RJMP TWI_ISR_0 ;0x80 data rec-d , ACK ret-d ( prevSLA)
RJMP TWI_ISR_7 ;0x88 data rec-d ,NACK ret-d ( prevSLA)
RJMP TWI_ISR_7 ;0x90 data rec-d , ACK ret-d ( prev Ceneral call)
RJMP TWI_ISR_7 ;0x98 data rec-d , NACK ret-d (prev General call)
RJMP TWI_ISR_2 ;0xA0 STOP for Slave
RJMP TWI_ISR_3 ;0xA8 SLA+R rec-d,ACK ret-d
RJMP TWI_ISR_7 ;0xB0 arb.lost in Master mode, SLA+R rec-d,ACK ret-d SL mode
RJMP TWI_ISR_4 ;0xB8 TWDR transm-d, ACK rec-d
RJMP TWI_ISR_5 ;0xC0 TWDR transm-d, NACK rec-d
RJMP TWI_ISR_7 ;0xC8 TWDR transm-d, ACK rec-d
RJMP TWI_ISR_7 ;0xD0
RJMP TWI_ISR_7 ;0xD8
RJMP TWI_ISR_7 ;0xE0
RJMP TWI_ISR_7 ;0xE8
NOP ;0xF0

TWI_ISR_7:
IN R16,0x01
STS TWI_state,R16

TWI_ISR_2:
LDI R16,4
OUT 0x36,R16
twi_int_end

TWI_ISR:
ST -Y,R31 ;2
ST -Y,R30 ;2
ST -Y,R16 ;2
IN R13,0x3F ;1 SREG keep
IN R30,0x01 ;1 TWI STatus reg
LSR R30 ;1
LSR R30 ;1
LSR R30 ;1
LDI R31, TWITAB>>9 ;1
IJMP ;2


TWI_ISR_3:
LDI R30,LOW(TWI_buf)
LDI R31,(TWI_buf >> 8)
LD R16,Z+
OUT 0x03,R16
LDI R16,197
OUT 0x36,R16
MOVW R15 : R14,R31 : R30
twi_int_end

TWI_ISR_4:
MOVW R31 : R30,R15 : R14
LD R16,Z+
OUT 0x03,R16
LDI R16,197
OUT 0x36,R16
; ANDI R30,63 ; not actual for sending
MOVW R15 : R14,R31 : R30
twi_int_end

TWI_ISR_5:
LDI R30,LOW(TWI_statusReg)
LDI R31,(TWI_statusReg) >> 8
LD R16,Z
ORI R16,0x01 ; end flag, TX oli OK
ST Z,R16
LDI R16,4
OUT 0x36,R16
twi_int_end

TWI_ISR_6:
LDI R30,LOW(TWI_statusReg)
LDI R31,(TWI_statusReg) >> 8
LD R16,Z
ORI R16,0x02 ; Rx data in buf
ST Z,R16
LDI R30,LOW(TWI_buf)
LDI R31,(TWI_buf) >> 8
MOVW R15 : R14,R31 : R30
LDI R16,197
OUT 0x36,R16
twi_int_end

TWI_ISR_0:
IN R16,0x03
MOVW R31 : R30,R15 : R14
ST Z+,R1 ; if(R30>65 ) R30=0
CPI R30,66
BRCS noo
LDI R30,0
noo: MOVW R15 : R14,R31 : R30
LDI R30,LOW(TWI_statusReg)
LDI R31,(TWI_statusReg) >> 8
LD R16,Z
ORI R16,0x01 ;
ST Z,R16
LDI R16,197
OUT 0x36,R16
twi_int_end

END
Moks
Спасибо, но я просил на Си, к тому же моя микросхема работает как Master! Только в начале она используется как transmitter, а потом как receiver!
James D.
Продолжаю добивать TWI. Хочу разобраться в конце-концов.
Вопрос такой: на вызов мастера-передатчика должны отвечать оба слэйва? Какие действия должен предпринимать тот слэйв, адрес которого не совпал с переданным мастером?
Раньше я делал так: от мастера к каждому слэйву кроме линий TWI шли еще по одной линии - разрешение на связь с мастером. Соответствующая линия сбрасывается в "0", если мастер хочет передавать данные на этот слэйв; вторая линия в "1", т.е. второй слэйв вообще не заходит в программу приема данных по TWI. Так не заработало - могу передать только на первый слэйв, при попытке передать на второй - все зависало - окончательно и безнадежно.
Теперь сделал по-другому. Должно, по идее, работать так:
мастер сбрасывает в "0" обе линии (разрешение на связь с мастером). Тот слэйв, адрес которого не совпал, выходит из программы приема данных, и продолжает выполнять основную прогу. А тот слэйв, адрес которого совпал - принимает данные.
Но и здесь не все гладко.
Мастер (m32) передает данные на слэйв1 (m32) - тут все нормально. Но слэйв2 (m16) при этом висит!
Нажимаю на кнопочку, чтобы начать передавать данные на слэйв2 - он при этом выходит из зависания, и данные передаются на оба контроллера - так и должно быть. При этом слэйв1 не зависает.
При включении передачи на слэйв1 - слэйв2 опять зависает.

Как тут быть?

P.S. Кстати, описанная ситуация происходит, если при связи с обоими МК мастер выдает повторный старт.
Если мастер дает сигнал старт - все безнадежно зависает (при попытке передать на слэйв2).
Petka
Цитата(James D. @ Dec 19 2005, 15:42) *
Продолжаю добивать TWI. Хочу разобраться в конце-концов.
Вопрос такой: на вызов мастера-передатчика должны отвечать оба слэйва? Какие действия должен предпринимать тот слэйв, адрес которого не совпал с переданным мастером?
Раньше я делал так: от мастера к каждому слэйву кроме линий TWI шли еще по одной линии - разрешение на связь с мастером. Соответствующая линия сбрасывается в "0", если мастер хочет передавать данные на этот слэйв; вторая линия в "1", т.е. второй слэйв вообще не заходит в программу приема данных по TWI. Так не заработало - могу передать только на первый слэйв, при попытке передать на второй - все зависало - окончательно и безнадежно.
Теперь сделал по-другому. Должно, по идее, работать так:
мастер сбрасывает в "0" обе линии (разрешение на связь с мастером). Тот слэйв, адрес которого не совпал, выходит из программы приема данных, и продолжает выполнять основную прогу. А тот слэйв, адрес которого совпал - принимает данные.
Но и здесь не все гладко.
Мастер (m32) передает данные на слэйв1 (m32) - тут все нормально. Но слэйв2 (m16) при этом висит!
Нажимаю на кнопочку, чтобы начать передавать данные на слэйв2 - он при этом выходит из зависания, и данные передаются на оба контроллера - так и должно быть. При этом слэйв1 не зависает.
При включении передачи на слэйв1 - слэйв2 опять зависает.

Как тут быть?

P.S. Кстати, описанная ситуация происходит, если при связи с обоими МК мастер выдает повторный старт.
Если мастер дает сигнал старт - все безнадежно зависает (при попытке передать на слэйв2).

ИМХО вы не разобрались с протоколм I2C. Зачем вы ведёте линии разрешения если в протокол заложена АДРЕСАЦИЯ? вероятно у вас с этим и глюки связаны. Слэйв, адрес которого не совпадает, с адресом, который передаётся по шине НИЧЕГО С ШИНОЙ ДЕЛАТЬ НЕ ДОЛЖЕН.
James D.
TWI у меня работает не по своим прерываниям, а в основной программе (в обработчике таймера). Линии разрешения я сделал для того, чтобы слэйвы не ждали, когда к ним обратится мастер, из-за этого прога будет работать очень медленно.
Начало обработки TWI (слэйв):

Код


Fr_M:  sbic  PIND,6;Проверка: мастер готов передавать данные?
     rjmp Go_prog;Если нет - прога выполняется дальше

Fr_M_n: ldi temp,$20;Инициализация режима "Приемник"
      out TWAR,temp

TWINT_n:ldi temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
       out TWCR,temp

wait1n:  in temp,TWCR;Ожидаем вызова от мастера
            sbrs temp,TWINT
            rjmp wait1n

            in temp,TWSR
            andi temp,$F8
            cpi temp,$60;Проверка принятого адреса от мастера
            breq Pr_data

            ldi temp,(1<<TWINT)|(1<<TWEN)
            out TWCR,temp

            rjmp Go_prog

;Прием данных:

Pr_data:
Petka
Цитата(James D. @ Dec 19 2005, 17:49) *
TWI у меня работает не по своим прерываниям, а в основной программе (в обработчике таймера). Линии разрешения я сделал для того, чтобы слэйвы не ждали, когда к ним обратится мастер, из-за этого прога будет работать очень медленно.


сделайте как полагается, по своим прерываниям. а потом можете говорить что TWI не работает. Мне кажется из-за этих разрешений-запрещений шина и виснет.
bodja74
Цитата(James D. @ Dec 19 2005, 17:49) *
TWI у меня работает не по своим прерываниям, а в основной программе (в обработчике таймера). Линии разрешения я сделал для того, чтобы слэйвы не ждали, когда к ним обратится мастер, из-за этого прога будет работать очень медленно.
Начало обработки TWI (слэйв):


Тут не просто кажеться ,тут 200% будут глюки.
Если мастера еще можно сделать в основной программе,то подчиненного только по прерыванию.
Слейв выдает NACK если адресс не совпадает и наоборот ACK если совпадает.
По этому и ориентируется мастер,а слейв выдает по TWSR &h60 если к нему обратились и
&h80 если после адресса пошли данные.
Если делать по прерыванию,не нужно ничего ждать и проверять.
В подпрограмме обработки прерывания достаточно проверять значения TWSR и
соответственно реагировать.
James D.
Цитата
В подпрограмме обработки прерывания достаточно проверять значения TWSR и
соответственно реагировать.


Что должен делать слэйв, адрес которого не совпал?
Должен ли он выдавать NACK (см. ниже - я так понял, так выдается NACK):
ldi temp,(1<<TWINT)|(1<<TWEN)
out TWCR,temp

Потом он выходит из прерывания - это понятно.

В основной проге я сделал обработку TWI, потому что так было удобнее. Если это не правильно, тогда, конечно, придется делать по спец. прерываниям.
На вызов мастера-передатчика должны отвечать ВСЕ слэйвы? В даташите написано, что все МК должны быть просто запитаны. Вот я и делал, что у меня отвечал только один, а второй вообще игнорировал вызов.
Petka
Цитата(James D. @ Dec 20 2005, 08:56) *
Что должен делать слэйв, адрес которого не совпал?
........
На вызов мастера-передатчика должны отвечать ВСЕ слэйвы?

НАСТОЯТЕЛЬНО рекомендую перечитать информацию о I2C и TWI в частности.

в неккоторых AVR'ках присутствует АППАРАТНЫЙ I2C~TWI. это обозначает что большинство действий с протоколом возложено на плечи железа, например генерация NACK(а точнее отсутствие генерации ACK) если адрес не совпал... т.е. ваши действия по работе с TWI (slave):
1) на каждое устройство придумать УНИКАЛЬНЫЙ адрес из диапазона 1-127. (0 адрес используется для массовых сообщений его выставлять НЕ надо).
2) записать адрес в регистр TWAR выбранный адрес сдвинутый на один бит влево.
3) настроить контрольный регистр TWI (TWСR) TWIE=1, TWEN=1, TWEA=1.

4) ждать прерывание.

5) при прирывании в зависимости от регистра TWSR выполнить соответствуюшие действия (какие именно расписано в даташите)

6) поблагодарить меня за то что научил уму-разуму =)

7) получить пилюлей от IgorKossak за п. 6) twak.gif
James D.
Цитата
2) записать адрес в регистр TWAR выбранный адрес сдвинутый на один бит влево.


Зачем?

Цитата
3) настроить контрольный регистр TWI (TWСR) TWIE=1, TWEN=1, TWEA=1.


А TWINT не надо сбрасывать(в слэйве) при настройке, и в процессе работы (а также при выходе из обработчика прерывания)?

Пока что у меня мастер зависает при попытке что-либо передать на любой из слэйвов...
А слэйвы работают.
Petka
Цитата(James D. @ Dec 20 2005, 13:51) *
Цитата
2) записать адрес в регистр TWAR выбранный адрес сдвинутый на один бит влево.


Зачем?

Цитата
3) настроить контрольный регистр TWI (TWСR) TWIE=1, TWEN=1, TWEA=1.


А TWINT не надо сбрасывать(в слэйве) при настройке, и в процессе работы (а также при выходе из обработчика прерывания)?

Пока что у меня мастер зависает при попытке что-либо передать на любой из слэйвов...
А слэйвы работают.


1) конктретизуй вопрос. Зачем адрес записывать или зачем сдвигать на бит его.
2) мастер зависает скорее всего НЕ дожидаясь ACK от устройства.
3) TWINT надо сбрасывать только в обработчике прерываний, после того, как необходимая реакция на прерывание будет выполнена.
IgorKossak
Цитата(Petka @ Dec 20 2005, 13:53) *
1) конктретизуй вопрос. Зачем адрес записывать или зачем сдвигать на бит его.

"Сдвиг на бит" это если не сказать "записать адрес слейва в поле адреса".
Делать это надо, чтобы слейв реагировал только на СВОЙ адрес, записанный в указанный регистр
Цитата(Petka @ Dec 20 2005, 13:53) *
2) мастер зависает скорее всего НЕ дожидаясь ACK от устройства.

И не дождётся, т. к. у слейва не прописан свой адрес по которому его мастер спрашивает.
Цитата(Petka @ Dec 20 2005, 13:53) *
3) TWINT надо сбрасывать только в обработчике прерываний, после того, как необходимая реакция на прерывание будет выполнена.

Или в фоновой программе если прерывания не применяются (тогда опрашивать надо быстро, чтобы не пропустить события).
James D.
Установил адрес слэйва - $40, а мастер вызывает адресом - $20. Так?
При запуске контроллеров мастер передает слэйву несколько байт в фоновом режиме (в основной программе), до разрешения общих прерываний, настройки таймеров и т.д. Проходит нормально, даже если у слэйва адрес $20, или $40 (мастер передает адрес $20).
Вот, что получается потом.

Код
;Инициализация TWI:

  ldi  temp,$40 ;Инициализация режима "Приемник"
  out  TWAR,temp
  ldi  temp,(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  sei


Слэйв-приемник постоянно входит в обработчик прерывания TWI, производит проверку адреса (код $60 не соответствует, и выходит из прерывания), даже если мастер вообще передачу по TWI не начинает.
Если мастер пытается что-либо передать, то зависает после загрузки адреса + WR (TWDR) на этапе ожидания, когда TWINT уст. в "1".

Код
wait: in  temp,TWCR;Ожидаем ответа от слэйва
  sbrs temp,TWINT
  rjmp wait


А этот бит устанавливаться не хочет.
В чем же тут дело?
Petka
Цитата(James D. @ Dec 20 2005, 17:31) *
Установил адрес слэйва - $40, а мастер вызывает адресом - $20. Так?
........
Слэйв-приемник постоянно входит в обработчик прерывания TWI, производит проверку адреса (код $60 не соответствует, и выходит из прерывания), даже если мастер вообще передачу по TWI не начинает.
...........
В чем же тут дело?


1) Адреса должны совпадать.
2) В прерывании вы ДОЛЖНЫ обрабатывать все события, не только $60. у меня, например сеть висла, если я не обрабатывал $F8 и $00.
3) успехов!
bodja74
Хорошо,обьясняю популярнее.

Слейву вообще по барабану что твориться на шине,
все гораздо проще чем вы думаете.
Если на шине не то что ему нужно,он просто не
выдаст прерывания

Первое прерывание возникнет только после того,когда
проидет СТАРТ и совпадет адресс слейва,TWSR выдаст НЕХ 60,
кричим УРА ,устанавливаем TWINT=1 и дружно выходим из прерывания.
TWI при этом АППАРАТНО выдает АСК.

Второе и ДАЛЕЕ прерывание возникнет после того,когда
прибудут данные ЕСЛИ ПЕРЕД ЭТИМ СОВПАЛ АДРЕСС
( то есть уже прошли первое прерывание)
TWSR выдаст НЕХ 80.устанавливаем TWINT=1 и
в TWDR имеем полученные данные,отправляем их куда хотим.
выходим из прерывания.

И ПОСЛЕДНЕЕ решаем выставлять нам АСК при следующем получении
данных или нет.
ЕСЛИ НЕТ тогда в следующем прерывании TWSR выдаст НЕХ 88
а МАСТЕР должен выдать СТОП.
Соответственно мастер должен определять NACK и выдавать СТОП на шину.

ПОСЛЕДНЕЕ в принципе не обязательно.
Просто если охота делать так как книжка пишет.

Сложно?
Я думаю проще некуда.

У меня при таком раскладе слев легко берет пакеты со скоростью
800Кбит в сек ,при частоте проца 8Мгц
James D.
Цитата(Petka @ Dec 20 2005, 17:45) *
Цитата(James D. @ Dec 20 2005, 17:31) *

Установил адрес слэйва - $40, а мастер вызывает адресом - $20. Так?
........
Слэйв-приемник постоянно входит в обработчик прерывания TWI, производит проверку адреса (код $60 не соответствует, и выходит из прерывания), даже если мастер вообще передачу по TWI не начинает.
...........
В чем же тут дело?


1) Адреса должны совпадать.
2) В прерывании вы ДОЛЖНЫ обрабатывать все события, не только $60. у меня, например сеть висла, если я не обрабатывал $F8 и $00.
3) успехов!


1. А кто мне говорил, что адрес в слэйве надо сдвигать на 1 бит?
2. Что нужно делать, если выпадет $F8 и $00?
3. Спасибо! Хорошо бы, чтоб они появились!

То bodja74:
"Если на шине не то что ему нужно,он просто не
выдаст прерывания"
А вот и нет - выдает постоянно, даже если к нему никто не обращается.

А если слэйву из прерывания не выходить, при приеме адреса, данных, а принимать все в пределах одного прерывания по TWI? Просто ждать, когда TWINT уст. в "1"?

"И ПОСЛЕДНЕЕ решаем выставлять нам АСК при следующем получении
данных или нет."
Что-то я не пойму все-таки, как слэйв должен выдавать ACK или NACK. Это же делается аппаратно? Как это сделать программно?

Мастер на шине один, и два подчиненных. Значит обработку ошибок касательно арбитража можно откинуть? Что должен делать слэйв, если его адрес не совпал с переданным мастером? В даташитовской таблице для подч-приемника это не описано.
DeXteR
Добрый день

Вот бы кто из действительно шарящих людей описал бы подробно процесс обмена
в случае с однирм мастером (приемником и передатчиком) и 2 слейвами

Ну типа там
1. Мастер посылает АСК ....
2. .....

Всем Спасибо

De}{teR
m16
Цитата(DeXteR @ Dec 21 2005, 13:00) *
Вот бы кто из действительно шарящих людей описал бы подробно процесс обмена
в случае с однирм мастером (приемником и передатчиком) и 2 слейвами

а чем ,простите, шит не устраивает . имхо все доходчиво
IgorKossak
Цитата(m16 @ Dec 21 2005, 12:06) *
а чем ,простите, шит не устраивает . имхо все доходчиво

Ну, например, на русский его перевести. cool.gif
Хотя, ести перечитать всю эту тему, то это уже сделано.
Petka
Цитата(IgorKossak @ Dec 21 2005, 13:10) *
Цитата(m16 @ Dec 21 2005, 12:06) *

а чем ,простите, шит не устраивает . имхо все доходчиво

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


Уважаемый Games D.! Вы задаёте вопросы на которые ЕСТЬ однозначные ответы в datahsheet на AVR (если быть точнее в разделе "Two-wire Serial Interface"), поэтому у меня есть конструктивное предложение: задавайте вопросы в таком виде "в пункте таком-то даташита написано что надо делать так-то, что бы получить то-то а у меня выходит сяк-то.". просто практика показывает что если делать, как рекомендуется в datasheet, то всё работает с первого раза и с минимальными временами на отладку.

для общего ознакомления с I2C можно прочитать это (на русском).
James D.
Я делаю так - передача одного байта (без обработки ошибок), пусть меня поправят, если я не прав:

1. Мастер производит установку скорости передачи (TWSR, TWBR);
2. Посылает сигнал START: (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
3. Ожидает, когда бит TWINT в TWCR установится в "1";

Слэйв работает по прерываниям TWI; как только происходит перепад из "1" в "0" на шине SDA (при "1" на шине SCL) - значит мастер послал сигнал START, при этом бит TWINT в слэйве уст. в "1"; происходит прерывание и переход на обработчик, в котором слэйв проверяет значение в регистре TWSR (только непонятно, выдает ли при этом слэйв аппаратно ACK?).

4. Мастер, дождавшись установки бита TWINT в "1", проверяет значение в TWSR - оно должно соответствовать $08;
5. Мастер загружает адрес слэйва, допустим $20 в TWDR, обновляет регистр TWCR: (1<<TWINT)|(1<<TWEN);
6. Ожидает, когда бит TWINT в TWCR установится в "1";

Если слэйв определил, что значение TWSR не соответствует $60, значит мастер обращается не к этому слэйву. Слэйв аппаратно выдает NACK и выходит из прерывания - выполняется далее основная программа.
Если значение соответствует $60 - слэйв аппаратно выдает ACK, записывает новое значение в TWCR: (1<<TWINT)|(1<<TWEA)|(1<<TWEN), и ждет, когда бит TWINT в TWCR установится в "1".

7. Мастер, дождавшись установки бита TWINT в "1", проверяет значение в TWSR - оно должно соответствовать $18 - адрес слэйвом принят, мастером получен ACK;
8. Заносит в TWDR передаваемый байт;
9. Обновляет TWCR: (1<<TWINT)|(1<<TWEN);
10. Ожидает, когда бит TWINT в TWCR установится в "1";

Слэйв, дождавшись, когда бит TWINT уст. в "1", проверяет рег. TWSR - должен быть код $80; выдает на шину ACK, и сохраняет принятый байт из TWDR в свою память. Далее готовится к приему команды STOP: обновляет TWCR: (1<<TWINT)|(1<<TWEA)|(1<<TWEN), и ждет, когда бит TWINT в TWCR установится в "1".

11. Мастер, дождавшись установки бита TWINT в "1", проверяет значение в TWSR - оно должно соответствовать $28 - данные слэйвом приняты, мастером получен ACK;
12. Мастер, обновляет TWCR: (1<<TWINT)|(1<<TWSTO)|(1<<TWEN), и выходит из программы передачи данных - продолжает выполняться основная программа.

Слэйв, дождавшись, когда бит TWINT уст. в "1", проверяет рег. TWSR - должен быть код $A0. После этого слэйв выходит из программы приема данных - продолжает выполняться основная программа.
Petka
Цитата(James D. @ Dec 21 2005, 14:25) *
Я делаю так - передача одного байта (без обработки ошибок), пусть меня поправят, если я не прав:

1. Мастер производит установку скорости передачи (TWSR, TWBR);
2. Посылает сигнал START: (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
3. Ожидает, когда бит TWINT в TWCR установится в "1";

ВОТ ГДЕ ОШИБКА!!!
надо ждать не "1" а "0".
ибо: "The TWINT flag must be cleared by software by writing a logic one to it"
если флаг "cleared" - "by writing logic ONE" значит флаг имеет ИНВЕРСНУЮ логику!
исправляйте ошибку, будем дальше дебажить =)
James D.
Так, заменил на ожидание "0" (в цикле ожидания сразу после посылки START) - теперь мастер зависает здесь:

7. Мастер, дождавшись установки бита TWINT в "1", проверяет значение в TWSR - оно должно соответствовать $18 - адрес слэйвом принят, мастером получен ACK;

то есть код в TWSR не равен $18.

SLA_Wn: ldi temp,$20 ;Загрузка адреса слэйв + "WRITE"
out TWDR,temp
ldi temp,(1<<TWINT)|(1<<TWEN)
out TWCR,temp

wait2n: in temp,TWCR ;Ожидаем ответа от слэйв
sbrs temp,TWINT
rjmp wait2n

in temp,TWSR
andi temp,$F8
cpi temp,$18
brne SLA_Wn ;Переход, если ответ от слэйв неверный

А раньше зависал в цикле wait2n.
James D.
Кстати, в даташите (в приведенном там примере) стоит ожидание "1" - после посылки START.

P.S. Прочитал PDF'ку, и сразу возник вопрос: надо ли в процессе работы TWI как-то коммутировать порты (PC0, PC1). У меня они настроены на ввод с вкл. подтягивающими резисторами.
Petka
Цитата(James D. @ Dec 21 2005, 16:30) *
Кстати, в даташите (в приведенном там примере) стоит ожидание "1" - после посылки START.


Какой вы упёртый =)

цитата из даташита:

"while (!(TWCR & (1<<TWINT))); // Wait for TWINT flag set. This indicates that the START condition has been transmitted"
IgorKossak
Цитата(James D. @ Dec 21 2005, 13:25) *
Я делаю так - передача одного байта (без обработки ошибок), пусть меня поправят, если я не прав:

1. Мастер производит установку скорости передачи (TWSR, TWBR);
2. Посылает сигнал START: (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
3. Ожидает, когда бит TWINT в TWCR установится в "1";

Слэйв работает по прерываниям TWI; как только происходит перепад из "1" в "0" на шине SDA (при "1" на шине SCL) - значит мастер послал сигнал START, при этом бит TWINT в слэйве уст. в "1"; происходит прерывание и переход на обработчик, в котором слэйв проверяет значение в регистре TWSR (только непонятно, выдает ли при этом слэйв аппаратно ACK?).

Нет такого события. Слейв не реагирует на START.
Зато есть событие
Код
0x60 Own SLA+W has been received; ACK has been returned

Это значит, что первое прерывание у слейва возникает только если его адрес совпал или было обращение по широковещательному адресу (событие 0x70) или их ошибочные варианты (0x68, 0x78).
Далее требуется коррекция Вашего алгоритма.
James D.
Цитата
Это значит, что первое прерывание у слейва возникает только если его адрес совпал или было обращение по широковещательному адресу (событие 0x70) или их ошибочные варианты (0x68, 0x78).
Далее требуется коррекция Вашего алгоритма.


Но ведь слэйв проверяет содержимое TWSR на соответствие $60 как раз в обработчике прерывания, значит само прерывание возникает до того.
У меня обработчик слэйва начинается так:

Код
;*******************************************************************
;Режим - подчиненный-приемник:

TWI_Obr:in  temp,TWSR
  andi temp,$F8
  cpi  temp,$60 ;Проверка принятого адреса
  breq Pr_data  ;Переход на прием данных
  reti
IgorKossak
Цитата(James D. @ Dec 21 2005, 16:54) *
Код
;*******************************************************************
;Режим - подчиненный-приемник:

TWI_Obr:in  temp,TWSR
  andi temp,$F8
  cpi  temp,$60;Проверка принятого адреса
  breq Pr_data ;Переход на прием данных
  reti

В таблице Status Codes for Slave Receiver Mode в поле Application Software Response To TWCR требуется обязательно сбросить TWINT записью в него 1 после завершения всех операций по TWI, но перед reti, чтобы иметь возможность воспринимать другие события.
IgorKossak
Добавлю также, что надо анализировать ВСЕ события и делать все действия. Ничего не сокращая! Оптимизировать будете когда всё заработает.
bodja74
Цитата
То bodja74:
"Если на шине не то что ему нужно,он просто не
выдаст прерывания"
А вот и нет - выдает постоянно, даже если к нему никто не обращается.


Это я вижу? Или это сон?

Цитата
А если слэйву из прерывания не выходить, при приеме адреса, данных, а принимать все в пределах одного прерывания по TWI? Просто ждать, когда TWINT уст. в "1"?


Зачем?

Цитата
"И ПОСЛЕДНЕЕ решаем выставлять нам АСК при следующем получении
данных или нет."
Что-то я не пойму все-таки, как слэйв должен выдавать ACK или NACK. Это же делается аппаратно? Как это сделать программно?


Аппаратно выставляется АСК при совпадении адресса.
Программно можно выставить NACK при получении данных елементарно TWEA=0

Цитата
Мастер на шине один, и два подчиненных. Значит обработку ошибок касательно арбитража можно откинуть? Что должен делать слэйв, если его адрес не совпал с переданным мастером? В даташитовской таблице для подч-приемника это не описано.


1 Арбитраж нужен когда два мастера ,а не два слейва.
2 Если адресс слейва не совпал ,слейв ничего не делает (NACK)
3 В таблице ничего и не будет описано.В таблице описаны ТОЛЬКО ТЕ СОБЫТИЯ при которых возникает прерывания.Поэтому и задал вопрос в начале поста


Теперь раскладка по регистрам что касается слейва

1 Инициализация TWI

1.1 #H00->TWBR
1.2 #H00->TWSR //Устанавливаем максимальную скороcть приема
1.3 #H40->TWAR //Адресс слейва 20НЕХ без учета последнего разряда
1.4 #H45->TWSR //Включение ,разрешение прерывания,ACK ,(TWINT=0)

2 Основная программа (ждем прерывание)

3 Прерывание по TWI (TWI_Finished)

3.1 <TWSR=#H60> //Если TWSR=#H60 ,устанавливаем TWINT=1 (#HC5->TWCR),Выходим из подпрограммы (RETI)
3.2 <TWSR=#H80> //Если TWSR=#H80 ,устанавливаем TWINT=1 (#HC5->TWCR),Извлекаем данные из TWDR,Выходим из подпрограммы (RETI)
3.1 <TWSR=#H88> //Если TWSR=#H88 ,устанавливаем TWINT=1 (#HC5->TWCR),Выходим из подпрограммы (RETI)

Все!!!

Сложно?
bbill
Немного не по теме. Кто-нибудь встречал русскоязычное описание USI для "тинек", для того же двухпроводного интерфейса?
James D.
Сделал следующее.
Убрал из программ мастера и слэйва передачу данных при включении обоих МК - там было не по прерываниям, а в основной программе.
Далее. Слэйв:

Код
;Инициализация TWI:

  ldi  temp,$00;Установка скорости передачи
  out  TWBR,temp
  ldi  temp,$00
  out  TWSR,temp
  ldi  temp,$40;Инициализация режима "Приемник"
  out  TWAR,temp
  ldi  temp,(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  sei

;Обработчик прерывания TWI (слэйв):
TWI_Obr:in  temp,TWSR
  andi temp,$F8
  cpi  temp,$60;Проверка принятого адреса от мастера
  breq Address
  cpi  temp,$80;Прием данных
  breq Data
  cpi  temp,$88;Stop
  breq Stop
  reti


Address:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

;Прием данных:
Data:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE);здесь пока ничего не делается
  out  TWCR,temp
  reti
;Стоп:
Stop:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti


Программа мастера:

Код
sbi  PORTD,2;Временная индикация
  sbi  PORTD,3
  sbi  PORTC,2
  sbi  PORTC,3
  sbi  PORTC,4
  sbi  PORTC,5
  sbi  PORTC,6

  ldi  temp,$00;Установка скорости передачи= ? kHz
  out  TWBR,temp
  ldi  temp,$00
  out  TWSR,temp

Pusk_Sn:ldi  temp,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
  out  TWCR,temp;Посылка сигнала "START"

wait1n: in  temp,TWCR;Ожидаем ответа от слэйва
  sbrc temp,TWINT
  rjmp wait1n

  in  temp,TWSR
  andi temp,$F8
  cpi  temp,$08;Проверка подтверждения приема от слэйва
  brne Pusk_Sn

SLA_Wn: ldi  temp,$20;Загрузка адреса слэйва + "WRITE"
  out  TWDR,temp
  ldi  temp,(1<<TWINT)|(1<<TWEN)
  out  TWCR,temp

wait2n: in  temp,TWCR;Ожидаем ответа от слэйва
  sbrs temp,TWINT
  rjmp wait2n

  in  temp,TWSR;Переход, в зависимости от содержимого TWSR
  andi temp,$F8
  cpi  temp,$08
  breq Kod_08
  cpi  temp,$10
  breq Kod_10
  cpi  temp,$18
  breq Kod_18
  cpi  temp,$20
  breq Kod_20
  cpi  temp,$28
  breq Kod_28
  cpi  temp,$30
  breq Kod_30
  cpi  temp,$38
  breq Kod_38

ST_TWI: rjmp ST_TWI

Kod_08: cbi  PORTD,2;Индикация на светодиодах
  rjmp Kod_08
Kod_10: cbi  PORTD,3
  rjmp Kod_10
Kod_18: cbi  PORTC,2
  rjmp Kod_18
Kod_20: cbi  PORTC,3
  rjmp Kod_20
Kod_28: cbi  PORTC,4
  rjmp Kod_28
Kod_30: cbi  PORTC,5
  rjmp Kod_30
Kod_38: cbi  PORTC,6
  rjmp Kod_38


Так вот, слэйв в обработчик прерывания вообще не заходит, а мастер содержит в TWSR код $08 (по индикации).
На шине TWI оставил, для чистоты эксперимента, только два МК - мастер и слэйв.
И еще: скорость передачи устанавливается только в мастере, или в слэйве тоже?
IgorKossak
1. Скорость передачи устанавливается только в мастере и обязательно!
Цитата
Note: TWBR should be 10 or higher if the TWI operates in Master mode. If TWBR is lower than 10, the Master may produce an incorrect output on SDA and SCL for the reminder of the byte. The problem occurs when operating the TWI in Master mode, sending Start + SLA + R/W to a Slave (a Slave does not need to be connected to the bus for the condition to happen).
При тактовой 8МГц и скорости TWI 100кГц TWBR = 32.
2. Между этими командами у слейва
Цитата
breq Stop
reti
тоже надо вставить сброс TWINT на случай ошибочных ситуаций (может даже с какой-нибудь индикацией).
3. Мастер. При посылке СТАРТ мы ожидаем реакции не от слейва, а от интерфейса (но это только терминология). СТАРТ будет осуществлён и TWINT возникнет только тогда, когда шина будет свободна и вариантов здесь нет. Закольцовывать эту процедуру brne Pusk_Sn не нужно.
4. Байт адреса слейва, передаваемый мастером в Вашем случае должен быть 0x40, т. е. сдвинутым на 1 влево, т. к. младший бит это R/W. См. рисунок Typical Data Transmission.
James D.
Цитата
4. Байт адреса слейва, передаваемый мастером в Вашем случае должен быть 0x40, т. е. сдвинутым на 1 влево, т. к. младший бит это R/W. См. рисунок Typical Data Transmission.

Вобщем, адрес в слэйв и, передаваемый мастером, должны совпадать: слэйв - $20, мастер - $20, или слэйв - $40, мастер - $40. Правильно?
Все МК у меня работают на частоте 4 MHz. Значит скорость в мастере я установлю не менее 10 (как, впрочем, у меня всегда и было - ставил $14).
IgorKossak
Цитата(James D. @ Dec 22 2005, 16:56) *
Вобщем, адрес в слэйв и, передаваемый мастером, должны совпадать: слэйв - $20, мастер - $20, или слэйв - $40, мастер - $40. Правильно?

Точно так. Т. к. адрес слейва занимает старшие 7 бит в TWAR, также как и в передаваемом мастером адресном байте.
Цитата(James D. @ Dec 22 2005, 16:56) *
Все МК у меня работают на частоте 4 MHz. Значит скорость в мастере я установлю не менее 10 (как, впрочем, у меня всегда и было - ставил $14).

Пока всё верно.
bodja74
К IgorKossak мне уже добавить особо нечего,
единственное проверять F8 необязательно после проверки TWINT,
это промежуточное значение когда TWINT=0.
James D.
Переписал проги. Слэйв:

Код
;***** Векторы Прерываний *****

.CSEG
.org $000
  rjmp RESET ;Сброс вектор

.org $026
  jmp  TWI_Obr ;Обработчик "TWI"

;Инициализация TWI:

  ldi  temp,$20;Инициализация режима "Приемник"
  out  TWAR,temp
  ldi  temp,(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  sei

Обработчик прерывания TWI:

;*******************************************************************
;Режим - подчиненный-приемник:

TWI_Obr:in  temp,TWSR
  andi temp,$F8
  cpi  temp,$60;Проверка принятого адреса от мастера
  breq Address
  cpi  temp,$80;Прием данных
  breq Data
  cpi  temp,$88;Stop
   breq Stop
  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  reti

;************************************************************
Address:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti
;************************************************************
;Прием данных:

Data: in  temp,TWDR;Принимаем 1 байт, и сохраняем его в память
  sts  DATA,temp

  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti
;************************************************************
Stop: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti
;************************************************************


Программа мастера:

Код
;*******************************************************************
;Программа пересылки данных (настроек) в slave-контроллер

To_SL: ldi  temp,$14;Установка скорости передачи= ? kHz
  out  TWBR,temp
  ldi  temp,$00
  out  TWSR,temp

Pusk_Sn:ldi  temp,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
  out  TWCR,temp;Посылка сигнала "START"

wait1: in  temp,TWCR;Ожидаем ответа интерфейса
  sbrc temp,TWINT
  rjmp wait1

;  in  temp,TWSR
;  andi temp,$F8
;  cpi  temp,$08
;  brne Pusk_Sn

SLA_Wn: ldi  temp,$20;Загрузка адреса slave-контроллера + "WRITE"
  out  TWDR,temp
  ldi  temp,(1<<TWINT)|(1<<TWEN)
  out  TWCR,temp

wait2: in  temp,TWCR;Ожидаем ответа от slave контроллера
  sbrs temp,TWINT
  rjmp wait2

  in  temp,TWSR;Переход, в зависимости от содержимого TWSR
  andi temp,$F8
  cpi  temp,$08
  breq Kod_08
  cpi  temp,$10
  breq Kod_10
  cpi  temp,$18
  breq Kod_18
  cpi  temp,$20
  breq Kod_20
  cpi  temp,$28
  breq Kod_28
  cpi  temp,$30
  breq Kod_30
  cpi  temp,$38
  breq Kod_38

ST_TWI: rjmp ST_TWI

Kod_08: cbi  PORTD,3;Временная индикация
  rjmp Kod_08
Kod_10: cbi  PORTC,2
  rjmp Kod_10
Kod_18: cbi  PORTC,3
  rjmp Kod_18
Kod_20: cbi  PORTC,4
  rjmp Kod_20
Kod_28: cbi  PORTC,5
  rjmp Kod_28
Kod_30: cbi  PORTC,6
  rjmp Kod_30
Kod_38: cbi  PORTC,7
  rjmp Kod_38


Теперь вопросы.
Прога слэйва написана правильно?
В проге мастера после посылки START в цикле "wait1" надо ждать "1" или "0"? После этого надо ли проверять TWSR на соответствие коду $08?
В цикле wait2 надо ждать "1" или "0"?
Пока результат такой: слэйв в обработчик прерывания не заходит, мастер выдает код в TWSR=$08 - по индикации.
На шине присутствуют 2 МК: ATmega32, частота обоих = 4MHz.
James D.
Цитата(bodja74 @ Dec 22 2005, 19:46) *
К IgorKossak мне уже добавить особо нечего,
единственное проверять F8 необязательно после проверки TWINT,
это промежуточное значение когда TWINT=0.


А где я проверяю F8?
bodja74
Мастеру нужно ждать пока TWINT=0,если TWINT=1 двигаемся дальше.

Насчет F8 ,с чем связаны эти маневры?


Цитата
wait1: in temp,TWCR;Ожидаем ответа интерфейса
sbrc temp,TWINT
rjmp wait1

; in temp,TWSR
; andi temp,$F8
; cpi temp,$08
; brne Pusk_Sn
bodja74
Цитата
;Режим - подчиненный-приемник:

TWI_Obr:in temp,TWSR
andi temp,$F8 <<<<<<<<<< И ЭТО ЗАЧЕМ??????????
cpi temp,$60;Проверка принятого адреса от мастера
breq Address
cpi temp,$80;Прием данных
breq Data
cpi temp,$88;Stop
breq Stop
ldi temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
out TWCR,temp

reti
James D.
Цитата
Насчет F8 ,с чем связаны эти маневры?

wait1: in temp,TWCR;Ожидаем ответа интерфейса
sbrc temp,TWINT
rjmp wait1


Как с чем? Ждем когда TWINT обнулится, потом:

Цитата
; in temp,TWSR
; andi temp,$F8
; cpi temp,$08
; brne Pusk_Sn


таким образом биты предделителя замаскированы нулевыми значениями, и можно проверять код состояния.
Далее.
Цитата
;Режим - подчиненный-приемник:

TWI_Obr:in temp,TWSR
andi temp,$F8 <<<<<<<<<< И ЭТО ЗАЧЕМ??????????
cpi temp,$60;Проверка принятого адреса от мастера
breq Address


Это сделано для того, чтобы слэйв, предварительно замаскировав биты предделителя нулевыми значениями, смог проверить код состояния в TWSR - его ли вызывает мастер.

У меня большая просьба к bodja74 и ко всем, кто участвует в этом обсуждении: я не пытаюсь выдумать что-то новое, изобрести совершенно отличный от даташитовского, алгоритм приема-передачи по TWI, и своими примерами что-то Вам доказываю; я просто хочу разобраться в том, что уже существует. И этих вопросов:
Цитата
Насчет F8 ,с чем связаны эти маневры?

Цитата
<<<<<<<<<< И ЭТО ЗАЧЕМ??????????

я просто не понимаю. Зачем-зачем, так описано в документации.
bodja74
Я извмняюсь,наверно неважный из меня советчик.
Хотелось помочь ,а не обидеть.

Теперь продолжим.

Цитата
Как с чем? Ждем когда TWINT обнулится, потом:


Нужно ждать появления "1" в TWINT

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


Вы их не маскируете,а подменяете значение полученое от TWSR.

Кроме того Предделитель TWSR вы уже обнулили в основной программе,Вот

Цитата
To_SL: ldi temp,$14;Установка скорости передачи= ? kHz
out TWBR,temp
ldi temp,$00
out TWSR,temp


Обнулите TWSR и слейве (я выше давал раскладку регистров)

Если в мастере проверять только TWINT слейв можно отключить.
И посмотреть до какого этапа дошел мастер,должен проходить до конца
и без слейва.
bodja74
Вот код для мастера.
Я щасс "графический" асм юзаю (удобнее гораздо),пришлось тряхнуть стариной с "классическим"
Здесь адресс $40 ($20 без r/w).Потом отправляем данные $FF.Потом СТОП,потом пауза чтобы модуль TWI смог завершить команду СТОП.

Цитата
; TWI Master
; Specify Device.
.include "m8def.inc"


.equ SP =$3D

; Variable Declarations
.def temp = r16
.def temp_a = r17
.def adress = r18
.def data = r19
.def W = r24
.def X = r26
.def Y = r28
.def Z = r30

.cseg ; CODE segment.

.org 0
rjmp PROG ; origin.



PROG: ldi r16,$FF ; Initialize the stack.
out SP,r16

ldi adress,$40
rcall TWI_START
ldi data,$FF
rcall TWI_DATA
rcall TWI_STOP
rcall PAUSE
sleep

TWI_START: ldi temp,$02
out TWBR,temp
ldi temp,$02
out TWSR,temp
ldi temp,$A4
out TWCR,temp
s1: in temp,TWCR
sbrs temp,7
rjmp s1

out TWDR,adress
ldi temp,$C4
out TWCR,temp
s2: in temp,TWCR
sbrs temp,7
rjmp s2
ret

TWI_DATA: out TWDR,data
ldi temp,$C4
out TWCR,temp
d1: in temp,TWCR
sbrs temp,7
rjmp d1
ret

TWI_STOP: ldi temp,$94
out TWCR,temp
ret

PAUSE: ldi temp,$40
ldi temp_a,$00
dec temp
cpse temp,temp_a
rjmp PAUSE
ret
James D.
Предлагаю сразу прояснить ситуацию с адресами.
Допустим адрес слэйва - $20, мастер в режиме передачи данных (Write) должен выдавать адрес - $20, а при чтении (Read) - адрес $21. Правильно?
Идем дальше.
bodja74, Вы, в приведенной проге мастера, нигде не проверяете регистр TWSR, можно ли так делать?
Второй вопрос. Вот здесь:

out TWDR,adress
ldi temp,$C4
out TWCR,temp

Вы в мастере устанавливаете бит TWEA, нужно ли это делать? Я думал, что этот бит участвует только при приеме данных.
И последний вопрос. Пауза, после передачи STOP, она нужна, Вы написали: "чтобы модуль TWI смог завершить команду СТОП". Эта пауза должна быть какой-то определенной величины? Можно ли об этой паузе узнать поподробнее? Что будет, если ее не выдерживать? Или она нужна только перед "сном"?
James D.
Переписал программы.
Слэйв:

Код
;Инициализация TWI:

  ldi  temp,$20;Инициализация режима "Приемник"
  out  TWAR,temp
  ldi  temp,(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  sei

Обработчик прерывания TWI:

;*******************************************************************
;Режим - подчиненный-приемник:

TWI_Obr:in  temp,TWSR
  andi temp,$F8
  cpi  temp,$60 ;Проверка принятого адреса от мастера
  breq Address
  cpi  temp,$80 ;Прием данных
  breq Data
  cpi  temp,$A0 ;Stop
   breq Stop
  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  reti

;************************************************************
Address:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti
;************************************************************
;Прием данных:

Data: in  temp,TWDR ;Принимаем 1 байт, и сохраняем его в память
  sts  DATA,temp

  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti
;************************************************************
Stop: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti
;************************************************************


Программа мастера:

Код
;*******************************************************************
;Программа пересылки данных (настроек) в slave-контроллер

To_SL: ldi  temp,$14;Установка скорости передачи= ? kHz
  out  TWBR,temp
  ldi  temp,$00
  out  TWSR,temp

Pusk_Sn:ldi  temp,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
  out  TWCR,temp;Посылка сигнала "START"

wait1: in  temp,TWCR;Ожидаем ответ интерфейса
  sbrc temp,TWINT
  rjmp wait1

SLA_Wn: ldi  temp,$20;Загрузка адреса slave-контроллера + "WRITE"
  out  TWDR,temp
  ldi  temp,(1<<TWINT)|(1<<TWEN)
  out  TWCR,temp

wait2: in  temp,TWCR;Ожидаем ответа от slave контроллера
  sbrs temp,TWINT
  rjmp wait2

  in  temp,TWSR
  andi temp,$F8
  cpi  temp,$18
  breq DATA

  ldi  temp,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN);Передаем STOP
  out  TWCR,temp
  rjmp To_SL ;Передачу начинаем заново

;Начинаем передавать данные:
DATA: out  TWDR,temp ;Отправка: данные
  rcall Writen
  rjmp STOP  ;Передача данных завершена

;*******************************************************************
Writen: ldi  temp,(1<<TWINT)|(1<<TWEN)
  out  TWCR,temp

wait3: in  temp,TWCR;Ожидаем ответа от слэйв
  sbrs temp,TWINT
  rjmp wait3

  in  temp,TWSR
  andi temp,$F8
  cpi  temp,$28
  brne Writen ;Переход, если ответ от слэйв неверный

  ret
;*******************************************************************
;Все данные переданы - STOP (линия приема/передачи переходит в высокоимпедансное состояние)

STOP_n: ldi  temp,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
  out  TWCR,temp

;*******************************************************************

Далее идет выполнение основной программы.


Теперь вопросы.
В слэйв, после приема последнего байта, ожидаем команду STOP, код $A0. Правильно ли я все это написал?
В проге мастера, после цикла wait1, я убрал проверку TWSR.
После цикла wait2, если код в TWSR не равен $18, передаем STOP, и начинаем процесс передачи заново. Это так делается?
Если надо передать несколько байт, как грамотно организовать это в слэйв-программе?
Допустим, мастер передает второй байт, слэйв сразу выполняет эту проверку (?):
cpi temp,$80 ;Прием данных
breq Data
и, если код совпал с $80, куда должно идти выполнение проги? Если опять на "Data", то следующий, переданный мастером байт, запишется в ту же ячейку памяти слэйв, что и предыдущий. А это негодится.
bodja74
Цитата(James D. @ Dec 24 2005, 12:02) *
Предлагаю сразу прояснить ситуацию с адресами.
Допустим адрес слэйва - $20, мастер в режиме передачи данных (Write) должен выдавать адрес - $20, а при чтении (Read) - адрес $21. Правильно?


Хорошо давайте с простого
Мастер передает $40
Мастер получает $41
Слейв $40

Обьясняю в формировании ЗНАЧЕНИЯ адресса участвуют только старших 7 битов.
Последний отбрасывается так как это бит R/W.
Поэтому передавая мастером $40 или $41 и получая слейвом значения $40 или $41
мы фактически адрессуем устройство $20 и слейв имеет адресс $20.
В данной ситуации это для вас не актуально.Но когда начнете работать с памятью или
LCD с управлением по I2C и начнете читать даташиты,вам прийдется учитывать эту
неразбериху с адрессацией.

Цитата
Идем дальше.
bodja74, Вы, в приведенной проге мастера, нигде не проверяете регистр TWSR, можно ли так делать?


Я привел простейший код ,как стартовый,который будет работать что со слейвом ,что без.
Естественно в дальнейшем можно добавлять различные проверки,дополнять и т.д.
Все зависит от вашей фантазии и поставленных задач.
Цитата
Второй вопрос. Вот здесь:



out TWDR,adress
ldi temp,$C4
out TWCR,temp


Вы в мастере устанавливаете бит TWEA, нужно ли это делать? Я думал, что этот бит участвует только при приеме данных.

Да он участвует в приеме,На передачу он не влияет ,если вам будет охота в дальнейшем принимать данные от слейва не нужно будет прописывать.
Цитата
И последний вопрос. Пауза, после передачи STOP, она нужна, Вы написали: "чтобы модуль TWI смог завершить команду СТОП". Эта пауза должна быть какой-то определенной величины? Можно ли об этой паузе узнать поподробнее? Что будет, если ее не выдерживать? Или она нужна только перед "сном"?


Зайдите на этом форуме на тему "не могу писать 24с256" ,почитайте мои посты ,просто не охота
повторяться.

Остальное вечером после работы.
James D.
Ну вот теперь, наконец, с адресацией разобрались!
Цитата
Зайдите на этом форуме на тему "не могу писать 24с256" ,почитайте мои посты ,просто не охота
повторяться.

А этой темы я что-то не нашел...
bodja74
Цитата(James D. @ Dec 24 2005, 13:08) *
Переписал программы.
Слэйв:

Код
;Инициализация TWI:

  ldi  temp,$20;Инициализация режима "Приемник"
  out  TWAR,temp
  ldi  temp,(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  sei

Обработчик прерывания TWI:

;*******************************************************************
;Режим - подчиненный-приемник:

TWI_Obr:in  temp,TWSR
  andi temp,$F8<<<убрать
  cpi  temp,$60;Проверка принятого адреса от мастера
  breq Address
  cpi  temp,$80;Прием данных
  breq Data
  cpi  temp,$A0;Stop<<<убрать
   breq Stop<<<убрать
  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)<<<Здесь на данный момент наилучшее решение .Просто выходим из подпрограммы во всех остальных случаях.

  out  TWCR,temp

  reti

;************************************************************
Address:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti
;************************************************************
;Прием данных:

Data: in  temp,TWDR;Принимаем 1 байт, и сохраняем его в память
  sts  DATA,temp

  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti
;************************************************************
Stop: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)<<<убрать
  out  TWCR,temp<<<убрать
  reti<<<убрать
;************************************************************


Программа мастера:

Код
;*******************************************************************
;Программа пересылки данных (настроек) в slave-контроллер

To_SL: ldi  temp,$14;Установка скорости передачи= ? kHz
  out  TWBR,temp
  ldi  temp,$00
  out  TWSR,temp

Pusk_Sn:ldi  temp,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
  out  TWCR,temp;Посылка сигнала "START"

wait1: in  temp,TWCR;Ожидаем ответ интерфейса
  sbrc temp,TWINT
  rjmp wait1

SLA_Wn: ldi  temp,$20;Загрузка адреса slave-контроллера + "WRITE"
  out  TWDR,temp
  ldi  temp,(1<<TWINT)|(1<<TWEN)
  out  TWCR,temp

wait2: in  temp,TWCR;Ожидаем ответа от slave контроллера
  sbrs temp,TWINT
  rjmp wait2

  in  temp,TWSR<<<убрать
  andi temp,$F8<<<убрать
  cpi  temp,$18<<<убрать
  breq DATA <<<перейти или вставить DATA:

  ldi  temp,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN);Передаем STOP
  out  TWCR,temp
  rjmp To_SL;Передачу начинаем заново

;Начинаем передавать данные:
DATA: out  TWDR,temp;Отправка: данные
  rcall Writen
  rjmp STOP ;Передача данных завершена <<<потом пауза длиной 1такт SCL
;*******************************************************************
Writen: ldi  temp,(1<<TWINT)|(1<<TWEN)
  out  TWCR,temp

wait3: in  temp,TWCR;Ожидаем ответа от слэйв
  sbrs temp,TWINT
  rjmp wait3

  in  temp,TWSR
  andi temp,$F8<<<убрать
  cpi  temp,$28
  brne Writen;Переход, если ответ от слэйв неверный<<<переход на стоп если ответ от слэйв неверный

  ret
;*******************************************************************
;Все данные переданы - STOP (линия приема/передачи переходит в высокоимпедансное состояние)

STOP_n: ldi  temp,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
  out  TWCR,temp

;*******************************************************************

Далее идет выполнение основной программы.


Указал где исправить
Коротче по мастеру сравните с моим кодом.В этом духе и сделайте
Цитата
Теперь вопросы.
В слэйв, после приема последнего байта, ожидаем команду STOP, код $A0. Правильно ли я все это написал?

Нет.
Цитата
В проге мастера, после цикла wait1, я убрал проверку TWSR.
После цикла wait2, если код в TWSR не равен $18, передаем STOP, и начинаем процесс передачи заново. Это так делается?

В вашей проге указал
Цитата
Если надо передать несколько байт, как грамотно организовать это в слэйв-программе?
Допустим, мастер передает второй байт, слэйв сразу выполняет эту проверку (?):
cpi temp,$80 ;Прием данных
breq Data
и, если код совпал с $80, куда должно идти выполнение проги? Если опять на "Data", то следующий, переданный мастером байт, запишется в ту же ячейку памяти слэйв, что и предыдущий. А это негодится.

Например можно держать вектор адресса ОЗУ в каком нибудь двойном регистре.
При старте указывать начало в ОЗУ первого байта,
При получении отправлять в ОЗУ с постинкрементом указателя.
При повторном старте Указатель опять примет значения начала и т.д.

При повторном приеме байта данных значение остается $80

Потом прога неспешно выбирает значения и обрабатывает данные.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.