Мне интересно, насколько возможно использовать бит-бэнгинг для управления последовательностью 9600 бод через контакты GPIO на Raspberry Pi.
Очевидно, что Linux не очень хорошая платформа для бит-бенга, поскольку существует большое количество драйверов и других прерываний, которые могут блокировать процессор на длительные периоды времени (1-10 мс). Однако в последнее время ситуация значительно улучшилась, и теперь в ядрах регулярно включаются некоторые упреждения. Я также подозреваю, что на Raspberry Pi можно легко использовать исправленное ядро в режиме реального времени, а также тщательно выбирать подключенное оборудование и драйверы.
Моим стандартом надежности является то, что большую часть времени он должен оставаться в пределах нормальных допусков 9600 бод. В настоящее время я не уверен, сколько ошибок допустимо на практике, но в протоколе есть повторные передачи и подтверждения, поэтому он по крайней мере несколько терпим.
Итак, мои вопросы:
- Может ли программное обеспечение пользователя надежно работать на скорости 9600 бод?
- Нужно ли для этого исправленное ядро в реальном времени?
- Сколько ошибок мне следует ожидать в целом?
Кроме того, есть ли какой-нибудь пример кода, выполняющего последовательное соединение по битам GPIO? Я знаю об Arduino SoftSerial, но это все.
На всякий случай, чтобы ограничить вопрос: это не стандартный последовательный интерфейс, а UART Raspberry Pi уже используется для другого последовательного соединения. Я не желаю ответов, которые предлагают внешнее оборудование (например, Gertboard или Arduino), а также ответы, которые зависят от UART.
reliability
может зависеть от действий и ожиданий.Ответы:
Я наконец решил это, но довольно неортодоксальным способом. Я отказался от бит-бенга как слишком ненадежного и попытался найти другие решения, которые позволили бы мне то же самое, не добавляя больше оборудования. Я собирался написать драйвер ядра, который бы вызывал прерывание на GPIO, а затем перенастраивал вывод на SPI и использовал SPI для чтения всего байта данных - но потом я получил более удачную идею.
Я использую SPI для выборки линий со скоростью 20x. Я полностью игнорирую выводы SCLK и SS, подключаю линию RX к MISO и линию TX к MOSI. Это дает мне (1-битное) осциллографическое представление в линии RX и ясно видеть биты, передаваемые в последовательной линии:
Исходя из этого, это простой вопрос кодирования, чтобы выяснить правильные позиции, из которых можно выбирать фактические биты данных. Сторона отправки одинаково тривиальна, мне просто нужно преобразовать каждый байт в длинный поток битов с включенным начальным и конечным битами.
Причина, по которой это работает лучше, чем синхронизация по битам, заключается в том, что 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.
источник
Казалось бы, по крайней мере без исправлений в реальном времени (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, я думаю, что я хочу подождать, пока их больше не будет в основном ядре.
Итак, тестирование это слишком сложно, и я отказываюсь от него.
источник
Вам не нужно кусать удар. Вы можете настроить пользовательское прерывание земли в rx gpio, чтобы обнаружить падение начального бита. затем установите прерывание по времени для выборки в середине битов. Модуль ядра делает это выполнимым.
источник