The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

5.3.2 Архитектура программного обеспечения I2C

5.3.2 Архитектура программного обеспечения I2C

Предыдущая  Содержание  Следующая V*D*V

Подсистема I2C появилась после большой реконструкции, с выходом ядра версии 2.6. В этом разделе мы обсудим архитектуру I2C в ядре версии 2.6. Хотя эта шина сама по себе очень проста, архитектура подсистемы I2C в Linux является довольно сложной и лучше всего её можно понять на примере.

Предположим, что ваша плата использует I2C, как показано на Рисунке 5.8, который показывает на плате две шины I2C; каждая шина I2C находится под управлением адаптера шины I2C, подобного PCF8584, который действует как ведущее устройство I2C для данной шины и, кроме того, работает как интерфейс между шиной процессора и шиной I2C. Таким образом, процессор может обращаться к любому из устройств I2C на шинах I2C путём программирования этих адаптеров. К первой шине I2C подключены две микросхемы EEPROM, а к другой шине I2C подключена микросхема RTC.

 

Рисунок 5.8 Пример топологии шины I2C.

Рисунок 5.8 Пример топологии шины I2C.

 

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

 

Драйвер алгоритма I2C: каждый адаптер шины I2C имеет свой собственный способ взаимодействия с процессором и шиной I2C. В приведённом выше примере оба шинных адаптера используют стиль сопряжения микросхемы PCF, который определяет регистры, которые должны быть реализованы адаптером шины и реализацию алгоритмов для передачи и приёма данных. Драйвер алгоритма реализует основные процедуры обмена данными (передача и приём). Например, на Рисунке 5.8 показан только один драйвер алгоритма, драйвер алгоритма PCF8584.

Драйвер адаптера I2C: это можно рассматривать как уровень BSP для подсистемы I2C. Драйвер адаптера I2C и драйвер алгоритма вместе управляют шинами I2C в системе. В приведённом выше примере мы определяем два драйвера адаптера I2C для каждой из двух шин в системе. Оба эти драйвера адаптера связаны с драйвером алгоритма PCF8584.

Драйвер ведомого устройства I2C: драйвер ведомого устройства содержит процедуры для доступа к определённому виду ведомого устройства на шине I2C. В нашем примере мы предоставляем два драйвера: один для доступа к EEPROM на первой шине I2C, а другой для доступа к микросхеме RTC на второй шине I2C.

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

 

Почему подсистема разделена таким образом? Это делается для как можно большего повторного использования программного обеспечения и чтобы дать возможность переносить код. Это достигается за счёт сложности. Подсистема I2C находится в каталоге drivers/i2c дерева исходных текстов ядра. В этом каталоге подкаталог buses содержит различные драйверы адаптера шины, algos содержит различные драйверы микросхем алгоритма, а каталог chips содержит различные драйверы ведомых устройств и клиентов. Общая часть всей подсистемы I2C называется ядром I2C и реализована в файле drivers/ic2/i2c-core.c.

 

Драйвер алгоритма и адаптера шины

 

Для того, чтобы лучше понять, как писать эти драйверы, мы рассмотрим реализацию драйвера алгоритма для PCF8584 для Linux и шинный адаптер, который использует этот алгоритм. Прежде чем мы углубимся в исходный код, давайте сделаем очень общий обзор микросхемы интерфейса I2C PCF8584. PCF8584 представляет собой интерфейсное устройство между стандартными высокоскоростными параллельными шинами и шиной I2C. Микросхема осуществляет передачу данных между шиной I2C и широко распространённой параллельный шиной микроконтроллера, используя либо прерывание, либо опрос. PCF8584 определяет следующие регистры адаптера шины I2C.

 

S0: регистр буфера данных/сдвига, который выполняет параллельно-последовательное преобразование между процессором и шиной I2C.

S0': это внутренний регистр адрес и он заполняется во время инициализации.

S1: управляющий регистр и регистр состояния, используемый для доступа к шине и управления.

S2: регистр тактовой частоты.

S3: регистр вектора прерывания.

 

Спецификация PCF8584 содержит более подробную информацию о том, как программировать регистры для инициализации, передачи и приёма. Спецификацию можно загрузить с веб-сайта компании Philips Semiconductor.

Каждый драйвер алгоритма связан со структурой данных i2c_algorithm, объявленной в файле include/linux/i2c.h. Эта структура данных имеет указатель на функцию master_xfer, который указывает на функцию, которая реализует фактический алгоритм передачи и приёма по I2C. Другими важными полями этой структуры являются:

 

name: название алгоритма.

id: каждый алгоритм определяется с помощью уникального номера. Различные типы алгоритмов определены в заголовочном файле include/linux/i2c-id.h.

algo_control: это указатель на функцию, подобную ioctl.

functionality: это указатель на функцию, которая возвращает функции, поддерживаемые адаптером, например, какие типы сообщений поддерживаются драйвером I2C.

 

static struct i2c_algorithm pcf_algo = {
  .name          = "PCF8584 algorithm",
  .id            = I2C_ALGO_PCF,
  .master_xfer   = pcf_xfer,
  .functionality = pcf_func,
};

 

Драйвер алгоритма сам по себе не имеет смысла, если он не связан с драйвером адаптера шины I2C. Драйвер алгоритма PCF обеспечивает для этой цели функцию привязки: i2c_pcf_add_bus(). Каждый драйвер адаптер связан со структурой данных i2c_adapter (объявленной в файле include/ linux/i2c.h), экземпляр которой создаётся драйвером адаптера. Драйвер адаптера вызывает функцию i2c_pcf_add_bus с указателем на структуру i2c_adapter. Важными полями структуры i2c_adapter, которые настраиваются драйвером адаптера, являются:

 

name: имя для адаптера.

class: указывает тип класса устройств I2C, который поддерживает этот драйвер.

algo: указатель на структуру данных i2c_algorithm. i2c_pcf_add_bus() устанавливает algo указывающим на pcf_algo.

algo_data: указатель на закрытую, зависимую от алгоритма структуру данных. Например, драйвер алгоритма PCF  присваивает этому полю внутренний указатель на структуру данных i2c_algo_pcf_data. Эта структура данных содержит указатель на процедуры для доступа к различным регистрам адаптера. Таким образом, драйвер алгоритма отделён от деталей конструкции платы; драйвер адаптера экспортирует особенности конструкции платы используя эту структуру данных. Драйвер адаптера определяет различные процедуры, которые определены в структуре данных i2c_algo_pcf_data следующим образом:

 

static struct i2c_algo_pcf_data pcf_data = {

  .setpcf     = pcf_setbyte,

  .getpcf     = pcf_getbyte,

  .getown     = pcf_getown,

  .getclock   = pcf_getclock,

  .waitforpin = pcf_waitforpin,

  .udelay     = 10,

  .mdelay     = 10,

  .timeout    = 100,

};

 

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

 

Определить структуру типа i2c_adapter следующим образом:
 
static struct i2c_adapter pcf_ops = {
 .owner     = THIS_MODULE,
 .id        = I2C_HW_P_ID,
 .algo_data = &pcf_data,
 .name      = "PCF8584 type adapter",
};
 

Определить функции инициализации, которые делают следующее:
– Запрашивают различные ресурсы, необходимые для драйвера адаптера, такие как линия прерывания.
– Вызывают функцию i2c_pcf_add_bus для связи алгоритма PCF с этим драйвером адаптера. Функция i2c_pcf_add_bus выполняет внутренний вызов функции ядра I2C i2c_add_adapter, которая регистрирует в ядре новый драйвер адаптера. После этого адаптер доступен для регистрации клиентами.

 

I2C драйверы ведомых устройств и клиентов

 

Чтобы понять модель драйвера клиента I2C, предположим, что есть вымышленное устройство, подключенное по шине I2C, которое содержит один 32-х разрядный регистр. Функциональность драйвера заключается в предоставлении процедур для выполнения чтения и записи регистра. Мы также предполагаем наличие программного обеспечения драйвера алгоритма и драйвера адаптера. Это включает в себя создание драйвера ведомого устройства и клиента. Драйвер ведомого устройства использует структуру данных i2c_driver, объявленную в заголовочном файле include/linux/i2c.h. Важными полями этой структуры данных являются:

 

name: название клиента.

id: уникальный идентификатор этого устройства. Список всех идентификаторов может быть найден в файле include/linux/i2c-id.h.

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

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

detach_client: указывает на функцию, которая удаляет экземпляр клиента и уведомляет ядро I2C о его удалении.

command: это подобная ioctl команда, которая может быть использована для специальных функций в устройстве.

 

В нашем примере драйвера мы определяем структуру i2c_driver следующим образом:

 

static struct i2c_driver i2c_test_driver = {

  .owner          = THIS_MODULE,

  .name           = "TEST",

  .id             = I2C_DRIVERID_TEST,

  .flags          = I2C_DF_NOTIFY,

  .attach_adapter = i2c_test_scan_bus

  .detach_client  = i2c_test_detach,

  .command        = i2c_test_command

};

 

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

 

static int i2c_test_scan_bus(struct i2c_adapter *d)

{

  return i2c_probe(d, &addr_data, i2c_test_attach);

}

 

Функция i2c_probe предоставляется ядром I2C; эта функция использует информацию в структуре данных addr_data, чтобы вызвать функцию i2c_test_attach; последняя создаёт нового экземпляр клиента и регистрирует его в подсистеме. Структура addr_data объявлена в файле include/linux/i2c.h. Функция addr_data используется для выполнения следующего:

 

Принудительной регистрации устройства I2C по указанному адресу в качестве клиента без проверки

Игнорирования устройства I2C по указанному адресу

Зондирования устройства I2C по указанному адресу с помощью адаптера и обнаружения его присутствия

Функционирования в нормальном режиме, просто обращаясь к устройству I2C по указанному адресу и проверяя его присутствие

 

Функция i2c_test_attach создаёт структуру данных i2c_client для клиента и заполняет её. Структура данных i2c_client также объявлена в файле include/linux/i2c.h и её важными полями являются:

 

id: идентификация

addr: I2C адрес, по которому было обнаружено ведомое устройство

adapter: указатель на структуру i2c_adapter для шины, на которой был обнаружен клиент

driver: указатель на структуру i2c_driver

 

static int

i2c_test_attach(struct i2c_adapter *adap, int addr,

                int type)

{

  struct i2c_client *client =

      kmalloc(sizeof(struct i2c_client), GFP_KERNEL);

  client->id = TEST_CLIENT_ID:

  client->addr = addr;

  client->adapter = adapter;

  client->driver = &i2c_test_driver;

 

  return(i2c_attach_client(client));

}

 

Наконец, командная функция, которая реализует функциональные возможности чтения и записи одного регистра микросхемы, выглядит в следующим образом:

 

static int

i2c_test_command(struct i2c_client *client,

                 unsigned int cmd, void *arg)

{

  if(cmd == READ)

    return i2c_test_read(client, arg);

  else if(cmd == WRITE)

    return i2c_test_write(client, arg); return -EINVAL;

}

 

static int

i2c_test_read(struct i2c_client *client, void *arg)

{

  i2c_master_recv(client,arg,4);

}

 

static int

i2c_test_write(struct i2c_client *client, void *arg)

{

  i2c_master_send(client, arg ,4);

}

 

Функции i2c_master_recv и i2c_master_send читают и записывают байты от данного клиента. Внутри они вызывают функцию драйвера master_xfer. Также доступна ещё одна функция, i2c_transfer; она посылает серию сообщений, которые могут быть смесью операций чтения и записи, приводя к комбинированным операциям.

 

Предыдущая  Содержание  Следующая