Возникла у меня потребность обмениваться информацией с внешним миром, да не абы как, а используя CAN-интерфейс, ну и окружение было соответствующее интерфейсу: процессор AT91SAM9G45 (ARM9), Linux 3.2.18 и buildroot 05.2013.
Какие у нас имеются варианты решения данной задачи:
1. Написание своего драйвера. Опыт у меня такой имелся, но... но хотелось изобрести варп-двигатель, а не очередной велосипед, поэтому мимо.
2. Использовать драйвер SPI - spidev. С этого варианта я и начал - убедился в правильной разводке MCP2515 и ее адекватном функционировании. Но для реального обмена по CAN-шине этот метод подходит мало, т.к. много ручной работы (слежение за поступлением прерывания от микросхемы, посылки команд, чтобы забрать полученные данные). В общем, на самый крайний случай.
3. Применить драйвер конкретно для MCP2510/2515. Идеальный во всех отношениях вариант. Реализуя его, получаем устройство CAN, базирующееся на стеке TCP/IP, а это значит, что можно:
- Создавать сокеты и работать с ними любым доступным инструментарием (довольно обширным). В качестве классического примера - функции select()/poll() Unix. А в частности я буду использовать инструменты, имеющиеся в такой отличной библиотеке, как Qt.
- Можно пробрасывать IP поверх CAN, т.е. довольно простым способом сделать маршрутизацию в сети CAN со сложной топологией.
Очевидно, что надо всеми силами стремиться к реализации именно третьего варианта, чем я сейчас и займусь.
Чтение мануалов показало, что для начала надо бы пересобрать ядро с нужными параметрами:
# make linux-menuconfig
* Device drivers
* SPI support
* Atmel SPI controller
* User mode SPI device driver support
* Network support
* CAN bus subsystem support
* Raw CAN protocol
* CAN device drivers
* Platform CAN drivers with Netlink support
* CAN bit-timing calculation
* Microchip MCP251x SPI CAN controllers
* CAN devices debugging messages
Тут же удобно будет пересобрать и файловую систему:
#make menuconfig
* Package Selection for the target
* Network applications
* can-utils
* iproute2
Обе программы нам пригодятся для настройки и тестирования нашего CAN-интерфейса.
Перед тем, как пересобрать ядро и файловую систему, будет полезно провести еще одну манипуляцию - внести небольшие изменения в файл board-sam9m10g45ek.c.
Мы добавим две структуры:
static struct mcp251x_platform_data mcp251x_info =
{
.oscillator_frequency = 24000000,
.irq_flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
};
Здесь указывается тактовая частота MCP, и, что оказалось очень важно для at91, фронты сигналов, по которым определяется прерывание от микросхемы. Для at91 необходимо указывать и нарастание, и убывание фронтов, т.е. любое изменение уровня, если написать только IRQF_TRIGGER_FALLING (как почти везде и написано), то драйвер не сможет захватить прерывание и работы не получится.
{ /* CAN */
.modalias = "mcp2515",
.platform_data = &mcp251x_info,
.mode = SPI_MODE_0,
.chip_select = 2,
.max_speed_hz = 2 * 1000 * 1000,
.bus_num = 0,
.irq = AT91_PIN_PB22,
},
Здесь все тривиально, поясню только два момента:
1. В .modalias надо писать именно свою модель микросхемы, т.к. драйвер реализует отличающееся поведение
2. В .irq указываете именно AT91_PIN_XX, т.е. не употребляя функцию gpio_to_pin().
А ну и в начале файла борды надо не забыть вставить #include:
#include <linux/can/platform/mcp251x.h>
С настройкой ядра и файловой системы закончили - теперь можно прошивать устройство.
Наступил волнующий момент проверки:
Смотрим, чтобы появилось устройство can0:
#ifconfig -a
Поднимаем интерфейс CAN, выставляет скорость 1мБит. Тут нам и пригодится пакет iproute2, мы его запускаем напрямую - /sbin/ip. Если бы его не было, то запустился бы ip из состава buildroot, и у нас бы ничего не заработало:
#cansend can0 00112233#0102030405060708
Проверяем прием входящих пакетов:
#candump can0
Если все работает правильно, то прописываем интерфейс can0 в файл /etc/network/interfaces:
auto can0
iface can0 inet manual
pre-up /sbin/ip link set $IFACE type can bitrate 1000000 triple-sampling on
up /sbin/ifconfig $IFACE up
down /sbin/ifconfig $IFACE down
Ну вот, в принципе, и все
Какие у нас имеются варианты решения данной задачи:
1. Написание своего драйвера. Опыт у меня такой имелся, но... но хотелось изобрести варп-двигатель, а не очередной велосипед, поэтому мимо.
2. Использовать драйвер SPI - spidev. С этого варианта я и начал - убедился в правильной разводке MCP2515 и ее адекватном функционировании. Но для реального обмена по CAN-шине этот метод подходит мало, т.к. много ручной работы (слежение за поступлением прерывания от микросхемы, посылки команд, чтобы забрать полученные данные). В общем, на самый крайний случай.
3. Применить драйвер конкретно для MCP2510/2515. Идеальный во всех отношениях вариант. Реализуя его, получаем устройство CAN, базирующееся на стеке TCP/IP, а это значит, что можно:
- Создавать сокеты и работать с ними любым доступным инструментарием (довольно обширным). В качестве классического примера - функции select()/poll() Unix. А в частности я буду использовать инструменты, имеющиеся в такой отличной библиотеке, как Qt.
- Можно пробрасывать IP поверх CAN, т.е. довольно простым способом сделать маршрутизацию в сети CAN со сложной топологией.
Очевидно, что надо всеми силами стремиться к реализации именно третьего варианта, чем я сейчас и займусь.
Чтение мануалов показало, что для начала надо бы пересобрать ядро с нужными параметрами:
# make linux-menuconfig
* Device drivers
* SPI support
* Atmel SPI controller
* User mode SPI device driver support
* Network support
* CAN bus subsystem support
* Raw CAN protocol
* CAN device drivers
* Platform CAN drivers with Netlink support
* CAN bit-timing calculation
* Microchip MCP251x SPI CAN controllers
* CAN devices debugging messages
Тут же удобно будет пересобрать и файловую систему:
#make menuconfig
* Package Selection for the target
* Network applications
* can-utils
* iproute2
Обе программы нам пригодятся для настройки и тестирования нашего CAN-интерфейса.
Перед тем, как пересобрать ядро и файловую систему, будет полезно провести еще одну манипуляцию - внести небольшие изменения в файл board-sam9m10g45ek.c.
Мы добавим две структуры:
static struct mcp251x_platform_data mcp251x_info =
{
.oscillator_frequency = 24000000,
.irq_flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
};
Здесь указывается тактовая частота MCP, и, что оказалось очень важно для at91, фронты сигналов, по которым определяется прерывание от микросхемы. Для at91 необходимо указывать и нарастание, и убывание фронтов, т.е. любое изменение уровня, если написать только IRQF_TRIGGER_FALLING (как почти везде и написано), то драйвер не сможет захватить прерывание и работы не получится.
{ /* CAN */
.modalias = "mcp2515",
.platform_data = &mcp251x_info,
.mode = SPI_MODE_0,
.chip_select = 2,
.max_speed_hz = 2 * 1000 * 1000,
.bus_num = 0,
.irq = AT91_PIN_PB22,
},
Здесь все тривиально, поясню только два момента:
1. В .modalias надо писать именно свою модель микросхемы, т.к. драйвер реализует отличающееся поведение
2. В .irq указываете именно AT91_PIN_XX, т.е. не употребляя функцию gpio_to_pin().
А ну и в начале файла борды надо не забыть вставить #include:
#include <linux/can/platform/mcp251x.h>
С настройкой ядра и файловой системы закончили - теперь можно прошивать устройство.
Наступил волнующий момент проверки:
Смотрим, чтобы появилось устройство can0:
#ifconfig -a
Поднимаем интерфейс CAN, выставляет скорость 1мБит. Тут нам и пригодится пакет iproute2, мы его запускаем напрямую - /sbin/ip. Если бы его не было, то запустился бы ip из состава buildroot, и у нас бы ничего не заработало:
#/sbin/ip link set can0 up type can bitrate 1000000 triple-sampling on
Посылаем исходящий пакет и смотрим осциллографом:#cansend can0 00112233#0102030405060708
Проверяем прием входящих пакетов:
#candump can0
Если все работает правильно, то прописываем интерфейс can0 в файл /etc/network/interfaces:
auto can0
iface can0 inet manual
pre-up /sbin/ip link set $IFACE type can bitrate 1000000 triple-sampling on
up /sbin/ifconfig $IFACE up
down /sbin/ifconfig $IFACE down
Теперь у нас интерфейс поднимается автоматически.
Ну вот, в принципе, и все