четверг, 21 января 2010 г.

Atmel AVR USI TWI library

Довелось на днях разбираться с тем, что предоставляет нам Atmel для взаимодействия с устройствами по протоколу i2c. Производители решили, что реализовывать раздельно spi и i2c много чести, и предоставили нам набор "рассыпухи", из которой мы сами можем соорудить один из интерфейсов, или придумать свой. Основные составляющие этого набора это сдвиговый регистр для обмена данными, 4-х битный счётчик для подсчёта количества пришедших бит, и различные переключалки, для выбора типа протокола, тактового генератора и пр плюс кое-какие прерывания под это дело. Всего три 8-ми битных регистра.
Первым делом глянул в гугл на предмет готовых реализаций i2c на этом железе. Однако, может я плохо смотрел, но нашел только исходники на аппаратный twi. Про TWI на USI были упоминания рядом с IAR (навороченная среда разработки под МК), но что тянуть палёный и непонятный код. Было решено написать "библиотечку" на основе исходников под аппаратный twi.
Собственно, оттуда я взял только названия функций. Посылка на старт, стоп и клоки реализуется программно, т.о. функции у нас получились блокирующие, и во время пересылки мы не сможем больше ничего сделать. Но поскольку twi мне нужен только для начальной конфигурации пары девайсов, то такая не совсем оптимальная реализация меня устраивает.
Во время внимательного чтения даташита на предмет управления с этими тремя регистрами, и попытки оживить всё это дело, обнаружилась пара совершенно тонких и не очевидных нюансов, ради которых и я пишу эту заметку. В документации о них написано весьма вскользь, и, как мне кажется зря.

1. Во первых, нет чёткого разделения на мастера и слейва. И логика устроена так, что при опознавании на начала передачи выставляется флаг USISIF в регистре USISR и одновременно с этим блокируется линия SCL. Особенность в том, что флаг срабатывает и тогда, когда старт формирует сам девайс, и, т.о. чтобы дальше была возможность контролировать SCL необходимо этот флаг сбросить.

2. Передача данных из USIDR на порт. Этот момент менее описан в доках, по этому за правильность не ручаюсь, но когда я сначала выставлял на порт SDA нуль, а после писал данные в USIDR и пытался их оправить, то линия никак на мои действия не реагировала. Однако, когда я сначала выставил на SDA единичку, после чего, чтобы таки выставить его в нуль для посылки start, записал 0x00 в USIRD, и только после этого записал адрес устройства и попытался его отправить, то всё заработало. Эврика, как говорится :) Итого, рецепт такой. Пишем в PORT на пины SDA и SCL по единичке, потом делаем их выходами, а после рулим через USIDR и флаг USITC из USICR.

Исходники можно взять по адресу http://galilley.at.nsu.ru/usitwi.tar.bz2, но есть нюанс, проверена работоспособность только функций на запись, функции на чтение не отлажены, хотя теоретически должны работать.

2 комментария:

Петр комментирует...

Большое спасибо за статью. Борюсь с Tiny26 в этом же ключе. Буду благодарен за исходники.
admin@soberyrobota.com.ua

DS комментирует...

Точно, я же замотался и совсем забыл выложить исходники. спешу исправится :)