|
|
  |
Проблема с TWI |
|
|
|
Dec 22 2005, 14:56
|

Местный
  
Группа: Участник
Сообщений: 315
Регистрация: 10-10-05
Пользователь №: 9 466

|
Цитата 4. Байт адреса слейва, передаваемый мастером в Вашем случае должен быть 0x40, т. е. сдвинутым на 1 влево, т. к. младший бит это R/W. См. рисунок Typical Data Transmission. Вобщем, адрес в слэйв и, передаваемый мастером, должны совпадать: слэйв - $20, мастер - $20, или слэйв - $40, мастер - $40. Правильно? Все МК у меня работают на частоте 4 MHz. Значит скорость в мастере я установлю не менее 10 (как, впрочем, у меня всегда и было - ставил $14).
|
|
|
|
|
Dec 22 2005, 15:30
|

Шаман
     
Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221

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

Местный
  
Группа: Участник
Сообщений: 315
Регистрация: 10-10-05
Пользователь №: 9 466

|
Переписал проги. Слэйв: Код ;***** Векторы Прерываний *****
.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:12
|
|
|
|
|
Dec 23 2005, 11:51
|
Знающий
   
Группа: Свой
Сообщений: 543
Регистрация: 22-10-05
Пользователь №: 9 984

|
Мастеру нужно ждать пока 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
|
|
|
|
|
Dec 23 2005, 14:33
|

Местный
  
Группа: Участник
Сообщений: 315
Регистрация: 10-10-05
Пользователь №: 9 466

|
Цитата Насчет 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 ,с чем связаны эти маневры? Цитата <<<<<<<<<< И ЭТО ЗАЧЕМ?????????? я просто не понимаю. Зачем-зачем, так описано в документации.
|
|
|
|
|
Dec 23 2005, 19:27
|
Знающий
   
Группа: Свой
Сообщений: 543
Регистрация: 22-10-05
Пользователь №: 9 984

|
Я извмняюсь,наверно неважный из меня советчик. Хотелось помочь ,а не обидеть. Теперь продолжим. Цитата Как с чем? Ждем когда TWINT обнулится, потом: Нужно ждать появления "1" в TWINT Цитата таким образом биты предделителя замаскированы нулевыми значениями, и можно проверять код состояния Вы их не маскируете,а подменяете значение полученое от TWSR. Кроме того Предделитель TWSR вы уже обнулили в основной программе,Вот Цитата To_SL: ldi temp,$14;Установка скорости передачи= ? kHz out TWBR,temp ldi temp,$00 out TWSR,temp Обнулите TWSR и слейве (я выше давал раскладку регистров) Если в мастере проверять только TWINT слейв можно отключить. И посмотреть до какого этапа дошел мастер,должен проходить до конца и без слейва.
|
|
|
|
|
Dec 23 2005, 23:31
|
Знающий
   
Группа: Свой
Сообщений: 543
Регистрация: 22-10-05
Пользователь №: 9 984

|
Вот код для мастера. Я щасс "графический" асм юзаю (удобнее гораздо),пришлось тряхнуть стариной с "классическим" Здесь адресс $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
|
|
|
|
|
Dec 24 2005, 09:02
|

Местный
  
Группа: Участник
Сообщений: 315
Регистрация: 10-10-05
Пользователь №: 9 466

|
Предлагаю сразу прояснить ситуацию с адресами. Допустим адрес слэйва - $20, мастер в режиме передачи данных (Write) должен выдавать адрес - $20, а при чтении (Read) - адрес $21. Правильно? Идем дальше. bodja74, Вы, в приведенной проге мастера, нигде не проверяете регистр TWSR, можно ли так делать? Второй вопрос. Вот здесь:
out TWDR,adress ldi temp,$C4 out TWCR,temp
Вы в мастере устанавливаете бит TWEA, нужно ли это делать? Я думал, что этот бит участвует только при приеме данных. И последний вопрос. Пауза, после передачи STOP, она нужна, Вы написали: "чтобы модуль TWI смог завершить команду СТОП". Эта пауза должна быть какой-то определенной величины? Можно ли об этой паузе узнать поподробнее? Что будет, если ее не выдерживать? Или она нужна только перед "сном"?
|
|
|
|
|
Dec 24 2005, 10:08
|

Местный
  
Группа: Участник
Сообщений: 315
Регистрация: 10-10-05
Пользователь №: 9 466

|
Переписал программы. Слэйв: Код ;Инициализация 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", то следующий, переданный мастером байт, запишется в ту же ячейку памяти слэйв, что и предыдущий. А это негодится.
|
|
|
|
|
Dec 24 2005, 13:06
|
Знающий
   
Группа: Свой
Сообщений: 543
Регистрация: 22-10-05
Пользователь №: 9 984

|
Цитата(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" ,почитайте мои посты ,просто не охота повторяться. Остальное вечером после работы.
|
|
|
|
|
Dec 24 2005, 13:47
|

Местный
  
Группа: Участник
Сообщений: 315
Регистрация: 10-10-05
Пользователь №: 9 466

|
Ну вот теперь, наконец, с адресацией разобрались! Цитата Зайдите на этом форуме на тему "не могу писать 24с256" ,почитайте мои посты ,просто не охота повторяться. А этой темы я что-то не нашел...
|
|
|
|
|
Dec 24 2005, 20:36
|
Знающий
   
Группа: Свой
Сообщений: 543
Регистрация: 22-10-05
Пользователь №: 9 984

|
Цитата(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 Потом прога неспешно выбирает значения и обрабатывает данные.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|