аппаратный I2C (TWI) Mega2560 кто-то пользовал?
- Войдите на сайт для отправки комментариев
Как-то устал курить даташит на мегу. Вроде как все понятно, прочел даже описание интерфейса в Википедии.. остались вопросы:
1. Частота работы. В вики сказано, что мастер может выставлять 10, 100 и 400 кгц. Есть типа "новы" стандарт на 3.8Мгц .. а у дуньки-меги регистр под установку делителя и ещё аж целых 2 бита в другом регистре под масштабный множитель .. спрашивается зачем (нафига попу эта гармонь)? Не поленился, подсчитал .. если заюзать все возможные варианты, то частоту можно программировать от 491 герца до 888 килогерц. А аппаратная часть "поймет" нестандартную частоту? И "кому надо 491герц"? Фигня какая-то. Тем более, что ардуиновский Wire.h ставит тупо 100кгц и не парится.
2. Ардуиновский Wire.h, точнее utility/twi.c при каждои чике проставляет в TWICR битик TWIEN -- "включить TWI" .. зачем? Он что, после каждой итерации авто выключается? аналогично переустанавливаются ещё несколько битиков в регистре управления каждый раз ..
3. И в даташите, и в стандарте есть "групповые" режимы обмена .. в смысле передача пачки данных после подтверждения данных .. однако, реализация в Wiring сделана строго побайтная с рестартом после передачи каждого байта .. типа для надежности или зачем?
Может кто-то пояснить по вопросам?
Ну и? Никто не может подсказать или я как-то непонятно пишу? :)
Ну и? Никто не может подсказать или я как-то непонятно пишу? :)
тут тебе платная справочная контора, гарантирующая обязательный ответ на твой вопрос?
что, за нах "ну, и?"?
почитайте может поможет
http://www.avrfreaks.net/forum/i2c-twi-library
https://github.com/g4lvanix/I2C-master-lib
Спасибо за ссылки, посмотрел. Это практически "в лоб" реализация примеров из даташита без обработчика прерываний.
1. вопрос про настройку частоты: И тут точно также частота TWI задается фиксом в 100кгц. Прескалер тупо ставится в 1, и делитель подбирается из соотношения частоты проца к заданным 100кгц. Ответа на этот вопрос тут тоже нет.
Меня интересует ответ на вопрос: Надо ли (стоит ли) делать отдельную функцию twi_setSpeed(f), которая сможет вычислять значения как для прескалера так и делителя для любой, произвольной частоты передачи? или эта частота фикс в 100кгц? Почему тогда стандарт прописывает ещё 400кгц? А если это делать незачем, то нафига у проца весь этот баян с делителем и прескалером, когда вполне достаточно одного делителя ..
Если такую функцию сделать, то можно общаться на частотах от 0.491 до 888 килогерц (при тактовой в 16Мгц) и даже делать автонастройку частоты обмена с конкретным устройством - работать на максимально возможной частоте для железок. А получится?
2.вопрос про перевключение при каждом чихе: тут точно также постоянно дергается TWEN - "включить TWI", даже чаще чем в примерах даташита .. сильно подозреваю "на всякий случай" .. или оно "так надо" и не будет работать? Например, если аппаратно блок TWI после каждой передачи отключает свои ноги от пинов, переводя их в третье состояние .. так на самом деле или нет?
3. С этим разобрался.
ИМХО: в целом реализация в Wiring не настолько фиговая, как те же функции millis() или работы с пинами .. вся работа с TWI построена на обработчике прерывания в виде "конченного автомата". Единственное что откровенно не нравится - это двойная буферизация как данных так и работы с самим автоматом .. навеяло из КБРД:
"... Новости: Редакция молодая гвардия выпустило в свет серию романов для детей: "Боевой Устав" ... замечательный роман, но почему-то авторы забывают что противник был уничтожен ещё в первой главе и в дальнейшем его снова окружают и подавляют огнем .. но, в целом роман интересен и патриотичен и мы настоятельно рекомендуем книгу мальчикам предпризывного возраста"
В общем, пока решил оставить в тексте все эти чедесатости и сделать ряд отдельных функций по управлению TWI. Буду проверять чё получится и как оно на самом деле. Удастся ли связать мегу с уной на 800кгц или нет.
Ещё вопрос: Что делает периферия, когда мастер читает данные с ошибкой? Она способна (бывает такая) переотправить только последний байт повторно или требуется перезапуск всего чтения?
Просто при ошибке приема есть несколько разных ситуаций:
а) ожидался один байт или пришел косяк с первого байта - можно и перезапусить все заново.
б) принят ошибочный байт в середине приема (мож просто помеха) .. и что, всё заново? Получить повторно только кривой байт - никак? Мастер же отправил NACK ..
1. Частота работы.
Не частота, а максимальная частота. Интерфейс синхронный, от частоты мало зависимый, лиш бы устройства успевали. Потому если устройство осилит 100КГц то и на 500Гц будет работать. Эту шину вообще можно остановить на какое то время, например в прерывание уйти, потом продолжить. Набор делителей и множетелей для адаптации под кварц, далеко не всегда работаем на 16МГц. Реализация стандартной библиотеки только на 100КГц имеет скрытую мудрость - именно медленые устройства не удобны в програмной реализации. При кварце 16МГц для устройства на 400КГц ( а зачастую они могут работать и выше, например SSD1306 у меня устойчиво работает в раене 800КГц) правильный подход - ногодрыг без аппаратных прибамбасов.
При ошибках приема - зависит от устройства. Флеш память с блоковой записью, один байт битый - весь блок не пишем. Экрану похоже без разницы, выводит по мере приема сразу. Вобще случайные ошибки на i2c - больша редкость, если появились, то скорей всего все плохо. Потому забить на их обработку не сильный грех.
О. Пасибки. То есть получается функция установки произвольной скорости может оказаться даже полезной: при желании, можно будет организовать связь вплоть до 1Мгц, и даже делать "автонастройку" частоты: "Ась? А медленнее? А ещё?" :)
С ошибками - посмотрю что можно сделать. Пока вырисовывается драйвер в виде конечного автомата на прерывании с логированием количества успешного объема и ошибок свзяи .. что-то типа диагностики от линуксового ifconfig по сетевым интерфейсам: столько-то принято, передано, конфликтов шины, ошибок адреса, ошибок передачи данных. Буду тестировать - посмотрю насколько оно "помех не бывает".
делать "автонастройку" частоты: "Ась? А медленнее? А ещё?" :)
Ну не перегибайте ))) За такие вещи приходится платить размером кода, стабильностю и т.д.
Пока вырисовывается драйвер в виде конечного автомата на прерывании с логированием количества успешного объема и ошибок свзяи .. что-то типа диагностики от линуксового ifconfig по сетевым интерфейсам: столько-то принято, передано, конфликтов шины, ошибок адреса, ошибок передачи данных. Буду тестировать - посмотрю насколько оно "помех не бывает".
Главное чтоб все это можна было отключить после отладки, чтоб место не занимало.
Вобще не очень понимаю как совместить на 16Мгц эти моменты: "связь вплоть до 1МГц" и "конечного автомата на прерывании"?
Просто не успеет автомат на прерывании отрабатывать. 16 такта на отправку 1 бита хватит только ногодрыгом. Вот пример вывода на экран (немного менше 1МГц, пришлось NOP вставлять, вставил везде, хоть можно было и не везде), там свободных ресурсов производительности всего ничего 3 NOP на бит, в них автомат и обработчик никак не лезут (и вобщем не зачем, и так все силы проца ушли на i2c, остальное подождет, кроме прерываний они не запрещены)
Понятно что аппаратно будет побайтная отправка, но при обмене на 1МГц циклов на байт будет 8*16=128 их может (может!!!) и хватит как раз на вход в прерывание, инициализацию отправки и выход из прерывания, но в чем смысл? Вся производительность уже ушла, почти сразу новое прерывание будет и основной цикл мало продвинется.
К Вам небольшой вопросик будет. Я правильно понимаю, что в Вашей разработке digitalWrite при константах в параметрах разварачивается в одну команду, но при вызове digitalWrite в либах в параметрах переменные и это приводит к вызову функции, которая намного "легче" стандартной?
Там в каждом состоянии автомата команд под обработку набирается не более 3-5. Так шта "вполне успеет". :)
Логирование будет выглядеть так:
Нужно - втыкиваешь константу в код - будет. :)
Нужно - втыкиваешь константу в код - будет. :)
Так куда же её воткнеш?! Обычная привязка либы к пинам выглядит так из скетча вызов конструктора (или инициализации) с номером пина - константой. В конструкторе сохраняется этот номер в переменной. И далее используется при выводе эта самая переменная. Прямо в либу тыкать - не красиво, к тому же может быть 2 обекта на разных пинах - совсем плохо.
Мою либу вы же видели? Как темплейтится датчик HCSR-04 видели? Ну вот, примерно также и это будет добавлено по завершению.. хотя, не уверен что буду публиковать.
Причин несколько:
1. В целом, как показал разбор, Wire.h и его нутро utility/twi.h, twi.c в целом реализованы достаточно неплохо. Вполне можно пользоваться, если ресурсы "не жмут" и не требуется какой-то "экзотики". Писано явно прогером со стажем, хотя и без опыта программирования микроконтроллеров (ресурсо-избыточно, но "терпимо").
2. Мой "велосипед" не намного лучше получается по ресурсам, по архитектуре реализации выходит "тоже самое" .. разве что будет позволять разного рода выкрутасы и даст некоторую экономию по коду. Что мало кому полезно.
В целом, как тут уже мне писали: "нет спроса - нет предложения". Пока особой полезности втыкать этот вариант в либу - не вижу. Да и работы "многовато" оказалось .. выкладывать в бесплатный доступ .. не знаю, пока нет желания, особенно без ожидаемой существенной пользы. Пока работа больше ведется на желании "разобраться" с этим протоколом "для себя".
Ну и ещё вопрос: Slave Recieve Mode -- применяется на практике, где? Я пока вижу только обмен между дуньками .. но это всеж-таки "не скоростной интерфейс".
Аналогичный вопрос с передачами "всем" и прием таких сообщений Ардуино "извне" .. они бывают на практике? Отправку "всем" из Ардуино как мастера шины - я могу себе представить .. а вот "прием всем" - как-то не хватает фантазии.
Если да, то хотелось бы почитать о примерах где и как такое применяется.
Просто получается, что верхний уровень интерфейса (типа Wire.h) "знает чего хочет" в данный момент: принять или передать что-то кому-то. Его иожно и нагрузить вопросом буферизации данных, а из нижнего слоя устранить заранее выделяемые буфера передач. Экономия памяти и как ни странно кода тоже. Но это - режимы "мастера": "отправил команду - получил результат" или "отправил железяке "команду и данные". Частично так же можно решить и с режимом Slave: если верхний уровень знает, что что-то может прилететь, то он же и буферизацию способен организовать. Надо вести прием и передачу одновременно - "не проблема".
Но, если при этом требуется реакция на внешнюю активность и особенно "всем", то наличие буферизации в нижнем уровне может оказаться оправданным: принял то, что верхнему уровню и не требовалось, но зато не запорол сеанс связи. Вот бывает ли такое? То есть, бывают ли применения, когда Ардуино стоит в шине из нескольких мастеров, которые способны слать что-то "всем" (ХШ подсказывает: "Всем: Капец, авария!" или "Всем: Матрица, перезагрузка!") и её ПО не заточено никак на реацию, но принять такой сеанс таки надо...
.. кстати, а что будет делать мастер, инициировавший такую передачу "всем" в случае когда на шине сидит с десяток устройств и каждое отправляет свой ACK? Он же не знает сколько их принять надо!
Бяда .. совсем запутался.
Всем, кто хочет разобраться с шиной I2C рекомендую: http://easyelectronics.ru/interface-bus-iic-i2c.html#comments свои проблемы я решил. Этот топик можно закрыть или пофлудить. :)
Подниму тему ещё раз. Оказывается не "все проблемы" .. :)
Вопрос по широковещательной связи "всем" так и остался.. даже 2:
1. Предположим, что на шине сидит с десяток устройств и все они могут работать как в режиме "Мастер", так и "Slave" (ардуино кластер). Все слушают шину в режиме slave и при обнаружении широковещательной передачи должны отдать ACK .. тот, кто её запустил как поймет что ВСЕ приняли сигнал или КТО-ТО "пролетел" (отдал NACK)?
Как понял стандарт, на шине действует "монтажное или", и соответственно NACK (=0) - "рулит", то есть если кто-то один "глух", то мастер получит NACK .. что ему делать? В смысле КАК узнать, что глух кто-то один и в режиме "всем"? При последовательном опросе адресов он жеж может и откликнуться штатно ..
2. Настройка мастера на частоту передачи .. в ситуации "несколько мастеров" каждый из них может быть настроен на свою частоту .. но шина "синхронная" .. или так не надо делать? В описании протокола ничего не нашел или просмотрел. В принципе, такая ситуация тоже легко приводит к коллизии на стадии передачи адреса мастерами .. но только шина будет синхронизироваться наименьшей частотой (монтажное или). Или на одной шине все мастера ОБЯЗАНЫ работать на одной частоте?
Может кто-то прояснить эти вопросы?
.. хотя нет, в первом вопросе получается что бит TWEA - один и на отклик на свой адрес и на всем. То есть, если есть NACK, то он же будет и при адресном запросе к устройству... или нет?
Народ, так надо дополнять arhat.h интерфейсами или нет? помогайте, кто знает ответы .. :) вопрос с мастерами на разных частотах так и остался.
Ты уже свою либу во всех темах распиарил.
Блин, да не пиарю я ничегошеньки! Не нравится - не пользуйтесь .. разве где-то и что-то и кому-то навязывал? Тут - спрашиваю как сделать интерфейс I2C (он же TWI, 2-Wire и т.п.). Да, делаю как развитие этой либы, ибо нужен самому. Пока получается ужать раза в 2-3 то что есть в wiring и сэкономить около 60 байт оперативы, сохранив ВСЕ возможности аппаратной части и поиметь обмен на скоростях до 1 мегагерца. Я же не навязываю ничего! Мне надо - я и делаю. А будет ли кто-то ещё этим пользоваться и надо ли кому такое - мне глубоко ... "все равно".
Лучше бы пояснили что-то по делу. Разберусь и сам конечно, не первый интерфейс и не первый МК "в руках"..
Поднял тему, перечитал и желание постить очередной вопрос - как-то завяло. Но, тем не менее, вопрос на засыпку знатокам этого интерфейса:
Ардуино имеет аппаратный TWI контроллер, который существенно разгружает проц. и фактически делает буссмысленным программную имитацию интерфейса. Он умеет работать во всех режимах и как мастер и как слейв и даже ОДНОВРЕМЕННО.
А теперь, вопрос на засыпку: Если указать ему "свой адрес" на шине и поставить в режим слейв, то он будет слушать шину и принимать данные. В сети куча примеров ..
внимание, вопрос: если в режиме мастер попытаться передать на шину адрес своего же слейва - контроллер будет принимать "сам себя" или нет? То есть чать контроллера, которая мастер - выкладывает на шину адрес своего же слейва и пишет ему байтик .. слейв его примет, поскольку они управляются разными битами статуса .. и, куда он его сложит? Регистр данных - ровно один и общий жеж. :)