I2c сниффер

Bus Pirate Logic, SPI, I2C Protocol Analyzer

i2c сниффер

The Bus Pirate is a Logic and Protocol Analyzer from Sparkfun which can analyze I2C, SPI, JTAG, MIDI, HD44780 LCD and other protocols. With the free LogicSniffer software, this has to be the cheapest analyzer around.

The Bus Pirate, created by Ian Lesnet and featured on Hack a Day, is a troubleshooting tool that communicates between a PC and any embedded device over most standard serial protocols, which include I2C, SPI, and asynchronous serial — all at voltages from 0-5.5VDC. This product eliminates a ton of early prototyping effort when working with new or unknown chips.

These boards are loaded with the latest bootloader and firmware. Currently these are

  • Bootloader V4.4
  • Firmware V5.10
  • Board V3

Note: This is the board only. Also check out the Bus Pirate Cables and Test Hooks

The Bus Pirate can be used either as a Protocol analyzer by using the LogicSniffer software (see downloads at bottom of page) or can be used to send data to a device by typeing commands into a terminal on your computer, those commands are interpreted by the Bus Pirate and sent via the proper protocol. The Bus Pirate will also interpret data sent from your embedded device back to your computer terminal. A big bonus is the bootloader installed on the PIC, which allows you to easily update the firmware and change the functionality of the board.

The main components of the Bus Pirate are PIC24FJ64 processor and an FT232RL USB-to-Serial chip. A Mini-B USB connector is populated on the board, and when you plug it into your computer it will come up as a virtual COM port.

The Bus Pirate can be used with the open source Logic Sniffer Software to give you a 5 channel Logic Analyzer tool that can help you debug Serial, Logic, I2C, SPI and other protocols.

LogicSniffer showing captured data

LogicSniffer showing decoded I2C analysis

Bus Pirate and Logic Sniffer Video

Features:

  • Supported protocols:
    • 1-Wire
    • I2C
    • SPI
    • JTAG
    • Asynchronous serial
    • MIDI
    • PC keyboard
    • HD44780 LCD
    • 2- and 3-wire libraries with bitwise pin control
    • Scriptable binary bitbang, 1-Wire, I2C, SPI, and UART modes
  • 0-5.5volt tolerant pins
  • 0-6volt measurement probe
  • 1Hz — 40MHz frequency measurement
  • 1kHz — 4MHz pulse-width modulator, frequency generator
  • On-board multi-voltage pull-up resistors
  • On-board 3.3volt and 5volt power supplies with software reset
  • Macros for common operations
  • Bus traffic sniffers (SPI, I2C)
  • A bootloader for easy firmware updates
  • Transparent USB->serial mode
  • 10Hz — 1MHz low-speed logic analyzer
  • Scriptable from Perl, Python, etc.
  • Translations (currently Spanish and Italian)
  • Enumerates as a virtual COM port over USB
  • Can operate as AVR STK v2 clone programmer
  • Access to PIC24FJ64 ICSP programming port

Dimensions: 2.10 x 1.20″ (53 x 30mm)

Documents:

Источник: http://www.hobbytronics.co.uk/bus-pirate

[Из песочницы] I2C-сниффер03.04.2017 17:08

Добрый день! Как-то возникла на работе проблема — имеется устройство, работающее по I2С и протокол которого необходимо было понять. Следовательно, нужен сниффер под интерфейс I2С, который бы выводил все, что приходит-уходит по I2C, на порт UART и далее через преобразователь на COM-порт компьютера.

Начало

Под рукой валялись только пара атмег8 и я решил почему бы не использовать их. Далее, встал вопрос схемы сниффера.

Было 2 варианта — включать сниффер параллельно, либо в разрыв цепи. Очевидно, что первый вариант выглядит гораздо проще, что на деле оказалось совсем не так. Но обо всем по порядку.

Вкратце, о самом интерфейсе. В I2C (TWI по-атмеловски) используется два провода — SCL и SDA. Первый отвечает за тактирование сигнала, второй за передачу непосредственно информации. Также интерфейс располагает состояниями СТАРТ и СТОП.

Так вот, первая моя мысль была — взять щуп и с одной стороны подключить его к ноге внешнего прерывания на atmega8 с другой на линию SDA и ловить передний фронт, и по прошедшему времени определять 0 или 1. Очевидно, что работать это должно было очень плохо, так как не отрабатывался корректно сигнал СТОП.

Вторая мысль была сделать все то же, но прерывание ловить на линии SCL, и по прерыванию читать линию SDA, подключенную на обычную цифровую ногу. Здесь все выглядело уже более жизнеспособно, кроме того же состояния СТОП, но я решил попробовать собрать на макетке и посмотреть что же будет.

Заранее извиняюсь, если найдете очевидные промахи в коде ниже, так как отвергнутые варианты кода восстанавливаю по памяти на коленках.

Код обработчика прерывания выглядел следующим образом:

ISR(INT0_vect)
{ cli(); if (bitIsHigh(PINB, 0)) uart_send_char('1'); else uart_send_char('0'); sei();
}

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

В процессе выяснения причин все свелось к тому, что данные теряли из-за обращения к uart интерфейсу, который, к слову, работал на максимальной стабильной скорости 38 кбит/с, при этом сам I2C работал на 100 кбит/с.

Поднимать скорость работы UART не представлялось возможным ввиду отсутствия кристалла необходимой частоты, чтобы перевести uart на допустимую скорость. Следовательно нужно было убирать работу с uart из прерывания. Получил что-то следующее:

static uint8_t data = 0;
static uint8_t idx = 7; ISR(INT0_vect)
{ cli(); data |= bitIsHigh(PINB, 0)

Источник: http://pcnews.ru/blogs/%5Biz_pesocnicy%5D_i2c_sniffer-760884.html

Сниффер шины I2C на микроконтроллере AVR

Сниффер (монитор, «прослушка») I2C шины позволяет проводить мониторинг шины не влияя на работу проверяемого устройства: все данные, включая адреса устройств, сигналы ACK/NAK, условия START и STOP передаются в текстовой форме в терминальную программу на компьютере по последовательному интерфейсу.

В своих разработках, при отладке устройств и поиске ошибок, где используется интерфейс I2C, пользователям не редко необходимо знать, что происходит на шине при работе устройства.

Существуют коммерческие устройства для этих целей, но чаще всего их стоимость очень высока. Для мониторинга можно было использовать логический анализатор подключенный к сигналам SCL и SDA и расшифровывать протокол вручную.

Для решения этой проблемы и было разработано данное устройство – монитор I2C шины.

Интерфейс I2C был разработан компанией Philips в 1980 г. Это последовательная шина данных для связи интегральных схем, разработанная фирмой Philips в начале 1980-х как простая шина внутренней связи для создания управляющей электроники.

Используется для соединения низкоскоростных периферийных компонентов с материнской платой, встраиваемыми системами и мобильными телефонами. Название представляет собой аббревиатуру слов Inter-Integrated Circuit.

I2C использует две двунаправленных линии, подтянутые к напряжению питания и управляемые через открытый коллектор или открытый сток — последовательная линия данных (SDA, англ. Serial DAta) и последовательная линия тактирования (SCL, англ.

Serial CLock), обе нагруженные резисторами. Стандартные напряжения +5 В или +3,3 В, однако допускаются и другие.

Блок схема устройства приведена на рисунке ниже.

Принципиальная схема устройства представлена на рисунках ниже.

Кликните для увеличения

Кликните для увеличения

Кликните для увеличения

Основой устройства является 8-битный микроконтроллер AVR ATmega161 производства компании Atmel. Микроконтроллер использует внешнюю память RAM (ОЗУ), порт RS232 и два вывода для подключения к шине I2C.

Стоит отметить также, что имеется перемычка для установки скорости 9600 бод. Интерфейс RS232 использует линии RTS и CTS для управления потоком.

Интерфейс RS232 выполнен на микросхеме MAX203 (RS-232 трансивер).

Интерфейс I2C может работать на различных скоростях, но обычно в пользовательских устройствах это 100 кГц или 400 кГц. Изначально подразумевалось использовать устройство для 100 кГц шины, поэтому микроконтроллера AVR с рабочей частотой 8 МГц будет достаточно.

Ограничения на скорость накладываются ввиду того, что микроконтроллер AVR должен выполнить несколько инструкций для каждого бита на шине I2C.

В дальнейшем, для мониторинга высокоскоростных интерфейсов I2C, возможно применение дополнительной логики (программируемой логики) для захвата последовательного потока и предоставления данных для дальнейшей обработки микроконтроллеру.

Интерфейс RS232 поддерживает работу со скоростью 115,200 бод. Если данные будут передаваться в формате ASCII, каждый байт на шине I2C займет при передаче по RS232 два байта.

Это вызывает определенные проблемы при буферизации, поэтому было принято решение применить внешнюю память 32 КБайт для использования в качестве кольцевого буфера.

Подпрограмма помещает данные, полученные от I2C интерфейса в конец, подпрограмма обслуживания последовательного интерфейса берет данные для передачи с начала RAM памяти. Простая подпрограмма перемещает указатели обратно на начало внешней памяти RAM при достижении 32 КБайт.

В итоге для устройства понадобится микроконтроллер ATmega161, SRAM память и микросхема для управления памятью 74F573 (8 защелок D-типа). Возможно использование устаревшей памяти – 20 нс 32 КБайт SRAM (например, от старых компьютеров на базе 486 процессора).

Для тестирования памяти (т.к. нет уверенности, что устаревшие микросхемы работоспособны) была предусмотрена подпрограмма тестирования памяти. Вывод микроконтроллера PC7(А15) был выбран для сигнала CS (выбор устройства) микросхемы RAM, таким образом устанавливая RAM на адрес 0.

Перемычка на схеме (J6, вывод микроконтроллера PB0 ) предназначена для снижения скорости обмена по RS232 до 9600 бод (в этом случае внешняя память очень необходима) при подключении к «слабой» терминальной программе, а также при использовании аппаратного контроля потока.

Для отладки устройства применялась отладочная плата производства Atmel STK500.

Программное обеспечение микроконтроллера разработано таким образом, что все основные операции выполняются в обработчиках прерываний. На шине I2C условия Start и Stop формируются при изменении на линии SDA, когда SCL имеет высокий логический уровень, поэтому обработчик прерывания вызывается при каждой смене фронта сигнала SDA.

При входе в обработчик прерывания проверяет состояние линии SCL. Если SCL имеет низкий уровень – обработка прерывания прекращается. Иначе, «новый» уровень линии SDA определяет, было условие Stop или Start.

Все данные и условия записываются в память (S для условия Strat, P для условия Stop), счетчик битов сбрасывается и далее следует выход из обработчика прерывания.

Прерывания для линии SCL (для захвата бит данных) включаются только после определния наличия условия Start и выключаются после обнаружения условия Stop.

Для захвата данных нам необходим лишь нарастающий фронт сигнала SCL. С каждым прерыванием мы «захватываем» линию SDA, чтобы узнать что на линии: 1 или 0.

Каждый бит помещается в специальный регистр, предназначенный для данных, счетчик битов инкрементируется. По достижении 8 бит, происходит конвертация в формат ASCII и сохранение в RAM.

Следующий бит будет ACK или NAK, который также сохраняется в SRAM (A, N).

Пример данных получаемых от сниффера шины I2C в терминальной программе:

S C0 A 73 A E2 A 05 A 00 A 00 A P S C0 A 00 A 7F A 5F A 55 A 00 A P S C0 A 02 A 1F A 07 A 99 A A0 A P S C0 A 5C A 00 A 00 A 00 A D8 A P S C0 A 78 A 00 A 80 A 10 A CC A P S C0 A 7B A E0 A 05 A 00 A 00 A P S A0 A 00 A S A1 A 31 A 31 A 31 A 31 A 31 A 31 A 31 A 31 N P S C0 A 21 A 00 A 00 A 05 A 58 A P

S C0 A 21 A S C1 A 00 A 00 A 00 A 80 N P

По полученным данным видно, что тестируемое устройство производит запись в регистры устройства с адресом 0хС0, проводит чтение данных по адресу 0хА0 (повторное условие Start, следующее за адресом 0хА1), снова производит запись по адресу 0хС0, и затем производит чтение (снова, повторно условие Start) с адреса 0хС1.

Исходный код и прошивка для микроконтроллера

circuitcellar.com

Источник: https://www.rlocman.ru/shem/schematics.html?di=64837

Мониторинг шины I2C

Электронщики в своей работе часто встречаются с шиной I2C. Как правило, на этой шине висят разные заводские микросхемки: датчики, память, раширители портов ввода-вывода, часы реального времени и так далее. Обмен по шине минимален и, в общем-то, достаточен, если говорить о взаимодействии в рамках одной платы или одного небольшого устройства.

Скорость передачи — порядка 100 кбод, на шине может быть несколько мастеров, да и протокол сводится, как правило, к обращению к регистрам устройства. Большинство поставляемых сейчас микроконтроллеров уже имеют на борту модуль обмена по I2C, причём могут быть и мастером шины, и слейвом. Поэтому в некоторых случаях есть смысл использовать I2C для обмена между «своими» устройствами.

В обоих случаях возникает проблема отслеживания линии во время отладки. Дело в том, что при работе, например, с UART, можно взять один из сотен существующих в продаже переходников, подключить его к COM или USB порту и воспользоваться одним из десятков программ-терминалов (например, minicom, hyperterminal, cutecom). А вот с I2C всё не так уж очевидно.

В этой статье попробую рассмотреть несколько найденных вариантов комплексов для анализа шины I2C.Заголовок вышел не совсем корректный, так как я расскажу и о решениях, подключающихся к компьютеру через USB. Дело в том, что все эти решения в конечном итоге прикидываются в операционной системе последовательным портом, после чего передают данные об обменах прямо в терминал.

Для такого класса устройств не требуется установки отдельного ПО, достаточно иметь соответствующий драйвер для адаптера — и можно просто и быстро отлаживать происходящее на линии. Интернет полон различного рода подобных адаптеров. Как правило, это несложные кустарные схемотехнические этюды, использующие штатные возможности микроконтроллеров.

Читайте также:  Fat32 на stm32

Примеры таких проектов:  Плюсы такого подхода:

  • простота исполнения: аппаратно такие адаптеры устроены несложно, при должной сноровке легко повторяются в домашних условиях;
  • нет необходимости в приобретении специфического ПО, достаточно иметь простой терминал последовательного порта;
  • несложно использовать подобные адаптеры при написании скриптов для взаимодействия ПК со схемой.

Однако, очевидны минусы:

  • нет возможности вменяемо оценить загрузку линии;
  • нет возможности фильтровать посылки (что особенно необходимо при большой загрузке линии);
  • ограниченные возможности визуализации и анализа получаемых данных; 
  • нет чёткого стандарта вывода сообщений такими устройствами: каждый любитель, как правило, по-своему отображает события на шине (начало посылки, адрес получателя, «повторный старт» и так далее).

В целом, такие решения неплохо подходят для анализа событий на шине, к которой подключено небольшое количество устройств, редко обменивающихся сообщениями. Они дешевы и при необходимости легко повторимы радиолюбителями. Но их область применения, в сущности, ограничивается несложными любительскими устройствами. Далее рассмотрим более профессиональные программно-аппаратные комплексы для анализа шины I2C.

Программное обеспечение Total Phase Data Center для работы с Beagle Protocol Analyzer

Beagle Protocol Analyzer — устройство, разработанное компанией Total Phase для захвата и анализа данных, передаваемых по шинам SPI и I2C. Подключается к компьютеру через USB, требует для работы специальный драйвер и ПО Data Center.

Анализатор способен считывать данные с линии I2C при частоте шины до 4 МГц, работает только в режиме чтения данных.

Total Phase Data Center — ПО, написанное для работы с серией анализаторов аппаратных интерфейсов (SPI, I2C, USB, CAN), разработанных компанией Total Phase. Для этой серии анализаторов также официально распространяется API для написания собственных программ.

Считанные данные отображаются в окне несколькими способами: в сыром виде (raw) и в виде списка транзакций (сохраняющим, в том числе, время начала передачи). Умеет сохранять записи транзакций, а также экспортировать полученные данные в виде CSV для последующей обработки любым удобным способом, в том числе в математических средах (таких как Matlab) или электронных таблицах.

Данный комплекс предлагает довольно неплохие возможности по сбору данных о работе шины, не вмешиваясь при этом в его работу. Проприетарное ПО распространяется бесплатно (требуется регистрация на сайте Total Phase), доступно для Windows, Mac и Linux в виде 32- и 64-битных бинарников. Cтоимость самого адаптера — $330.

Для активного вмешательства в работу шины можно использовать другой проект этой же компании — Aardwark I2C/SPI Host Adapter

ПО Total Phase Control Center

Ещё один проект представленной выше компании Total Phase, разработанный для активной работы с шинами I2C и SPI.

ПО Control Center предлагает пользователю сконфигурировать адаптер в качестве master или slave, позволяет отправлять сообщения вручную, либо писать несложные batch-скрипты на XML для автоматизации работы с шиной, а также ведёт лог транзакций.

Адаптер подключается к компьютеру по USB, предлагает выбор напряжения логических уровней и питания целевого устройства.

Как и в случае с Data Center, ПО доступно для всех основных платформ и распространяется бесплатно. Стоимость адаптера Aardwark Host Adapter — $275.Bus Pirate — один из самых дешёвых доступных на рынке логических анализаторов, разработанный Ian Lesnet из Dangerous Prototypes.

Является open-source проектом: исходные коды прошивки и разводка печатной платы находятся в свободном доступе. Выпуск этих анализаторов развёрнут компанией Sparkfun.

BusPirate может выступать как обычный логический анализатор, а также имеет встроенную поддержку множества протоколов и интерфейсов, в том числе I2C, SPI, Dallas 1-Wire и HD44780 LCD. Способен выступать в роли пассивного анализатора, а также подключаться к шинам и работать в качестве master или slave.

Общение с ПК происходит через USB-порт, устройство распознаётся как последовательный порт, через который идёт взаимодействие с прошивкой. Доступен интерфейс командной строки, что позволяет использовать устройство без графического интерфейса, а также упрощает написание скриптов.

Для эффективной работы с анализатором используется открытое ПО LogicSniffer. Написанное на языке Java, оно доступно практически для всех платформ.

ПО LogicSniffer в режиме логического анализатора/осциллографа

Данный программно-аппаратный комплекс идеально подходит для многих задач анализа цифровых схем в любительской лаборатории. Идеальным его делает и стоимость самого анализатора — $30.

Однако, существующее ПО ориентировано на анализ физического уровня интерфейсов (с расшифровкой кодов), не предлагая возможностей анализа передаваемых данных. Открытость проекта BusPirate, тем не менее, даёт возможность написать ПО, ориентированное непосредственно на анализ посылок.

ПО BitScope Logic Protocol Analyzer

BitScope — компания, занимающаяся разработкой профессиональных цифровых осциллографов и анализаторов для подключения к ПК.

Для работы с этими устройствами компания разработала целую серию программ, нацеленных на различные задачи анализа сигналов, в том числе на расшифровку и анализ данных, передаваемых по стандартным интерфейсам.

ПО BitScope Logic — логический анализатор с возможностью расшифровки сообщений, передаваемых по протоколам UART, I2C, SPI, CAN и многим другим. Распространяется бесплатно, используется с аппаратным обеспечением BitLogic. Однако, как в случае с LogicSniffer, его возможности ограничены анализом физического уровня. ПО доступно для Windows, Mac OS и Linux.

Стоимость логических анализаторов BitLogic начинается от $150.

Мы рассмотрели лишь несколько решений для анализа передаваемых по шине I2C данных.

Как правило, такие решения нацелены на анализ проблем на физическом уровне, что обусловлено частым использованием I2C с несложными устройствами, работающими по несложным протоколам, где все передачи сводятся к чтению/записи значений регистров. Тем не менее, существуют решения, нацеленные на работу именно с передаваемыми данными.

Беглый обзор существующих решений показывает, что не так просто найти качественное ПО, способное на анализ как физического уровня передающей среды, так и на анализ данных.

Источник: http://ru-webconn.blogspot.com/2015/10/i2c.html

Как я с i2c разбирался…

Моё вхождение в увлечение электроникой, началось с ардуины. Вначале я подключал резисторы, светодиоды, lcd экраны и другие штуки, используя готовые библиотеки.

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

Постепенно назрела необходимость использовать различные МК работающие на i2c, но вначале нужно разобраться как с ними работать, и для этого мне потребовался отладчик, готовых реализаций, для сборки отладчика на радио-компонентах имеющихся у меня в наличии не нашел, поэтому сделал свой.

Перед прочтением желательно прочитать следующее: http://easyelectronics.ru/interface-bus-iic-i2c.html

Общение с устройствами i2c будет через микроконтроллер atmega16, данный микроконтроллер с компьютером соединяется по протоколу USART,  а с устройством i2c,  по 2-м выводам  атмеги  sda и scl соответственно. Получается что микроконтроллер  атмега будет являться посредником в общении,  с устройствами i2c. Реализован только режим мастера.

Для общения с устройствами через USART, был разработан небольшой протокол:

1) Передаваемая строка начинается на ! и заканчивается на &

2) Для установки на шине i2c начала передачи используется символ S

3) Для установки окончания передачи используется символ E

4) Для посылки байта команда Wxx, где хх – шестнадцатиричное значение

5) Если при получении байта от i2c устройства нужно послать AСK то команда будет такой r–, иначе R– будет послан NAK, что означает мы не собираемся больше получать данные.

А теперь собственно пример при работе с мк ds1307 (календарь):

Мы посылаем команду: !SWD0W00E&

Для удобства разобьем команду пробелами,  ! S WD0 W00 E &

1) S – в начале шлем старт

2) WD0 – шлем байт D0 в данном случае он содержит адрес устройства из 7-ми бит, и 8-й бит R/W сейчас он равен нулю.

3) Woo – шлем байт 00, который устанавливает “указатель” на ячейку с которой мы далее будем работать

4) E – завершение связи с устройством

а вот как выглядит:

Пример записи в ячейку 01, значения 22 (хранятся в ней минуты): Посылаем команду: ! S WD0 W01  W22 & (пробелы не должны быть, так просто визуально понятнее сделал)

Пример чтения из устройства секунд, минут и часов: !SWD0W00SWD1r–r–R–E&, а в ответ микроконтроллер пришлет следующее: ++ok+ok++ok+41+47+00+

А теперь расшифрую посылаемую строку поподробнее: !S WD0 W00 S WD1 r– r– R– E&

1) S – начало

2) WD0 – посылаем адрес устройства (с битом write = 0)

3) W00 – устанавливаем указатель

4) S – посылаем повторный старт (требование логики мк ds1307)

5) WD1 – посылаем адрес устройства (с битом read = 1)

6) r–   – после получения байта посылаем ACK

7) r–   – после получения байта посылаем ACK

8)R–  – после получения байта посылаем NAK (сообщая мк ds1307 что больше получать данные не собираемся)

9) E -окончание

Расшифровка полученной строки: + +ok +ok + +ok +41 +47 +00 +

Получаемая строка всегда имеет одинаковую длину с посылаемой, если сопоставим то что отправили и получили увидим следующее:

1) S –> +

2) WD0 –> +ok

3) W00 –> +ok

4) S –> +

5) WD1 –> +ok

6) r–  –> +41   (сейчас 41 секунда)

7) r–   –> +47 (47 минут)

8)R–  –> +00 (0 часов)

9) E –> +

+ и +ok означают успешное выполнение.

И вот часть сигнала:

Зеленый шарик это посылка “старта”……

Сейчас понемногу делаю программу, с более дружественным интерфейсом, выглядит так:

Правда ещё очень сырая, но кому интересно, ниже будет архив, с 2-мя проектами для атмеги, и данной программы.

0034_AVR_SHARP_Tester_I2C

На этом пока и закончу, так-же успел проверить работоспособность с мк MCP23008 – эта мк имеет 8 выводов, которые можно настраивать на вход/выход, и собственно по 2 проводам рулить 8-ю портами.

Источник: http://selenur.ru/?p=88

Программа для контроллера I2C-шлюза (режим I2C-slave из терминалки ПК)

Читать все новости ➔

Итак, продолжаем эксперименты с собранным ранее I2C-шлюзом (который, как вы помните, у нас реализован на ATTiny2313).

В этой статье мы рассмотрим полностью программную реализацию режима I2C-Slave, который позволит нашему девайсу из терминальной программы персонального компьютера прикидываться любым Slave-устройством, а также просто подглядывать за обменом данными на шине I2C (то есть работать как сниффер).

Прога, как всегда, на асме, в конце статьи, как всегда, исходники (с комментариями) и прошивка.

Протокол обмена шлюза с компьютером состоит из однобайтных сообщений, в которых передаются служебные (команды шлюзу — что нужно делать или сообщения компьютеру о том, что сделано) или информационные данные (информация, которую нужно передать или которая получена по шине I2C).

Служебные сообщения мы закодируем следующим образом:

При передаче сообщения в направлении ПК->Шлюз:

20h — отправить байт по I2C (следующий переданный компьютером байт будет отправлен шлюзом по I2C)

21h — принять байт по I2C (следующий принятый компом байт — это тот байт, который шлюз считал с шины)

22h — не посылать Ack

23h — послать Ack

24h — запросить состояние входов порта D (например, для определения уровня на входе Chip Select), следующий принятый компом байт — это байт состояния входов порта D (PIND)

При передаче сообщения в направлении Шлюз->ПК:

20h — на шине произошло start-условие

21h — на шине произошло stop-условие

22h — не получили (не послали) Ack

23h — получили (послали) Ack

24h — ждём дальнейших указаний

FFh — от ПК получена неизвестная команда

02h — произошла реинициализация шлюза

Прежде чем рисовать алгоритм, — напишу немного текстухи, — чтобы было понятнее как это всё работает и как сделан режим I2C-Slave. Работа нашего девайса основана на том, что Slave устройство в протоколе I2C не совсем бесправно, — оно может растягивать обмен, удерживая на низком уровне линию Clock.

Таким образом, в те моменты, когда мастер роняет линию clock в ноль, мы можем захватить эту линию и удерживать её на низком уровне до тех пор, пока не «поговорим» с компьютером.

Далее, для того, чтобы определять на какой стадии обмена данными находится шлюз, — мы, во-первых, используем флаг T регистра SREG, в котором сохраняем текущее состояние линии Clock (это позволяет в дальнейшем определить от какой линии произошло прерывание — от Clock или от Data) и, во-вторых, создали в программе свой собственный регистр флагов (I2C_flags).

В нём мы юзаем 3 флага. Нулевой бит регистра I2C_flags установливается в 1 после обнаружения start-условия и используется при отправке первого Ack (после получения первого байта).

Используется он следующим образом: если мы посылаем «Ack», то флаг сбрасывается и мы продолжаем обмен, если же мы посылаем «No_Ack», то шлюз реинициализируется и ждёт нового старт-условия на шине.

Это для случая, когда на шине несколько slave-устройств, а мы хотим эмулировать только какое-то одно (первый байт после старт-условия — это адрес устройства, и, если обращаются не к нам, то мы последующий обмен игнорируем и ждём нового старт-условия). Первый бит регистра I2C_flags — это направление передачи данных, когда он установлен в 1 — шлюз будет посылать данные мастеру, когда он сброшен в ноль — шлюз будет читать данные от мастера. И, наконец, второй бит регистра I2C_flags сообщает о том, что мы читаем — данные или Ack (чтобы знать сколько бит нам с шины читать — 8 или 1).

Читайте также:  Безопасное обращение с электричеством

Наша прога делает следующее. Сначала мы инициализируем шлюз для чтения байта, флаг T устанавливаем равным 1, настраиваем прерывание от Pin_Change, разрешаем прерывания и переходим к циклической проверке обоих линий. Если на обоих линиях высокий уровень, то разрешаем прерывание от линии Data, если нет — запрещаем прерывание от любой линии.

Таким образом первое прерывание у нас в любом случае должно произойти от изменения уровня на линии Data с высокого уровня на низкий.

Далее, в прерывании мы первоначально попадём в обработчик старт-условия, там мы разрешаем прерывание от Clock, настраиваемся на приём от мастера первого байта, выставляем нужные флаги и переходим к процедуре ожидания (снова устанавливаем глобальный флаг разрешения прерываний и нифига не делаем).

В протоколе определено время фиксации старт-условия, оно зависит от скорости, но главное, что оно есть и в течении этого времени нельзя менять уровни на линиях Clock и Data. За это время мы должны успеть выполнить весь обработчик start-условия и снова разрешить прерывания.

Далее, при прерывании мы (с помощью флага T) определяем от какой линии произошло прерывание и, соответственно, на какой стадии обмена мы находимся.

Если помните описание протокола I2C — во время высокого уровня на линии clock приёмник читает данные, во время низкого уровня на линии clock — передатчик выставляет данные на шину, соответственно, когда мы определяем, что уровень на линии clock изменился с 1 на 0 — мы захватываем линию clock (сами роняем её в ноль), запрещаем прерывание от изменения уровня на линии Data и занимаемся своими делами, после чего отпускаем линию clock и ждём прерывания от её изменения. Пока clock не изменится с 0 на 1 — снова разрешать прерывания от линии Data нельзя, поскольку уровень на линии Data при низком уровне на линии clock может в любой момент измениться (в это время передатчик выставляет данные на шину). Когда мы определяем, что уровень на линии clock изменился с 0 на 1 — мы сначала делаем все свои дела (читаем если нужно байт или сигнал Ack), а потом снова разрешаем прерывание от линии Data (благо посылать старт- и стоп-условие запрещено сразу после изменения уровня на линии Clock, так что некоторый запас времени, на то, чтобы позаниматься своими делами, не рискуя пропустить старт или стоп условие, у нас есть). Ну вот, дальше смотрим алгоритм и прогу, в случае необходимости, — пишем вопросы на форум.

Алгоритм:

Итак, в аппаратной части мы имеем:

PB0 — линия Clock

PB2 — линия Data

PD5 — линия CS

PD0 — линия Rx

PD1 — линия Tx

Программа:

;——————————————————— .device ATtiny2313 .include «tn2313def.inc» .list ;— определяем свои переменные .def w=r16 ; это будет наш аккумулятор .def Bit_counter=r17 ; счётчик бит .def I2C_flags=r18 ; флаги I2C ;— флаг 0 — признак, что только что было старт-условие ;— флаг 1 — направление (приём: 0, передача: 1) ;— флаг 2 — признак чтения ack .def BTS=r19 ; байт для передачи .def RDB=r20 ; принятый байт .def Hi_PCIE=r21 ; сюда запишем GIMSK с поднятым PCIE .def Clr_reg=r22 ; здесь будет просто ноль .def PCMSK_D_Set=r23 ; тут PCMSK c установленным флагом ; для прерывания от линии Data .def PCMSK_C_Set=r24 ; тут PCMSK c установленным флагом ; для прерывания от линии Clock .def PCMSK_CD_Set=r25; тут PCMSK c флагами для ; прерываний от линий Data и Clock ;— определяем константы (и даём им имена) .equ Clock=0 ; PortB0/PinB0 — clock .equ Data=2 ; PortB2/PinB2 — data .equ CS=5 ; PinD5 — вход Chip Select ; кроме того, мы используем линии Rx (PD0), Tx (PD1) ;— начало программного кода .cseg .org 0 rjmp Init ; переход на начало программы (вектор сброса) ;— дальше идут вектора прерываний ;— если не используем — пишем reti, иначе — переход к обработчику reti ; внешнее прерывание INT0 reti ; внешнее прерывание INT1 reti ; Input capture interrupt 1 reti ; Timer/Counter1 Compare Match A reti ; Overflow1 Interrupt reti ; Overflow0 Interrupt reti ; USART0 RX Complete Interrupt reti ; USART0 Data Register Empty Interrupt reti ; USART0 TX Complete Interrupt reti ; Analog Comparator Interrupt rjmp PCInt ; Pin Change Interrupt reti ; Timer/Counter1 Compare Match B reti ; Timer/Counter0 Compare Match A reti ; Timer/Counter0 Compare Match B reti ; USI start interrupt reti ; USI overflow interrupt reti ; EEPROM write complete reti ; Watchdog Timer Interrupt ;— начало программы — Init: ldi w,RAMEND ; устанавливаем указатель вершины out SPL,w ; стека на старший байт RAM sbi ACSR,ACD ; выключаем компаратор ;— инициализируем порты ser w ; w=0xFF out DDRA,w ; настраиваем порт A. все линии на выход clr w ; w=0x00 out PORTA,w ; на всех линиях ноль ldi w,0b11111010 ; настраиваем порт B. out DDRB,w ; PB0, PB2 — входы, остальные — выходы clr w ; определяем начальное состояние out PORTB,w ; (выходы — нули, подтяжек нет) ldi w,0b11010100 ; настраиваем порт D out DDRD,w ; PD0,1,3,5 — входы, остальные — выходы clr w ; определяем начальное состояние out PORTD,w ; (выходы — нули, подтяжек нет) ;— инициализируем UART out UBRRH,w ; UBRRR для кварца 20МГц и скорости 115200 ldi w,10 ; равен 10, т.е. UBRRH=0, UBRRL=10 out UBRRL,w ldi w,0b00001110 ; поднимаем биты USBS, UCSZ1:0 out UCSRC,w ; формат: 1 старт, 8 данные, 2 стоп sbi UCSRB,RXEN ; включить приёмник in w,UDR ; считать из него мусор sbi UCSRB,TXEN ; включить передатчик ;— инициализируем вспомогательные регистры clr Clr_reg ldi Hi_PCIE,0b00100000 ldi PCMSK_D_Set,0b00000100 ldi PCMSK_C_Set,0b00000001 ldi PCMSK_CD_Set,0b00000101 ;— включить прерывание от pin change out GIMSK,Hi_PCIE ;— Для реинициализации — Reset: out PCMSK,Clr_reg; выключить прерывания от clock и data ldi w,0x02 ; сообщаем, что был reset out UDR,w ;— проверяем флаги от прерываний in w,EIFR ; читаем регистр sbrc w,5 ; пропустить команду, если PCIF=0 out EIFR,Hi_PCIE ; сбрасываем PCIF, если он установлен ;— cbi DDRB,Data ; отпускаем Data (=1) set ; инициализируем флаг T cbi DDRB,Clock ; отпускаем Clock (=1) ;— разрешаем глобальные прерывания sei ;— если обе линии свободны — разрешаем прерывание от Data — Wait_start: in w,PINB ; читаем входы PINB com w ; инвертируем andi w,0b00000101; если инверсные clock и data=0 — результат 0 breq Free_bus ; если флаг Z=1, то прыгать Not_free_bus: out PCMSK,Clr_reg; выключить прерывания от всех линий rjmp Wait_start Free_bus: out PCMSK,PCMSK_D_Set; включить прерывание от линии Data rjmp Wait_start ;—————————— ;— циклы ожидания после выполнения программы в C01 и C10 Wait_C: pop w ; выгружаем из стека адрес возврата pop w sei Wait: rjmp Wait ;——————————————- ;— Обработчик прерывания от pin change — PCInt: sbis PINB,Clock ; если clock=1 — пропустить команду rjmp Clock_Low ;——————————————- ;— Если на линии Clock высокий уровень — Clock_Hi: brts C1_no_changes ; если флаг T=1, то прыгаем ;——————————————— ;— Уровень на линии clock изменился с 0 на 1 C01: set ; сохраняем новое состояние линии clock sbrc I2C_flags,1;если флаг 1=0 — пропускаем 1 команду rjmp C01_Exit C01_Read: sbrc I2C_flags,2;если флаг 2=0 — пропускаем 1 команду rjmp C01_Read_Ack C01_Read_Byte: lsl RDB ; сдвиг влево sbic PINB,Data ; если Data=0 — пропускаем 1 команду sbr RDB,0b00000001 ; поднять нулевой бит dec Bit_counter brne C01_Exit ; если не считали 8 бит — просто выходим, out UDR,RDB ; если считали — шлём их на комп и выходим C01_Exit: out PCMSK,PCMSK_CD_Set; включить прерыв. от Data и Clock rjmp Wait_C ;———————- C01_Read_Ack: sbic PINB,Data ; если Data=0, пропускаем след-ю команду rjmp C01_Read_Ack_NotOk C01_Read_Ack_Ok: ldi w,0x23 ; говорим компу, что на линии есть Ack out UDR,w rjmp C01_Exit C01_Read_Ack_NotOk: ldi w,0x22 ; говорим компу, что на линии нет Ack out UDR,w rjmp C01_Exit ;————————————— ;— Уровень на линии clock не изменился C1_no_changes: ; линия clock=1 и прерывание не от неё ;— значит это старт или стоп sbic PINB,Data ; если data=0 — пропустить команду rjmp Stop_uslovie Start_uslovie: ldi Bit_Counter,8; один пакет = 8 бит от передатчика out PCMSK,PCMSK_CD_Set ; добавляем прерывание от Clock ldi w,0x20 ; сообщим, что получили start-условие out UDR,w ldi I2C_flags,0b00000001 ; чтение/было старт-условие rjmp Wait_C Stop_uslovie: ldi w,0x21 ; сообщаем компу что получили stop-усл. out UDR,w pop w ; выгружаем адрес возврата из стека pop w rjmp Reset ;————————————— ;— Если на линии Clock низкий уровень Clock_Low: brts C10 ; если флаг T=1, то прыгаем ;————————————— ;— Уровень на линии clock не изменился C0_no_changes: ; теоретически такого не должно произойти, ; поскольку мы выключаем прерывания от Data ; при переключении Clock 1->0 ldi w,0xFF ; сообщаем компу об ошибке out UDR,w pop w ; выгружаем адрес возврата из стека pop w rjmp Reset ; реинициализация ;——————————————— ;— Уровень на линии clock изменился с 1 на 0 C10: sbi DDRB,Clock ; зажимаем clock (чтоб всё успеть) cbi DDRB,Data ; отпускаем Data (=1) clt ; записываем новое состояние clock out PCMSK,PCMSK_C_Set ; убираем прерывание от Data in w,EIFR ; читаем регистр sbrc w,5 ; пропустить команду, если PCIF=0 out EIFR,Hi_PCIE; сбрасываем PCIF ;— проверяем — читаем или пишем? — sbrs I2C_flags,1;если флаг 1=1 — пропускаем rjmp C10_Read ;— Пишем — C10_Write: tst Bit_counter ; если записали 8 бит, ; то установится флаг Z brne C10_Write_Next ; если нет — выходим, иначе: C10_End_Write: ldi I2C_flags,0b00000100 ; чтение ack rjmp C10_Exit C10_Write_Next: lsr BTS sbrs BTS,0 ; если бит 0 в BTS=1 — проп. 1 команду sbi DDRB,Data ; Data=0 dec Bit_counter ; уменьшаем счётчик C10_Exit: cbi DDRB,Clock ; отпускаем clock rjmp Wait_C ;— Читаем — C10_Read: sbrs I2C_flags,2; если читали ack — пропускаем 1 команду rjmp C10_Read_Byte ;— стоит режим чтения Ack (значит мы его только что ;— прочли и ждём команды от компа что делать дальше) C10_Ready: sbis UCSRA,UDRE ; если буфер передатч. пуст — пропуск.1 команду rjmp C10_Ready ; дожидаемся, пока предыдущее сообщение уйдёт ldi w,0x24 ; сообщаем компу, что готовы принимать команды out UDR,w Wait_Comp_Answer: sbis UCSRA,RXC ; если пришли данные от компа — пропуск.1 команду rjmp Wait_Comp_Answer in w,UDR ; читаем — что пришло от компа cpi w,0x20 breq Com_Send_Byte ; переходим к команде «послать байт» cpi w,0x21 breq Com_Read_Byte ; переходим к команде «считать байт» cpi w,0x22 breq Com_NoAck ; переходим к команде «не посылать Ack» cpi w,0x23 breq Com_Ack ; переходим к команде «послать Ack» cpi w,0x24 breq Com_PIND_Status ; переходим к команде «PIND Status?» ;— если пришла какая-то другая команда — сообщ.компу и ресетимся ldi w,0xFF out UDR,w Exit_Reset: pop w pop w rjmp Reset ;— Выполнение разных команд — ;— готовимся писать байт Com_Send_Byte: ldi I2C_flags,0b00000010 ; направление — передача ldi Bit_Counter,7 Wait_BTS: sbis UCSRA,RXC ; если есть данные от компа — пропускаем 1 команду rjmp Wait_BTS in BTS,UDR ; читаем байт для передачи ;— посылаем первый бит cbi DDRB,Data ; Data=1 sbrs BTS,0 ; если бит 0 в BTS=1 — пропускаем команду sbi DDRB,Data ; Data=0 ;— и выходим rjmp C10_Exit ;— готовимся читать байт Com_Read_Byte: ldi Bit_Counter,8 ldi I2C_flags,0b00000000 ; направление — чтение rjmp C10_Exit ;— шлём в шину NoAck Com_NoAck: sbrc I2C_flags,0; если приняли первый байт после старта rjmp Exit_Reset ; выходим до нового start-условия ldi I2C_flags,0b00000100 ; направление — чтение/читаем Ack rjmp C10_Exit ;— шлём в шину Ack Com_Ack: sbi DDRB,Data ; Data=0 (Ack) ldi I2C_flags,0b00000100 ; направление — чтение/читаем Ack rjmp C10_Exit ;— шлём на комп состояние входов Com_PIND_Status: in w,PIND ; читаем входы порта D out UDR,w ; шлём на комп rjmp C10_Ready ;— Не стоит режим чтения ack (значит мы читаем байт) — C10_Read_Byte: tst Bit_counter ; если прочитали 8 бит — установится флаг Z brne C10_Exit ; если нет — выходим, иначе: rjmp C10_Ready ;———————————————————

Для правильной работы шлюза в контроллере должны быть «запрограммированы» следующие фьюзы: SPIEN, SUT0

Скачать готовую прошивку и asm-файл

Читайте также:  Домашний эталон переменного тока

Небольшой пример работы этой проги.

Пусть у нас есть мастер, который хочет считать байт по адресу 12h из микросхемы памяти 24С02, у которой адресные пины A0, A1, A2 подключены на общий провод (т.е. её 7-ми битный адрес равен 1010000), а мы хотим этой самой микрухой прикинуться и сказать мастеру, что по этому адресу у нас записан байт AAh.

Открываем даташит и смотрим как с этой микросхемой памяти общаться (то есть смотрим — что мы будем получать от мастера и как должны ему отвечать).

В даташите написано, что для чтения по произвольному адресу мастер должен сначала, после подачи старт-условия, адресовать нас для записи, передать адрес, потом послать повторное старт-условие, адресовать нас для чтения и потом уже прочитать байт.

Итак, заходим в терминалку, выбираем порт и подключаемся на скорости 115200. Описанный выше сценарий будет выглядеть в терминалке следующим образом:
(принимаемые от шлюза данные: ):

Источник: http://meandr.org/archives/10300

Сниффер/эмулятор I2C и 1-wire

Этеншн!
Зачастую, при отладке устройств, возникает необходимость проверить корректность обмена данными между модулями. В самых простых случаях, для того, чтобы найти багу, достаточно просто определить проходит обмен или нет. На это сгодится и мультиметр. Но чаще всего приходится разбираться, на каком этапе обмена произошёл сбой.

Сорвалась-ли передача ещё на этапе подготовки данных или, может, обмену помешало другое устройство, висящее на линии. Ситуация становится особенно запутанной, когда обмен данными реализован, по большей части, программно. Тут мультиметр уже не поможет. И вот, дабы упростить/ускорить процесс отладки, я решил сделать i2c сниффер.

Первоначально задача была такая: прослушивать I2C линию и отправлять лог в компьютер. Когда это было реализовано, выяснилось, что в Tiny2313 осталось еще полно свободного флеша. Поэтому был придуман дополнительный функционал. Вот, что в итоге получилось:Вид у него не самый гламурный, да в этом и не было необходимости. — Обмен данными с компьютером через UART.

Сейчас подключается к COM порту, что не очень удобно (приходится отдельно подрубать питание). Во второй версии сделаю подключение по USB на базе FT232. — В режиме i2c сниффера уверенно работает при скорости обмена (частоте SCL) до 50кГц. В этом режиме он записывает всю активность на линии в лог, который в фоновом режиме выкидывается на комп.

Вместе с каждой записью в лог пишется время. Первым делом я расскажу про то, как устроен i2c сниффер, ибо это тот функционал, ради которого задумывалось устройство. Сниффер я опишу чуть подробнее, чем остальные функции. Он реализован на базе USI, и будет ещё одним примером использования этой приблуды (по другому USI не назовёшь). Потом я расскажу про мастер-режим.

i2c мастер тоже реализован на USI. 1-wire полностью программный, и ничего особо интересного из себя не представляет.

Но сначала, общий экскурс:

За питание отвечает преобразователь на 78L05. Или, как я уже сказал, можно подрубить 5В с отлаживаемого устройства. Вообще, это конечно неудобно. В следующей версии будет USB. На питании стоят защитные диоды, поэтому спалить девайс проблематично. На связи у нас max232.

Моя разводка может показаться слишком мелкой (so16 и 0805 кондеры почти влотную к нему), но по-другому оно туда не влезало. Кварц 20МГц. Можно было взять и меньше, например на 16. Высокая скорость необходима для быстрой работы конечного автомата i2c сниффера. Корпус кварца я заземлил, так, на «всякий пожарный». ATTiny2313 правит бал.

Во-первых это один из немногих обладателей USI. Во-вторых он может разгонятся до 20МГц. Разъём для программирования я не вывел, поэтому придётся подпаивать проводки. На линиях SDA и SCL (это PB5 и PB7, соответственно) есть подтягивающие резисторы по 4.7к.

Они подключены к ножке PB6, которая, по команде с компа подключается к питанию, обеспечивая внутреннюю подтяжку. Ещё есть места для четырёх светодиодов, которые, в итоге не пригодились.
Крупнее i2c сниффер можно было реализовать полностью программно, но на USI это намного удобнее.

Главным образом потому, что USI имеет встроенный Start condition detector, да ещё и с отдельным прерыванием. Вот только проблема в том, что USI сам-по себе бесполезный кусок конечного автомата, и часть логики придется реализовать программно.

С одной стороны это не удобно, а с другой — есть возможность замутить, например, сниффер, который на обычном TWI сделать невозможно. По логике протокола i2c обмен данными, при передаче байта, проходит в двух направлениях. Если мы передаём байт, то нужно передать 8 бит «туда», и прочитать 1 бит «оттуда». Если читаем, то наоборот.

В случае-же сниффера, не существует «туда» и «оттуда». Есть только одно направление — «мимо». Это несколько облегчает задачу. Нам нужно всего-навсего слушать линию и складывать данные в буфер. Из этого буфера они будут передаваться на компьютер. Вся движуха на линии делится на четыре типа:

0x1 — Старт детектед

0x2 — Стоп детектед
0x4 — Байт + ACK
0xC — Байт + NACK Запись для каждого события занимает 4 байта. Первый (Старший) байт — это код события (те-самые 0x1,0x2…). Во втором данные. Для первых двух событий данные не нужны, тогда второй байт = 0. Последние два байта — значение таймера. Он запускается, как только будет пойман первый start-condition, и сбрасывается по команде с компьютера. Период одного «тика» таймера — 1мс. Он может считать чуть больше минуты, этого более чем достаточно для отлова всяких повторов и других неведомых вещей, которые иногда творятся на линии.Если бы мы решили ловить Start condition программными средствами, то пришлось-бы заводить ножку SDA на прерывания, и уже там определять старт это, или просто SDA переключилась. А при помощи USI такая задачка решается просто: включаем прерывание USI START и ждём… Вот так выглядит обработчик этого прерывания:procedure USI_Start; org 0xF; begin asm //Очищаем флаг, а счётчик = 15. in r16, USISR andi r16, %11110000 ori r16, %10001111 out USISR, r16 end; USI_recv_state := 2; //Пускаем таймер if TCCR0B=0 then begin Timer := 0; TCNT0 := 0; PSR10_bit := 1; TCCR0B := 4; //Предделитель 256 end; //Запихиваем данные в буфер push_to_buffer(f_start, 0); end; Первым делом мы сбрасываем флаг USISIF. Это нужно сделать как можно быстрее, ибо, пока флаг поднят, USI будет зажимать линию SCL. Затем мы запихиваем в счётчик USICNT 0x0F, и пишем в переменную USI_recv_state 2. Это подготовка к приёму данных (Знаю, сейчас похоже на черную магию, но потом станет понятнее). Проверяем, если таймер ещё не запущен, то сбрасываем его и запускаем. Для опредения stop-condition нам предоставили почти тоже самое, что и для start. Только прерывание пожадничали. Поэтому пришлось добавить в цикл программы проверку флага USIPF. if USIPF_bit=1 then begin USIPF_bit := 1; push_to_buffer(f_stop, 0); end; Тут, я думаю, ничего нового нету. Сбрасываем флаг (для этого в него нужно записать единичку) и запихиваем в буфер сообщение о том, что поймали стоп. Самое интересное — поймать данные. Целых 9 бит. USI у нас настроен так: USICS1 = 1; USICS0 = 0; USICLK = 0 — это значит, что при каждом положительном фронте на SCL, регистр данных USIDR будет сдвигаться, и в него будет записываться бит с линии SDA. А счётчик USICNT будет тикать на каждый фронт SCL. А вот и чёрная магия:При старте мы загружаем в USI_recv_state значение 2, а в счётчик (USICNT) — 0x0F. Таким образом переполнение счётчика (и прерывание USI) произойдёт, как только линия SCL упадёт в 0. В прерывании (Переполнение счётчика) мы проверяем USI_recv_state — определяем на каком этапе приёма мы сейчас находимся. Если USI_recv_state = 2, то нужно подготовится к приёму данных. Очищаем счётчик, чтобы он мог протикать все 16 тактов. И не забываем обновить значение USI_recv_state (теперь записываем 0), чтобы в следующий раз корректно обработать прерывание. Потом, в течении 16 тактов счётчика (по одному такту на каждый перепад линии SCL) USI работает автоматически, не отвлекая программу по каждому пустяку. При этом, на каждый положительный фронт SCL, бит с шины проталкивается в регистр USIDR. Таким образом, к тому моменту, как случится прерывание, в регистре уже соберётся весь байт. Если USI_recv_state = 0, то можно забирать данные (пока-что во временную переменную), и готовится к чтению девятого бита (ACK). Счётчик переполнился на заднем фронте восьмого импульса SCL, а ACK можно читать только на переднем фронте следующего импульса. Поэтому нужно протупить ещё один такт счётчика — записываем 0x0F. Ну, а в USI_recv_state записываем 1. Если USI_recv_state = 1, значит можно читать ACK и загонять данные в буфер. А вот следующий фронт нам придётся пропустить. Для этого загоняем в счётчик 0x0F, а в USI_recv_state число 2. Потом, если по линии побегут ещё данные, цикл повторится сначала. Отправка данных в компьютер тоже автоматизирована. Как только в буфер попадают данные, запускается конечный автомат на прерывании UDRE (UART Data Register Empty). Как только на линии происходит какое-то событие, в буфер добавляются данные и сдвигается указатель, по которому происходит запись. Параллельно с этим данные из буфера отправляются в UART.У мастера есть две основные функции — чтения данных из слейва и запись в него. Отладчик в мастер-режиме не следит за арбитражем. То есть предполагается, что на линии только один мастер. Обмен данными с отладчиком в этом режиме происходит по такой схеме:

1) Посылаем команду 0x31 — переход в мастер режим.

2) Посылаем 0x34. Эта команда говорит отладчику, что сейчас в UART прилетит куча данных — список действий, который отладчик должен выполнить.
3) Сразу за командой 0x34, посылаем размер (в байтах) этого списка действий. 4) Посылаем весь список.

5) Посылаем команду 0x35 — выполнить список.

После этого отладчик начинает последовательно выполнять команды из списка. На место выполненной команды записывается отчёт.

То есть, после выполнения команды «Передать байт 0x38», на её место запишется, например «Передан байт 0x38, получен NACK». И команда, и отчёт занимают два байта.

Логика здесь такая-же, как и в режиме сниффера: первый байт — код, второй — данные. Команды для i2c мастер-режима могут быть такие:

0x05 — Старт (Или повстарт)

0x02 — Стоп
0x07 — Записать байт. (Во втором байте — данные, которые нужно записать)
0x10 — Прочитать байт, передать ACK
0x11 — Прочитать байт, передать NACK Коды отчётов:

0x05 — Передан start-condition

0x02 — Передан stop-condition
0x07 — Передали байт, нам ответили ACK
0x08 — Передали байт, в ответ — NACK
0x10 — Прочитали байт, сказали ACK
0x11 — Прочитали байт, сказали NACK После того, как все команды будут выполнены и на их место будет записан отчёт, список отправляется обратно в компьютер. Когда весь список будет отправлен, устройство переходит в мастер режим. Можно опять загонять команду 0x34 и новый список, или перевести отладчик в другой режим. Этот режим, практически, является частью i2c мастера. Точнее, есть просто «Мастер-режим», в котором устройство выполняет команды из списка. Мы можем загнать в этот список команды для работы с i2c или 1-Wire, логика работы, при этом, не меняется. Для работы с 1-Wire есть 5 команд:

0x01 — Послать RESET импульс, и прочитать PRESENSE.

0x03 — Прочитать байт
0x06 — Передать байт
0x12 — Подключить дополнительное питание на линию Dq
0x13 — Отключить дополнительное питание. После выполнения списка, отладчик может выдать вот такие коды:

0x01 — Передали RESET, поймали PRESENSE импульс.

0x04 — Передали RESET, но PRESENSE не было.
0x06 — Байт прочитан
0x09 — Байт передан
0x12 — Дополнительное питание подключено
0x13 — Дополнительное питание отключено Если 1-Wire устройство работает от паразитного питания, то для выполнения некоторых операций ему понадобится дополнительная подпитка. Как раз для этих целей существуют команды 0x12 и 0x13. Первая подключает ножку Dq к питанию, а вторая — переводит в режим Hi-Z. Хотя, команда отключения питания почти не используется, т.к. оно отключается само, как только начнёт выполняться любая другая команда.

Архив с прошивкой и схемой

Архив с управляющей программой

Источник: http://we.easyelectronics.ru/AVR/sniffer-emulyator-i2c-i-1-wire.html

Ссылка на основную публикацию