среда, 19 февраля 2014 г.

USB 3g модем на базе чипа Sierra SL8082 и Linux

Оставлю себе напоминание об этом периоде.
Linux 3.2.18, buildroot 05-2013.
В первую очередь - мне не надо переключать модем в режим модема) потому что он сразу в нем и нет всякой ерунды типа сидирома и флэшки.
Просто появляется четыре устройства (типично - ttyUSB0-3).
ttyUSB0 - предназначен для обмена с модемом по двоичному протоколу (полезно, чтобы не разрывать текущее соединение)
ttyUSB3 - обмен классическими AT-командами.
Однако для того, чтобы увидеть эти самые устройства, нам надо конечно же настроить ядро (make linux-menuconfig):
* Device drivers
    * USB Support
        * USB Serial converter support
            * USB Generic serial driver
            * USB friver for GSM and CDMA modems
            * USB Sierra wireless driver
В принципе, теперь на загрузке должно появится упоминание о ttyUSB* устройствах.
Можно даже и соединятся напрямую посылая команды в ttyUSB3, но удобнее для этого использовать pppd, а чтобы использовать для начала надо установить (make menuconfig):
* Packages
    * Network applications
        * pppd
После установки настраиваем pppd:
1.  Создаем файл /etc/ppp/peers/имя_соединения такого содержания:
 /dev/ttyUSB3 115200
 nobsdcomp
 nodeflate
 connect '/usr/sbin/chat -v -f /etc/ppp/chat-gprs'
 noauth
 noipdefault
 usepeerdns
 defaultroute
 debug
 nodetach
2. Напишем файл /etc/ppp/chat-имя_соединения:
  TIMEOUT         5
  ECHO            ON
  ABORT           '\nBUSY\r'
  ABORT           '\nERROR\r'
  ABORT           '\nNO ANSWER\r'
  ABORT           '\nNO CARRIER\r'
  ABORT           '\nNO DIALTONE\r'
  ABORT           '\nRINGING\r\n\r\nRINGING\r'
  ''                       \rAT
  TIMEOUT         12
  OK              ATE1
  OK              'AT+cgdcont=1,"IP","m2mstatic.beeline.ru"'
  OK              ATD*99#
После таких манипуляций мы уже можем проверить соединение: pppd call имя_соединения
На этом бы можно было и закончить но есть проблема раз - соединение периодически разрывается. Раз проблема решается добавлением в файл /etc/inittab строки :::respawn:pppd call имя_соединения.
Однако стала проявляться проблема номер два - обрыв может произойти из-за аппаратной проблемы в модеме, и вот тут и всплывает, что после такого обрыва файл порта ВНЕЗАПНО становится ttyUSB4 и соединиться мы уже ни с кем, понятно, не сможем( Грусть-печаль, помогает тут передергивание провода USB. Но как-то это не технологично, поэтому думаем, как программно отключать USB-хабы, додумываемся до такого:
echo 0 > /sys/bus/usb/devices/usb2/1-1/1-1.2/authorized (отключить)
echo 1 > /sys/bus/usb/devices/usb2/1-1/1-1.2/authorized (включить)
Удобно все это засунуть в отдельный скрипт:
echo 0 > /sys/bus/usb/devices/usb2/authorized sleep 5 echo 1 > /sys/bus/usb/devices/usb2/authorized sleep 5 echo 0 > /sys/bus/usb/devices/usb1/authorized sleep 5 echo 1 > /sys/bus/usb/devices/usb1/authorized sleep 5 date >> /var/gprs echo "gprs connect" >> /var/gprs pppd call gprs
И уже этот скрипт вызывать для создания соединения.
Ну и напоследок важный момент - маршрутизация. После создания тоннеля надо его прописать маршрутом по умолчанию. Для этого создаем файл /etc/ppp/ip-up с таким содержимым:
#!/bin/sh
route del default
route add default ppp0
А теперь точно все.

пятница, 7 февраля 2014 г.

Подключение датчиков температуры LM75, DS1621 в Linux

Увидел я в одном из наших изделий большую белую колбасу - на деле это оказался низкоомный резистор мощностью 8Вт для обогрева платы в прохладном климате.
Раз есть обогреватель - значит кто-то должен решать, когда его включать. На роль "кого-то" разработчики сначала определили один из клонов терморегурятора LM75, но впоследствие он был заменен на DS1621, ибо у последнего была встроенная EEPROM и не надо было после выключения питания заново прописывать уставки срабатывания (хотя это было и не трудно).
Это было очень краткое (надеюсь) вступление. Теперь по существу.
Как известно - все уже придумано за нас, особенно в такой могучей ОС, как Linux, нам же остается лишь скромная участь повторителей, поэтому приступим.
1. Для начала традиционно настроим ядро (make linux-menuconfig):
    Device drivers
    * I2C Support
        * Enable compatibility bits for old user-space
        * I2C device interface
        * I2C bus multiplexing support
        * Autoselect pertinent helper modules
    * I2C Hardware Bus support
        * GPIO-based bit-banging I2C
    * Hardware monitoring support
        * Dallas Semiconductor DS1621 and DS1625
2. Теперь конкретизируем тип датчика на шине. Лезем в боард-файл своей платформы (например, board-sam9m10g45.c) и там пишем:
    static struct i2c_board_info __initdata ek_i2c_devices[] = {
   {
        I2C_BOARD_INFO("ds1621", 0x48),
        .type = "ds1621",
    },
}
и в этом же файле в функции инициализации платы прописываем i2c:
at91_add_device_i2c(0, ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));

В принципе, после перекомпиляции ядра в каталоге /sys/bus/i2c/device/x-yyyy/ появятся как минимум три файла - temp1_input (текущая температура), temp1_max (температура отключения), temp1_min  (температура включения), скорее всего файлов будет больше - зависит от типа терморегулятора.

Если что-то идет не так, то очень помогут диагностировать проблемы два комплекта утилит: lm-sensors и i2c-tools. Оба пакета можно подключить в Package selection for the target/Hardware handling.
В самом примитивном случае пользоваться ими можно так:
i2cdetect -y 0 (покажет все устройства на шине 0)
sensors (покажет данные с датчиков, обнаруженных на шине.

Вроде ничего не упустил.

среда, 15 января 2014 г.

Подключение микросхемы MCP2515 к Linux

Возникла у меня потребность обмениваться информацией с внешним миром, да не абы как, а используя 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, и у нас бы ничего не заработало:
#/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
Теперь у нас интерфейс поднимается автоматически.

Ну вот, в принципе, и все