Может ли Raspberry Pi надежно поразить серийный номер 9600 бод и есть ли пример кода?

29

Мне интересно, насколько возможно использовать бит-бэнгинг для управления последовательностью 9600 бод через контакты GPIO на Raspberry Pi.

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

Моим стандартом надежности является то, что большую часть времени он должен оставаться в пределах нормальных допусков 9600 бод. В настоящее время я не уверен, сколько ошибок допустимо на практике, но в протоколе есть повторные передачи и подтверждения, поэтому он по крайней мере несколько терпим.

Итак, мои вопросы:

  • Может ли программное обеспечение пользователя надежно работать на скорости 9600 бод?
  • Нужно ли для этого исправленное ядро ​​в реальном времени?
  • Сколько ошибок мне следует ожидать в целом?

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

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

Nakedible
источник
1
+1 Хороший вопрос. Я также был бы заинтересован в ответе на это. Однако вопрос reliabilityможет зависеть от действий и ожиданий.
Jivings
2
RS-232 требует отрицательного напряжения, но этот последовательный канал не использует напряжения RS-232. Я не знаю, но я полагаю, что RPi требует стандартного конвертера TTL в RS-232, такого как MAX232 или любого из десятков вариантов. Однако, чтобы было ясно, это не относится к моему вопросу, я просто хотел ответить.
Nakedible
4
Также есть второй UART на выводах GPIO 14 и 15. Это не так полно, как основной, хотя
Джон Ла Руи
1
@Nakedible не могли бы вы поделиться своей работой? У меня похожая проблема, и я хотел бы увидеть, как вы сделали второй сериал через spi. спасибо MSP

Ответы:

15

Я наконец решил это, но довольно неортодоксальным способом. Я отказался от бит-бенга как слишком ненадежного и попытался найти другие решения, которые позволили бы мне то же самое, не добавляя больше оборудования. Я собирался написать драйвер ядра, который бы вызывал прерывание на GPIO, а затем перенастраивал вывод на 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 бод я использую тактовую частоту SPI 250 кГц, и это означает, что я могу спать даже миллисекунду между заполнением и опустошением FIFO без каких-либо ошибок передачи. Однако, чтобы ошибиться, я использую 300 мкс сна. Я кратко проверил, насколько далеко я могу продвинуться, и, по крайней мере, тактовая частота SPI 2 МГц все еще использовалась, поэтому это решение также масштабируется до более высоких скоростей передачи.

Одна неприятная часть этого решения состоит в том, что драйвер SPI ядра не поддерживает такую ​​потоковую передачу битов. Это означает, что я не могу сделать это, написав свой собственный модуль ядра, используя драйвер SPI ядра, и я также не могу сделать это, используя /dev/sdidev0.0 из пользовательского пространства. Однако на Raspberry Pi SPI и другие периферийные устройства доступны непосредственно из пользовательского пространства с помощью mmap (): n / dev / mem, полностью минуя управление ядром. Я не очень доволен этим, но он работает отлично, и это дает дополнительное преимущество, что ошибки сегментации в пользовательском пространстве не могут привести к сбою ядра (если только случайно не возиться с другими периферийными устройствами). Что касается использования ЦП, 300 мкс-снов, кажется, дают мне около 7% использования ЦП постоянно, но мой код очень неоптимальный. Увеличение продолжительности сна, очевидно, снижает загрузку процессора напрямую.

Изменить: Забыл упомянуть, я использовал хорошую библиотеку bcm2835 для управления SPI из пользовательского пространства, расширяя его при необходимости.

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

Nakedible
источник
@ Nakedible - Можете немного рассказать или предоставить ссылки на часть mmap (). Я работаю над тем же.
Джей К
Используете ли вы оборудование SPI для передачи?
Гепард
Да, передача работает также.
Nakedible
3
Можете ли вы дать пошаговые инструкции о том, как вы можете отправлять и получать код, и делиться любыми модифицированными пакетами, если вы используете что-то, что вы исправили сами ... TIA!
Валентин
10

Казалось бы, по крайней мере без исправлений в реальном времени (CONFIG_PREEMPT_RT), Raspberry Pi не может надежно побить 9600 бод последовательный.

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

Мин .: 12 мкс. Средняя: 24 мкс. Макс .: 282 мкс.

Это казалось общим результатом. Максимум варьировался при более медленных измерениях от 100 мкс до 300 мкс. Я также проверил распределение, и кажется, что подавляющее большинство находится в диапазоне 24 мкс. Есть только несколько, которые превышают 50 мкс, но есть почти всегда некоторые. Иногда бывают и огромные задержки, например 4000 мкс, но они достаточно редки, чтобы их игнорировать, по крайней мере, пока.

Я полагаю, что максимальные задержки должны быть ниже 50 мкс для 9600 бод, чтобы не возникали ошибки, и любая задержка свыше 100 мкс приводит к тому, что при передаче или приеме полностью пропускается бит.

Это все, даже не касаясь контактов GPIO еще. Так как я не смог получить пробный запуск даже с двумя секундами, можно с уверенностью сказать, что без исправлений в реальном времени Raspberry Pi не сможет выполнить битовую передачу последовательного канала 9600 бод без генерации ошибок в течение какого-либо серьезного времени.

Я буду тестировать патчи в реальном времени позже, если у меня будет время.

(Используемый инструмент: http://git.kernel.org/?p=linux/kernel/git/clrkwllms/rt-tests.git;a=summary )

Обновление: ядро ​​RPi зависает при загрузке без обнаружения SD-карты, если оно скомпилировано с набором патчей CONFIG_PREEMPT_RT. Это может быть легко исправить, но, глядя на грязные различия в исходниках RPi, я думаю, что я хочу подождать, пока их больше не будет в основном ядре.

Итак, тестирование это слишком сложно, и я отказываюсь от него.

Nakedible
источник
0

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

Лало UY
источник
Но это все еще немного стучит. На самом деле, это то, как вы обычно делаете удары.
Филиппос