Ник:
Пароль:

Контакты

E-mail: info@starterkit.ru
тел.: +7 922 680-21-73
тел.: +7 922 680-21-74
Телеграм: t.me/starterkit_ru

Способы оплаты

User Info


Добро пожаловать,
Guest

Регистрация или входРегистрация или вход
Потеряли пароль?Потеряли пароль?

Ник:
Пароль:

ПользователейПользователей:3
Поисковых ботовПоисковых ботов:3
ГостейГостей:1

ОбновитьПодробнееВсегоВсего:7
Форум » starterkit.ru » Embedded Linux
Драйвер SPI жрёт процессорное время
SmartRogue
Добавлено 23.10.2019 10:35 Редактировалось 23.10.2019 10:53
0
Сообщение: 1
SmartRogue
0

Пункты: 1449
Регистрация: 27.11.2017
Здравствуйте, товарищи эксперты. У меня затык.

В наличии:
  • Два SPI-джойстика, соединённых последовательно на одном чипе и одних часах. В документации на джойстики значится, что после активации ножки CS надо дать им 35 мс времени на подготовку данных.
  • SK-iMX6S-OEM-Ind
  • SK-iMX6S/53/50-MB
  • buildroot-2017.08 на базе ядра 4.1.15-2.1.0 для i.mx6 от sasamy (тык).
  • Дебиан 9.3, модифицированный sasamy (тык).

    Что накодил:
    Код

    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    #include <linux/spi/spidev.h>

    ~~~

    typedef struct {
    int16_t adc[4];
    } JoystickMessage;

    ~~~

    path = "/dev/spidev0.0";

    ~~~

    int fd = open(path, O_RDWR);

    if (fd <= 0)
    return;

    uint8_t mode = SPI_MODE_2;
    uint8_t bits = 16;
    uint32_t maxSpeed = 16000;

    int ret = 0;
    ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
    ret += ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
    ret += ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &maxSpeed);

    if (ret < 0) {
    close(fd);
    return;
    }

    JoystickMessage rx[2];

    spi_ioc_transfer tr[3];
    memset(tr, 0, sizeof(tr));

    tr[0].tx_buf = 0;
    tr[0].rx_buf = 0;
    tr[0].len = 0;
    tr[0].delay_usecs = 35000;
    tr[0].bits_per_word = bits;
    tr[0].cs_change = 0;

    for (int i = 1; i <= 2; i++) {
    tr[i].tx_buf = 0;
    tr[i].rx_buf = (uint64_t)&rx[i - 1];
    tr[i].len = 8;
    tr[i].delay_usecs = 200;
    tr[i].bits_per_word = bits;
    tr[i].cs_change = 0;
    }

    ret = ioctl(fd, SPI_IOC_MESSAGE(3), tr);

    close(fd);

    if (ret < 0)
    return;

    // Далее парсинг данных


    Что не так:
    На первый взгляд всё хорошо: циферки приходят правильные, успешно парсятся, вроде бы профит. Код этот исполняется регулярно в цикле, между повторами sleep потока 5 мс. Долго работала программа с этим кодом, да вот заглянул я в утилиту top и глаза на лоб полезли: выше моей программы торчит процесс spi0 и жрёт 55-60% (!!!) процессорного времени. Такое ощущение, что во время пресловутого таймаута в 35000 мкс драйвер заставляет процессор делать while(1).

    Почему код написан именно так:
    Если разбить на два трансфера и вставить между ними православный sleep, то между трансферами CS возвращается в пассивное состояние, и никакие данные джойстиками не готовятся. Есть идея отвязать CS от стандартной ноги SPI и завладеть ею самому через банальный GPIO, но, хоспаде, это же такой костыль! Очень не хочется этого делать.

    Вопросы:
    1. Может, я всё-таки что-то упускаю из виду с драйвером spidev?
    2. Может, кто-то знает иной драйвер?

    Заранее благодарю за помощь!

    Upd. Гипотеза про while(1) подтверждается: заменил 35000 на 35. Джойстики не работают, но и загруженность проца от spi0 упала с ~60% до ~3%...
  • Спуститься к концу Подняться к началу
    Персональная информация
    John Smith
    Добавлено 23.10.2019 11:35 Редактировалось 23.10.2019 11:36 Сообщение: 2
    John Smith
    0

    Пункты: 2289
    Регистрация: 18.02.2011
    Цитата
    Вопросы:
    1. Может, я всё-таки что-то упускаю из виду с драйвером spidev?
    2. Может, кто-то знает иной драйвер?

    У вас все работает именно так как и должно работать. В исходниках драйвера spi написано:
    Код
    if (trans->delay_usecs)
    udelay(trans->delay_usecs);

    udelay - программная задержка типа while(1)...
    И подобное в полный рост используют в патчах реализации RS485 на uart без его аппаратной поддержки.
    "финские студенты" совершенно не умеют писать драйвера и работать с оборудованием да и те кто умеют пишут лишь бы собралось без варнингов.
    При такой задержке вам лучше использовать gpio и рулить им вместо cs spi интерфейса.
    Спуститься к концу Подняться к началу
    Персональная информация
    sasamy
    Добавлено 23.10.2019 16:08 Редактировалось 24.10.2019 11:25 Сообщение: 3
    sasamy
    4.71

    Пункты: 83540
    Регистрация: 14.08.2009
    Цитата
    1. Может, я всё-таки что-то упускаю из виду с драйвером spidev?


    это вообще не драйвер - это прослойка в юзерспейс для доступа к spi-мастеу, больше для тестов а не реальной работы с оборудованием

    Цитата

    2. Может, кто-то знает иной драйвер?


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

    Чтобы исправить то что уже сделано - можно в качестве CS драйаеру SPI указать "левый" gpio а реальным управлять из юзерспейс и использовать таймер для задержки.

    Даже если писать нормальный драйвер ядра для такой огромой задержки 35 ms чипселектом придется управлять вручную.
    Спуститься к концу Подняться к началу
    Персональная информация
    sasamy
    Добавлено 24.10.2019 10:20 Редактировалось 25.10.2019 13:24 Сообщение: 4
    sasamy
    4.71

    Пункты: 83540
    Регистрация: 14.08.2009
    Цитата
    У вас все работает именно так как и должно работать. В исходниках драйвера spi написано:

    if (trans->delay_usecs)
    udelay(trans->delay_usecs);

    udelay - программная задержка типа while(1)...


    ф-ции передачи данных по SPI вызываются в контексте прерывания - там возможны только такие задержки, перепланирование в таком контексте недопустимо - засыпать такой контекст не может, в таком контексте вообще лучше не делать никакие задержки.
    Спуститься к концу Подняться к началу
    Персональная информация
    sasamy
    Добавлено 24.10.2019 13:14 Сообщение: 5
    sasamy
    4.71

    Пункты: 83540
    Регистрация: 14.08.2009
    Цитата
    У меня затык.


    описание протокола этого джостика есть где-нибуть посмотреть ?
    Спуститься к концу Подняться к началу
    Персональная информация
    SmartRogue
    Добавлено 24.10.2019 17:33 Сообщение: 6
    SmartRogue
    0

    Пункты: 1449
    Регистрация: 27.11.2017
    Цитата
    Цитата
    У меня затык.
    описание протокола этого джостика есть где-нибуть посмотреть ?


    Я не совсем прав, называя его джойстиком. Это министик.
    Он работает как сдвиговый регистр и возвращает четыре 16-битных слова (значения АЦП по четырём полуосям). Данные готовы через 35 мс после активации CS.

    В любом случае, всем огромное спасибо за отклики! Я уже переписал всё, управляя ножкой CS самостоятельно. Работает, процессорное время не жрётся.
    Спуститься к концу Подняться к началу
    Персональная информация
    Форум » starterkit.ru » Embedded Linux