сайт для палких паяльників

I2C Шина (TWI)

I2C – последовательная шина данных для связи интегральных схем, использует две двунаправленные линии связи (SDA и SCL). Используется для соединения низкоскоростных периферийных компонентов. Название является аббревиатурой слов Inter-Integrated Circuit. TWI (Two Wire Interface) или TWSI (Two Wire Serial Interface) по сути та же шина I2C, но использует другое название с лицензионных причин. I2C использует две двунаправленные линии, подтянутые к напряжению питания и управляемые через открытый коллектор или открытый сток – последовательная линия данных (SDA, англ. Serial DAta) и последовательная линия тактирования (SCL, англ. Serial CLock). Стандартные напряжения питания +5 В или +3,3 В.

I2C

Классическая адресация включает 7-битный адресное пространство с 16 зарезервированными адресами. То есть 112 свободных адресов для подключения периферии на одну шину. Основной режим работы – 100 Кбит/с; 10 Кбит/с в режиме с пониженной скоростью. Стандарт допускает приостановление тактирования при работе с медленными устройствами.

После пересмотра стандарта в 1992 году стало возможным подключение еще большего количества устройств на одну шину (за счет 10-битной адресации), а также увеличилась скорость до 400 Кбит/с в скоростном режиме. Соответственно, доступное количество свободных узлов возросло до 1008. Максимальная допустимое количество микросхем, подключенных к одной шине, ограничивается максимальной емкостью шины в 400 пФ. Версия стандарта 2.0 1998 представила высокоскоростной режим работы со скоростью до 3,4 Мбит/с с пониженным энергопотреблением. Версия 2.1 2001 внесла лишь незначительные доработки.

I2C_data_transfer

Послідовність передачі даних

Состояние СТАРТ и СТОП

Процедура обмена начинается с того, что ведущий формирует состояние СТАРТ: генерирует переход сигнала линии SDA из ВЫСОКОГО состояния в НИЗКОЕ при ВЫСОКОМ уровне на линии SCL. Этот переход воспринимается всеми устройствами, подключенными к шине, как признак начала процедуры обмена. Генерация синхросигнала — это всегда обязанность ведущего; каждый ведущий генерирует свой собственный сигнал синхронизации при пересылке данных по шине. Процедура обмена завершается тем, что ведущий формирует состояние СТОП — переход состояния линии SDA из низкого состояния в ВЫСОКОЕ при ВЫСОКОМ состоянии линии SCL. Состояния СТАРТ и СТОП всегда вырабатываются ведущим. Считается, что шина занята после фиксации состояния СТАРТ. Шина считается освободившейся через некоторое время после фиксации состояния СТОП. При передаче посылок по шине I2C каждый ведущий генерирует свой синхросигнал на линии SCL. После формирования состояния СТАРТ, ведущий опускает состояние линии SCL в НИЗКОЕ состояние и выставляет на линию SDA старший бит первого байта сообщения. Количество байт в сообщении не ограничено. Спецификация шины I2C разрешает изменения на линии SDA только при НИЗКОМ уровне сигнала на линии SCL. Данные действительны и должны оставаться стабильными только во время ВЫСОКОГО состояния синхроимпульса. Для подтверждения приема байта от ведущего-передатчика ведомым-приемником в спецификации протокола обмена по шине I2C вводится специальный бит подтверждения, выставляемый на шину SDA после приема 8 бита данных.

Подтверждение

Таким образом передача 8 бит данных от передатчика к приемнику завершаются дополнительным циклом (формированием 9-го тактового импульса линии SCL), при котором приемник выставляет низкий уровень сигнала на линии SDA, как признак успешного приема байта. Подтверждение при передаче данных обязательно, кроме случаев окончания передачи ведомой стороной. Соответствующий импульс синхронизации генерируется ведущим. Передатчик отпускает (ВЫСОКОЕ) линию SDA на время синхроимпульса подтверждения. Приёмник должен удерживать линию SDA в течение ВЫСОКОГО состояния синхроимпульса подтверждения в стабильном НИЗКОМ состоянии. В том случае, когда ведомый-приёмник не может подтвердить свой адрес (например, когда он выполняет в данный момент какие-либо функции реального времени), линия данных должна быть оставлена в ВЫСОКОМ состоянии. После этого ведущий может выдать сигнал СТОП для прерывания пересылки данных. Если в пересылке участвует ведущий-приёмник, то он должен сообщить об окончании передачи ведомому-передатчику путем не подтверждения последнего байта. Ведомый-передатчик должен освободить линию данных для того, чтобы позволить ведущему выдать сигнал СТОП или повторить сигнал СТАРТ.

Синхронизация

Синхронизация выполняется с использованием подключения к линии SCL по правилу монтажного И. Это означает, что ведущий не имеет монопольного права на управление переходом линии SCL из НИЗКОГО состояния в ВЫСОКОЕ. В том случае, когда ведомому необходимо дополнительное время на обработку принятого бита, он имеет возможность удерживать линию SCL в низком состоянии до момента готовности к приему следующего бита. Таким образом, линия SCL будет находиться в НИЗКОМ состоянии на протяжении самого длинного НИЗКОГО периода синхросигналов. Устройства с более коротким НИЗКИМ периодом будут входить в состояние ожидания на время, пока не кончится длинный период. Когда у всех задействованных устройств кончится НИЗКИЙ период синхросигнала, линия SCL перейдет в ВЫСОКОЕ состояние. Все устройства начнут проходить ВЫСОКИЙ период своих синхросигналов. Первое устройство, у которого кончится этот период, снова установит линию SCL в НИЗКОЕ состояние. Таким образом, НИЗКИЙ период синхролинии SCL определяется наидлиннейшим периодом синхронизации из всех задействованных устройств, а ВЫСОКИЙ период определяется самым коротким периодом синхронизации устройств. Механизм синхронизации может быть использован приемниками как средство управления пересылкой данных на байтовом и битовом уровнях. На уровне байта, если устройство может принимать байты данных с большой скоростью, но требует определенное время для сохранения принятого байта или подготовки к приему следующего, то оно может удерживать линию SCL в НИЗКОМ состоянии после приема и подтверждения байта, переводя таким образом передатчик в состояние ожидания. На уровне битов, устройство, такое как микроконтроллер без встроенных аппаратных цепей I2C или с ограниченными цепями, может замедлить частоту синхроимпульсов путем продления их НИЗКОГО периода. Таким образом скорость передачи любого ведущего адаптируется к скорости медленного устройства.

Адресация в шине I2C

Каждое устройство, подключённое к шине, может быть программно адресовано по уникальному адресу. Для выбора приемника сообщения ведущий использует уникальную адресную компоненту в формате посылки. При использовании однотипных устройств, ИС часто имеют дополнительный селектор адреса, который может быть реализован как в виде дополнительных цифровых входов селектора адреса, так и в виде аналогового входа. При этом адреса таких однотипных устройств оказываются разнесены в адресном пространстве устройств, подключенных к шине. В обычном режиме используется 7-битная адресация. Процедура адресации на шине I2C заключается в том, что первый байт после сигнала СТАРТ определяет, какой ведомый адресуется ведущим для проведения цикла обмена. Исключение составляет адрес «Общего вызова», который адресует все устройства на шине. Когда используется этот адрес, все устройства в теории должны послать сигнал подтверждения. Однако, устройства, которые могут обрабатывать «общий вызов», на практике встречаются редко. Первые семь битов первого байта образуют адрес ведомого. Восьмой, младший бит, определяет направление пересылки данных. «Ноль» означает, что ведущий будет записывать информацию в выбранного ведомого. «Единица» означает, что ведущий будет считывать информацию из ведомого. После того, как адрес послан, каждое устройство в системе сравнивает первые семь бит после сигнала СТАРТ со своим адресом. При совпадении устройство полагает себя выбранным как ведомый-приёмник или как ведомый-передатчик, в зависимости от бита направления. Адрес ведомого может состоять из фиксированной и программируемой части. Часто случается, что в системе будет несколько однотипных устройств (к примеру ИМС памяти, или драйверов светодиодных индикаторов), поэтому при помощи программируемой части адреса становится возможным подключить к шине максимально возможное количество таких устройств. Все специализированные ИМС, поддерживающие работу в стандарте шины I2C, имеют набор фиксированных адресов, перечень которых указан производителем в описаниях контроллеров. Комбинация бит 11110ХХ адреса зарезервирована для 10-битной адресации. Как следует из спецификации шины, допускаются как простые форматы обмена, так и комбинированные, когда в промежутке от состояния СТАРТ до состояния СТОП ведущий и ведомый могут выступать и как приемник, и как передатчик данных. Комбинированные форматы могут быть использованы, например, для управления последовательной памятью. Во время первого байта данных можно передавать адрес в памяти, который записывается во внутренний регистр-защелку. После повторения сигнала СТАРТа и адреса ведомого выдаются данные из памяти. Все решения об авто-инкременте или декременте адреса, к которому произошел предыдущий доступ, принимаются конструктором конкретного устройства. Поэтому, в любом случае лучший способ избежать неконтролируемой ситуации на шине перед использованием новой (или ранее не используемой) ИМС следует тщательно изучить ее описание (datasheet или reference manual), получив его с сайта производителя.

Возможные проблемы

На сегодняшний момент наиболее популярная скорость использования I2C – 100 Кбит/с и 400 Кбит/с. Однако, надо понимать, что использование на одной шине нескольких устройств, имеющих различные реализации протокола, и работают на разных скорости может привести к непредвиденным проблемам. Чаще всего для обеспечения стабильной работы приходится ограничивать скорость шины до скорости самого медленного устройства. Некоторые устройства, работающие в режиме MASTER не поддерживают приостановление тактирования для медленных устройств (clock stretching). В результате чего возникают ошибки при работе. В этом случае приходится значительно уменьшать скорость шины или, если есть такая возможность, разносить быстрые и медленные устройства на разные шины.

Пример реализации I2C Slave на AVR микроконтроллере Atmega8

#include <avr/io.h>
#include <compat/twi.h>
#include <avr/interrupt.h>

#define I2CSLAVE_ADDR		0x4E

#define PORT_DDR			0xB0 // PORTB Settings
#define PORT_IN				0xB1 // Get PINB
#define PORT_OUT			0xB2 // Set PORTB

unsigned char regaddr; // Store the Requested Register Address
unsigned char regdata; // Store the Register Address Data

void i2c_slave_action(unsigned char rw_status)
{
	switch(regaddr) {
		// PORT
		case PORT_DDR:
			if (rw_status == 0)
				// read
				regdata = DDRB;
			else
				// write
				DDRB = regdata;
			break;

		case PORT_IN:
			if (rw_status == 0)
				// read
				regdata = PINB;
			break;

		case PORT_OUT:
			if (rw_status == 1)
				// write
				PORTB = regdata;
			break;
	}
}

ISR(TWI_vect)
{
	static unsigned char i2c_state;
	unsigned char twi_status;

	// Disable Global Interrupt
	cli();

	// Get TWI Status Register, mask the prescaler bits (TWPS1,TWPS0)
	twi_status=TWSR & 0xF8;     

	switch(twi_status) {
		case TW_SR_SLA_ACK:	// 0x60: SLA+W received, ACK returned
			i2c_state=0;	// Start I2C State for Register Address required
			break;

		case TW_SR_DATA_ACK:	// 0x80: data received, ACK returned
			if (i2c_state == 0) {
				regaddr = TWDR;	// Save data to the register address
				i2c_state = 1;
			} else {
				regdata = TWDR;	// Save to the register data
				i2c_state = 2;
			}
			break;

		case TW_SR_STOP:	// 0xA0: stop or repeated start condition received while selected
			if (i2c_state == 2) {
				i2c_slave_action(1);	// Call Write I2C Action (rw_status = 1)
				i2c_state = 0;		// Reset I2C State
			}
			break;

		case TW_ST_SLA_ACK:	// 0xA8: SLA+R received, ACK returned
		case TW_ST_DATA_ACK:	// 0xB8: data transmitted, ACK received
			if (i2c_state == 1) {
				i2c_slave_action(0);	// Call Read I2C Action (rw_status = 0)
				TWDR = regdata;		// Store data in TWDR register
				i2c_state = 0;		// Reset I2C State
			}
			break;

		case TW_ST_DATA_NACK:	// 0xC0: data transmitted, NACK received
		case TW_ST_LAST_DATA:	// 0xC8: last data byte transmitted, ACK received
		case TW_BUS_ERROR:	// 0x00: illegal start or stop condition
		default:
			i2c_state = 0;	// Back to the Begining State
	}
	// Clear TWINT Flag
	TWCR |= (1<<TWINT);
	// Enable Global Interrupt
	sei();
}

int main(void)
{
	// TWI Pull UP
	PORTC |= ((1<<PINC4) | (1<<PINC5));

	// Initial I2C Slave
	TWAR = I2CSLAVE_ADDR & 0xFE;	// Set I2C Address, Ignore I2C General Address 0x00
	TWDR = 0x00;			// Default Initial Value

	// Start Slave Listening: Clear TWINT Flag, Enable ACK, Enable TWI, TWI Interrupt Enable
	TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE);

	// Enable Global Interrupt
	sei();

	// Initial Variable Used
	regaddr=0;
	regdata=0;

	while (1) {

	}

}

Тактовая частота микроконтроллера должен быть не менее 8 MHz.

В этом примере, обращаясь по шине I2C к устройству по адресу указанному в строке:

#define I2CSLAVE_ADDR        0x4E

можно управлять портом B микроконтроллера, используя адреса:

#define PORT_DDR 0xB0 // PORTB Settings #define PORT_IN 0xB1 // Get PINB #define PORT_OUT 0xB2 // Set PORTB

Для программирования порта на вход, следует записать 0x00 по адресу 0xB0.
Для получения состояния входов порта B нужно прочитать один байт по адресу 0xB1.
Для программирования порта на выход записать 0xFF по адресу 0xB0.
Чтобы установить все выходы порта в 1 надо записать 0xFF по адресу 0xB2.

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

Успехов!

Translate
Архіви

© 2011-2019 Андрій Корягін, Кременчук - Київ, Україна