Цитата(Moks @ Dec 1 2005, 23:10)

Добрый вечер!
Вот нужна какая помощь: Я передаю три байта как Master Transmitter , а вот четвёртый и пятый байты мне нужно принять как Master Receiver. После третьего байта только Acknowledge , а следующий такт уже я должен начать принимать данные. В регистре TWDR - последнее отосланное мной значение.
Ну не знаю я что делать. Помогите! Желательно на СИ!
Помоему, после передачи третьего байта Вам нужно давать STOP.
Цитата(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.
интересно, как кто решил 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
Спасибо, но я просил на Си, к тому же моя микросхема работает как Master! Только в начале она используется как transmitter, а потом как receiver!
James D.
Dec 19 2005, 12:42
Продолжаю добивать TWI. Хочу разобраться в конце-концов.
Вопрос такой: на вызов мастера-передатчика должны отвечать оба слэйва? Какие действия должен предпринимать тот слэйв, адрес которого не совпал с переданным мастером?
Раньше я делал так: от мастера к каждому слэйву кроме линий TWI шли еще по одной линии - разрешение на связь с мастером. Соответствующая линия сбрасывается в "0", если мастер хочет передавать данные на этот слэйв; вторая линия в "1", т.е. второй слэйв вообще не заходит в программу приема данных по TWI. Так не заработало - могу передать только на первый слэйв, при попытке передать на второй - все зависало - окончательно и безнадежно.
Теперь сделал по-другому. Должно, по идее, работать так:
мастер сбрасывает в "0" обе линии (разрешение на связь с мастером). Тот слэйв, адрес которого не совпал, выходит из программы приема данных, и продолжает выполнять основную прогу. А тот слэйв, адрес которого совпал - принимает данные.
Но и здесь не все гладко.
Мастер (m32) передает данные на слэйв1 (m32) - тут все нормально. Но слэйв2 (m16) при этом висит!
Нажимаю на кнопочку, чтобы начать передавать данные на слэйв2 - он при этом выходит из зависания, и данные передаются на оба контроллера - так и должно быть. При этом слэйв1 не зависает.
При включении передачи на слэйв1 - слэйв2 опять зависает.
Как тут быть?
P.S. Кстати, описанная ситуация происходит, если при связи с обоими МК мастер выдает повторный старт.
Если мастер дает сигнал старт - все безнадежно зависает (при попытке передать на слэйв2).
Цитата(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.
Dec 19 2005, 14:49
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:
Цитата(James D. @ Dec 19 2005, 17:49)

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

TWI у меня работает не по своим прерываниям, а в основной программе (в обработчике таймера). Линии разрешения я сделал для того, чтобы слэйвы не ждали, когда к ним обратится мастер, из-за этого прога будет работать очень медленно.
Начало обработки TWI (слэйв):
Тут не просто кажеться ,тут 200% будут глюки.
Если мастера еще можно сделать в основной программе,то подчиненного только по прерыванию.
Слейв выдает NACK если адресс не совпадает и наоборот ACK если совпадает.
По этому и ориентируется мастер,а слейв выдает по TWSR &h60 если к нему обратились и
&h80 если после адресса пошли данные.
Если делать по прерыванию,не нужно ничего ждать и проверять.
В подпрограмме обработки прерывания достаточно проверять значения TWSR и
соответственно реагировать.
James D.
Dec 20 2005, 05:56
Цитата
В подпрограмме обработки прерывания достаточно проверять значения TWSR и
соответственно реагировать.
Что должен делать слэйв, адрес которого не совпал?
Должен ли он выдавать NACK (см. ниже - я так понял, так выдается NACK):
ldi temp,(1<<TWINT)|(1<<TWEN)
out TWCR,temp
Потом он выходит из прерывания - это понятно.
В основной проге я сделал обработку TWI, потому что так было удобнее. Если это не правильно, тогда, конечно, придется делать по спец. прерываниям.
На вызов мастера-передатчика должны отвечать ВСЕ слэйвы? В даташите написано, что все МК должны быть просто запитаны. Вот я и делал, что у меня отвечал только один, а второй вообще игнорировал вызов.
Цитата(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)
James D.
Dec 20 2005, 10:51
Цитата
2) записать адрес в регистр TWAR выбранный адрес сдвинутый на один бит влево.
Зачем?
Цитата
3) настроить контрольный регистр TWI (TWСR) TWIE=1, TWEN=1, TWEA=1.
А TWINT не надо сбрасывать(в слэйве) при настройке, и в процессе работы (а также при выходе из обработчика прерывания)?
Пока что у меня мастер зависает при попытке что-либо передать на любой из слэйвов...
А слэйвы работают.
Цитата(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
Dec 20 2005, 13:21
Цитата(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.
Dec 20 2005, 14:31
Установил адрес слэйва - $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
А этот бит устанавливаться не хочет.
В чем же тут дело?
Цитата(James D. @ Dec 20 2005, 17:31)

Установил адрес слэйва - $40, а мастер вызывает адресом - $20. Так?
........
Слэйв-приемник постоянно входит в обработчик прерывания TWI, производит проверку адреса (код $60 не соответствует, и выходит из прерывания), даже если мастер вообще передачу по TWI не начинает.
...........
В чем же тут дело?
1) Адреса должны совпадать.
2) В прерывании вы ДОЛЖНЫ обрабатывать все события, не только $60. у меня, например сеть висла, если я не обрабатывал $F8 и $00.
3) успехов!
bodja74
Dec 20 2005, 18:26
Хорошо,обьясняю популярнее.
Слейву вообще по барабану что твориться на шине,
все гораздо проще чем вы думаете.
Если на шине не то что ему нужно,он просто не
выдаст прерывания
Первое прерывание возникнет только после того,когда
проидет СТАРТ и совпадет адресс слейва,TWSR выдаст НЕХ 60,
кричим УРА ,устанавливаем TWINT=1 и дружно выходим из прерывания.
TWI при этом АППАРАТНО выдает АСК.
Второе и ДАЛЕЕ прерывание возникнет после того,когда
прибудут данные ЕСЛИ ПЕРЕД ЭТИМ СОВПАЛ АДРЕСС
( то есть уже прошли первое прерывание)
TWSR выдаст НЕХ 80.устанавливаем TWINT=1 и
в TWDR имеем полученные данные,отправляем их куда хотим.
выходим из прерывания.
И ПОСЛЕДНЕЕ решаем выставлять нам АСК при следующем получении
данных или нет.
ЕСЛИ НЕТ тогда в следующем прерывании TWSR выдаст НЕХ 88
а МАСТЕР должен выдать СТОП.
Соответственно мастер должен определять NACK и выдавать СТОП на шину.
ПОСЛЕДНЕЕ в принципе не обязательно.
Просто если охота делать так как книжка пишет.
Сложно?
Я думаю проще некуда.
У меня при таком раскладе слев легко берет пакеты со скоростью
800Кбит в сек ,при частоте проца 8Мгц
James D.
Dec 21 2005, 07:35
Цитата(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
Dec 21 2005, 10:00
Добрый день
Вот бы кто из действительно шарящих людей описал бы подробно процесс обмена
в случае с однирм мастером (приемником и передатчиком) и 2 слейвами
Ну типа там
1. Мастер посылает АСК ....
2. .....
Всем Спасибо
De}{teR
Цитата(DeXteR @ Dec 21 2005, 13:00)

Вот бы кто из действительно шарящих людей описал бы подробно процесс обмена
в случае с однирм мастером (приемником и передатчиком) и 2 слейвами
а чем ,простите, шит не устраивает . имхо все доходчиво
IgorKossak
Dec 21 2005, 10:10
Цитата(m16 @ Dec 21 2005, 12:06)

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

Цитата(m16 @ Dec 21 2005, 12:06)

а чем ,простите, шит не устраивает . имхо все доходчиво
Ну, например, на русский его перевести.
Хотя, ести перечитать всю эту тему, то это уже сделано.
Уважаемый Games D.! Вы задаёте вопросы на которые ЕСТЬ однозначные ответы в datahsheet на AVR (если быть точнее в разделе "Two-wire Serial Interface"), поэтому у меня есть конструктивное предложение: задавайте вопросы в таком виде "в пункте таком-то даташита написано что надо делать так-то, что бы получить то-то а у меня выходит сяк-то.". просто практика показывает что если делать, как рекомендуется в datasheet, то всё работает с первого раза и с минимальными временами на отладку.
для общего ознакомления с I2C можно прочитать это (на русском).
James D.
Dec 21 2005, 11: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?).
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. После этого слэйв выходит из программы приема данных - продолжает выполняться основная программа.
Цитата(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.
Dec 21 2005, 13:13
Так, заменил на ожидание "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.
Dec 21 2005, 13:30
Кстати, в даташите (в приведенном там примере) стоит ожидание "1" - после посылки START.
P.S. Прочитал PDF'ку, и сразу возник вопрос: надо ли в процессе работы TWI как-то коммутировать порты (PC0, PC1). У меня они настроены на ввод с вкл. подтягивающими резисторами.
Цитата(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
Dec 21 2005, 14:24
Цитата(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.
Dec 21 2005, 14:54
Цитата
Это значит, что первое прерывание у слейва возникает только если его адрес совпал или было обращение по широковещательному адресу (событие 0x70) или их ошибочные варианты (0x68, 0x78).
Далее требуется коррекция Вашего алгоритма.
Но ведь слэйв проверяет содержимое TWSR на соответствие $60 как раз в обработчике прерывания, значит само прерывание возникает до того.
У меня обработчик слэйва начинается так:
Код
;*******************************************************************
;Режим - подчиненный-приемник:
TWI_Obr:in temp,TWSR
andi temp,$F8
cpi temp,$60 ;Проверка принятого адреса
breq Pr_data ;Переход на прием данных
reti
IgorKossak
Dec 21 2005, 15:19
Цитата(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
Dec 21 2005, 15:30
Добавлю также, что надо анализировать ВСЕ события и делать все действия. Ничего не сокращая! Оптимизировать будете когда всё заработает.
bodja74
Dec 21 2005, 19:25
Цитата
То 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)
Все!!!
Сложно?
Немного не по теме. Кто-нибудь встречал русскоязычное описание USI для "тинек", для того же двухпроводного интерфейса?
James D.
Dec 22 2005, 13:16
Сделал следующее.
Убрал из программ мастера и слэйва передачу данных при включении обоих МК - там было не по прерываниям, а в основной программе.
Далее. Слэйв:
Код
;Инициализация 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
Dec 22 2005, 14:25
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.
Dec 22 2005, 14:56
Цитата
4. Байт адреса слейва, передаваемый мастером в Вашем случае должен быть 0x40, т. е. сдвинутым на 1 влево, т. к. младший бит это R/W. См. рисунок Typical Data Transmission.
Вобщем, адрес в слэйв и, передаваемый мастером, должны совпадать: слэйв - $20, мастер - $20, или слэйв - $40, мастер - $40. Правильно?
Все МК у меня работают на частоте 4 MHz. Значит скорость в мастере я установлю не менее 10 (как, впрочем, у меня всегда и было - ставил $14).
IgorKossak
Dec 22 2005, 15:30
Цитата(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
Dec 22 2005, 16:46
К IgorKossak мне уже добавить особо нечего,
единственное проверять F8 необязательно после проверки TWINT,
это промежуточное значение когда TWINT=0.
James D.
Dec 23 2005, 09:09
Переписал проги. Слэйв:
Код
;***** Векторы Прерываний *****
.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.
Dec 23 2005, 11:14
Цитата(bodja74 @ Dec 22 2005, 19:46)

К IgorKossak мне уже добавить особо нечего,
единственное проверять F8 необязательно после проверки TWINT,
это промежуточное значение когда TWINT=0.
А где я проверяю F8?
bodja74
Dec 23 2005, 11:51
Мастеру нужно ждать пока 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
Dec 23 2005, 12:01
Цитата
;Режим - подчиненный-приемник:
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.
Dec 23 2005, 14:33
Цитата
Насчет 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
Dec 23 2005, 19:27
Я извмняюсь,наверно неважный из меня советчик.
Хотелось помочь ,а не обидеть.
Теперь продолжим.
Цитата
Как с чем? Ждем когда TWINT обнулится, потом:
Нужно ждать появления "1" в TWINT
Цитата
таким образом биты предделителя замаскированы нулевыми значениями, и можно проверять код состояния
Вы их не маскируете,а подменяете значение полученое от TWSR.
Кроме того Предделитель TWSR вы уже обнулили в основной программе,Вот
Цитата
To_SL: ldi temp,$14;Установка скорости передачи= ? kHz
out TWBR,temp
ldi temp,$00
out TWSR,temp
Обнулите TWSR и слейве (я выше давал раскладку регистров)
Если в мастере проверять только TWINT слейв можно отключить.
И посмотреть до какого этапа дошел мастер,должен проходить до конца
и без слейва.
bodja74
Dec 23 2005, 23:31
Вот код для мастера.
Я щасс "графический" асм юзаю (удобнее гораздо),пришлось тряхнуть стариной с "классическим"
Здесь адресс $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.
Dec 24 2005, 09:02
Предлагаю сразу прояснить ситуацию с адресами.
Допустим адрес слэйва - $20, мастер в режиме передачи данных (Write) должен выдавать адрес - $20, а при чтении (Read) - адрес $21. Правильно?
Идем дальше.
bodja74, Вы, в приведенной проге мастера, нигде не проверяете регистр TWSR, можно ли так делать?
Второй вопрос. Вот здесь:
out TWDR,adress
ldi temp,$C4
out TWCR,temp
Вы в мастере устанавливаете бит TWEA, нужно ли это делать? Я думал, что этот бит участвует только при приеме данных.
И последний вопрос. Пауза, после передачи STOP, она нужна, Вы написали: "чтобы модуль TWI смог завершить команду СТОП". Эта пауза должна быть какой-то определенной величины? Можно ли об этой паузе узнать поподробнее? Что будет, если ее не выдерживать? Или она нужна только перед "сном"?
James D.
Dec 24 2005, 10: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
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
Dec 24 2005, 13:06
Цитата(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.
Dec 24 2005, 13:47
Ну вот теперь, наконец, с адресацией разобрались!
Цитата
Зайдите на этом форуме на тему "не могу писать 24с256" ,почитайте мои посты ,просто не охота
повторяться.
А этой темы я что-то не нашел...
bodja74
Dec 24 2005, 20:36
Цитата(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
Потом прога неспешно выбирает значения и обрабатывает данные.