Чи може Raspberry Pi надійно бити серійний бод 9600 бодів і чи є приклад код?


29

Мені цікаво, наскільки можливо використовувати бітбангінг для керування серійним бодом 9600 передач через штифти GPIO на Raspberry Pi.

Очевидно, що Linux не є надзвичайно хорошою платформою для бітбінгу, оскільки існує велика кількість драйверів та інших перебоїв, які можуть блокувати процесор протягом тривалого періоду часу (1-10 мс). Однак останнім часом ситуація значно покращилася, і зараз у ядрах регулярно ввімкнено деяке перевагу. Я також підозрюю, що ядро ​​виправленого в реальному часі може бути легко використане на Raspberry Pi, і підключене обладнання та драйвери можна обережно вибирати.

Мій стандарт надійності полягає в тому, що вона повинна залишатися в межах нормальних серійних допусків 9600 бод, що більшість часу. Наразі я не впевнений, скільки помилок допустимо на практиці, але є повторні передачі та підтвердження в протоколі, тож він є дещо толерантним.

Отже, мої запитання:

  • Чи може програмне забезпечення userland надійно виконувати швидкість передачі даних з частотою передачі 9600 бод?
  • Чи потрібно це ядро ​​в режимі реального часу?
  • Скільки помилок я повинен очікувати загалом?

Крім того, чи є який-небудь приклад коду, що робить серійний за допомогою GPIO бітових ударів? Я знаю про Arduino SoftSerial, але це про це.

На всякий випадок, щоб обмежити питання: це не стандартний послідовний інтерфейс, і UART програми Raspberry Pi вже використовується для іншого послідовного посилання. Я не бажаю відповідей, які пропонують зовнішнє обладнання (наприклад, Gertboard або Arduino), а також відповідей, які залежать від UART.


1
+1 Добре запитання. Мені також було б цікаво відповісти на це. Однак питання про це reliabilityможе залежати від дії та очікувань.
Стрибки

2
RS-232 потребує негативних напруг, але ця послідовна ланка не використовує напруги RS-232. Я не знаю, але я вважаю, що RPi вимагає стандартного перетворювача TTL для RS-232, такого як MAX232 або будь-який із десятків варіантів. Однак, щоб бути зрозумілим, це не стосується мого питання, я просто хотів відповісти.
Голий

4
Також є другий UART на штифтах GPIO 14 та 15. Він не такий повноцінний, як головний
Джон Ла Рой,


1
@Nakedible Ви можете, будь ласка, поділитися своєю роботою? У мене є однакова проблема, і я хотів би побачити, як ви зробили другий серіал через spi. дякую MSP

Відповіді:


15

Нарешті я вирішив це, але досить неортодоксально. Я відмовився від біт-ударів як надто ненадійного і намагався знайти інші рішення, які дозволяли б мені те саме, не додаючи більше апаратних засобів. Я розглядав питання про те, щоб написати драйвер ядра, який би викликав перерву на GPIO, а потім перенастроював PIN-код на SPI і використовував SPI для читання всього байта даних - але тоді я отримав кращу ідею.

Я використовую SPI для вибірки ліній на 20x швидкості передачі. Я повністю ігнорую шпильки SCLK і SS, підключаю лінію RX до лінії MISO і лінії TX до MOSI. Це дає мені (1-бітний) осцилоскоп-вид у лінії RX і чітко бачити біти, що передаються в послідовної лінії:

00 00 00 00 00 00 
00 00 00 00 01 FF 
FF FF FF FF 00 00 
01 FF FF FF FF FF 
FF FF E0 00 00 00 
00 00 07 FF FF FF 
FF FF 

З цього випливає просте кодування, щоб з'ясувати правильні позиції, з яких можна відібрати фактичні біти даних. Сторона надсилання однаково тривіальна, мені просто потрібно перетворити кожен байт у довгий потік бітів із включеним початковим бітом і стоп-бітом.

Причина, чому це працює краще, ніж біт-стук, полягає в тому, що SPI має свій власний годинник, який не замерзає з ядром, а лінії передачі та прийому SPI мають 16-байтовий FIFO для передачі, який також не залежить від заморожування ядра. Для 9600 бод я використовую 250 кГц SPI-годинник, а це означає, що я можу спати навіть мілісекунд між заповненням та зливанням FIFO без будь-яких помилок передачі. Однак, щоб помилитися з безпечної сторони, я використовую 300 мкс сна. Я коротко перевірив, наскільки далеко я можу просунути це, і принаймні 2 МГц тактова частота SPI була все ще придатною для використання, тому це рішення також збільшується до більшої швидкості передачі.

Однією потворною частиною цього рішення є те, що драйвер SPI ядра не підтримує таку передачу потокового біту. Це означає, що я не можу цього зробити, написавши власний модуль ядра за допомогою драйвера SPI ядра, а також не можу це зробити, використовуючи /dev/sdidev0.0 з землі користувача. Однак, на Raspberry Pi, SPI та інші периферійні пристрої доступні безпосередньо з userland за допомогою mmap (): n / dev / mem, повністю обходячи управління ядром. Я не дуже задоволений цим, але це працює чудово, і це дає додаткову перевагу, що помилки сегментації в користувальницькій області не можуть зірвати ядро ​​(якщо тільки не заплутатися з іншими периферійними пристроями випадково). Що стосується використання процесора, 300 мкс в режимі сну дають мені близько 7% використання процесора постійно, але мій код дуже неоптимальний. Збільшення тривалості сну очевидно знижує безпосередньо використання процесора.

Редагувати: Забув згадати, я використовував приємну бібліотеку bcm2835 для управління SPI від userland, розширюючи її, де потрібно.

Отже, підводячи підсумок: я можу надійно передавати та приймати по послідовній лінії зв'язку 9600 бод цілком з userland, безпосередньо використовуючи чіп SPI через / dev / mem на 250 кГц на Raspberry Pi.


@ Nakedible - Ви можете трохи розробити або надати посилання на частину mmap (). Я працюю над тим самим.
Джей К

Чи використовуєте ви також апаратне обладнання SPI для передачі?
Гепард

Так, і передача творів.
Голий

3
Чи можете ви, будь ласка, дати покрокові інструкції, як ви можете надсилати та отримувати код, і ділитися будь-якими зміненими пакетами, якщо ви використовуєте щось, що ви самі виправили ... TIA!
валент

10

Здавалося б, щонайменше без патчів у режимі реального часу (CONFIG_PREEMPT_RT), Raspberry Pi не може надійно розкусити серійну потужність 9600 бод.

Я використав простий тестер затримки, який оптимально налаштував усі побічні речі Linux (sched_fifo, пріоритет 99, cpu_dma_latench 0us, mlockall). Я спробував спати 100 мкс (приблизно 9600 бод) і перевірив перевищення затримки в тихій системі протягом 2 хвилин. Результати:

Мінімальна: 12 µсек. Середня: 24 мкс. Макс.: 282 мкс

Це здавалося загальним результатом. Максимум змінювався при повільних вимірах між 100 мкс та 300 мкс. Я також перевірив розподіл і, здається, переважна більшість знаходяться в діапазоні 24 мкс. Є лише декілька, що перевищують 50 мкс, але їх майже завжди є. Також іноді існують величезні затримки, такі як 4000 мкс, але це досить рідко, щоб їх ігнорувати, принаймні поки що.

Я думаю, що максимальна затримка повинна бути нижче 50 мкс для 9600 бод, щоб не отримати помилок, а будь-яка затримка понад 100 мкс має зовсім відсутність у передачі чи прийомі.

Це все, навіть не торкаючись штифтів GPIO. Оскільки я не міг досягти чистого пробігу навіть лише за 2 секунди, здається, сміливо сказати, що без виправлень в реальному часі Raspberry Pi не зможе розірвати послідовне посилання в режимі 9600 бод, не створюючи помилок за будь-яку серйозну кількість часу.

Пізніше я буду тестувати виправлення в режимі реального часу, якщо знайду час.

(Використовується інструмент: http://git.kernel.org/?p=linux/kernel/git/clrkwllms/rt-tests.git;a=summary )

Оновлення: Ядро RPi зависає під час завантаження, не виявляючи SD-карту, якщо вона зібрана з набором патчів CONFIG_PREEMPT_RT. Виправити це може бути просто, але, побачивши, що брудний розрізник у джерелі RPi, я думаю, я хочу зачекати, поки більше його буде в основному ядрі.

Отже, перевірити це занадто складно, і я відмовляюся від цього.


0

Вам не потрібно кусатися. Ви можете встановити переривання користувальницької землі в rx gpio, щоб виявити падіння початкового біта. потім встановіть час переривання для вибірки в середині біт. Модуль ядра робити це можливо.


Але це все-таки трохи стукає. Дійсно, це так, як правило, ви робите трохи удари.
Філіпос
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.