Перезапуск передачи данных на основе прерываний (C ++, буферы данных, аппаратная периферия и прерывания) - PullRequest
0 голосов
/ 31 мая 2018

В основном я занимаюсь написанием кода C ++ для встроенных систем на основе «голого металла» (без ОС или RTOS).У меня есть проблема, с которой я неоднократно сталкивался в различных формах, и мне кажется, что нет «по-настоящему элегантного» решения.Это снова беспокоило меня, поэтому я решил поднять его здесь, чтобы посмотреть, может ли кто-нибудь предложить лучший способ ...

Проблема обычно касается перемещения данных между аппаратным периферийным устройством и буферами данных в памяти вответ на прерывания, генерируемые периферийным оборудованием.Простым примером будет прием и передача данных через UART, причем входящие (принятые) байты и исходящие (переданные) байты буферизуются с помощью двух буферов на основе ОЗУ (обычно кольцевых), а аппаратное обеспечение UART генерирует два отдельных прерывания - Получено байт (aka Receiver Not Empty) и переданный байт (aka Transmitter Empty).Для простоты, скажем, не задействованы аппаратные FIFO или DMA, не возникают состояния ошибок (ошибки четности, переполнения буфера и т. Д.) И нет ОС или ОСРВ.

Обработка входящих (полученных) данных проста.Каждый раз, когда UART получает байт, он запускает прерывание, полученное в байтах, и обработчик прерываний считывает байт из приемника UART и записывает его в буфер входящих данных.Если у «отправителя» заканчиваются данные для отправки, UART прекращает прием байтов, поэтому он прекращает запуск своего прерывания, полученного в байтах, и код обработчика прерываний «автоматически» прекращает передачу данных из UART в буфер.Когда «отправитель» возобновляет отправку данных, UART возобновляет прием байтов и запускает свое полученное байтовое прерывание, поэтому код обработчика прерываний «автоматически» возобновляет передачу данных из UART в буфер.Какой-то другой процесс может асинхронно потреблять (считывать и обрабатывать) полученные байты из буфера входящих данных, и единственное осложнение, с которым сталкивается этот код, состоит в том, что некоторое время входящий буфер может быть пустым (не иметь доступных данных).Важно отметить, что ни коду, который реализует входящий буфер данных, ни коду, который потребляет принятые байты, которые были помещены во входящий буфер, не нужно ничего делать, чтобы запускать и останавливать поток принятых байтов из UART во входящийбуфер данных, и, следовательно, им не нужно «ничего знать» о специфике аппаратного обеспечения, которое получило данные, и о том, как их контролировать (т. е. UART и его прерывания).Эти «знания» должны существовать только в коде драйвера и обработчика прерываний UART, поэтому буфер и полученный код потребления данных могут быть довольно «общими».Это все довольно просто, и мне кажется «довольно элегантным».

Но меня беспокоит исходящая (переданная) информация.Давайте начнем с предположения, что в исходящем буфере уже есть байты, ожидающие передачи, и мы уже находимся в процессе их передачи.Каждый раз, когда UART передает байт, он запускает свое прерывание, переданное байтом, и код обработчика прерываний считывает следующий байт из буфера исходящих данных и записывает его в передатчик UART, затем процесс повторяется ... Пока больше нет данныхв буфере исходящих данных.В этот момент, когда UART передает последний байт и запускает свое прерывание, переданное в байтах, код обработчика прерываний обнаруживает, что буфер исходящих данных пуст и больше нет байтов для передачи, поэтому он отключает прерывание передатчика UART, чтобы остановить его непрерывный запуск,Позже, какой-то другой процесс асинхронно записывает еще несколько байтов в буфер исходящих данных, готовый для передачи UART.Но для того, чтобы исходящие данные снова стали «текущими», необходимо перезапустить цикл передачи UART, возможно, повторно включив прерывание UART «Передача байтов», чтобы прерывание сработало снова и обработчик прерывания возобновил перемещение байтов из буфера исходящих данных.к передатчику UART.На мой взгляд, это означает, что исходящий буферный код или процесс записи данных в исходящий буфер должен «знать» о необходимости перезапуска исходящего потока данных и должен «делать что-то особенное», чтобы инициировать это, обычноприводя к тому, что исходящий буферный код записывается для работы конкретно с UART (или другим конкретным оборудованием), чтобы он знал, как повторно включить аппаратное прерывание передачи.Это также довольно легко сделать, и в большей или меньшей степени, как я это делал на сегодняшний день, но по сравнению с процессом получения, который я описал выше, мне всегда кажется, что это несколько «не элегантно».

Другой способ, с которым я справился, - это регулярно получать независимый бит кода, проверяющий, есть ли какие-либо данные в исходящем буфере, и, если да, повторное включение прерывания передачи, но это также выглядит несколько «менее элегантно»,Это добавляет накладные расходы, добавляет задержку между данными, добавляемыми в буфер, и фактической передачей, и трудно понять, как это работает, если вы не знаете, что этот независимый бит кода повторно запускается откуда-то.

На самом деле, на мой взгляд, в «должном элегантном» решении, которое я желаю, входящие и исходящие буферы должны быть в состоянии быть точно таким же кодом (два экземпляра одного класса) и ничего не должны знатьоб оборудовании, к которому они «подключены».Точно так же код приложения, считывающий и записывающий в буферы, также не должен знать ничего об оборудовании, с которым буферы «связаны».Это сделало бы весь этот код достаточно общим, и тогда было бы легко изменить, к какому аппаратному интерфейсу «подключены» буферы данных, изменив только то, какие обработчики прерываний «подключаются» к каким буферам данных, и без необходимости менять буфер илиКод приложения каким-либо образом ...?

Но, как я понимаю, необходимость «перезапустить цикл передачи» предотвращает это.Мне было бы очень интересно узнать, может ли кто-нибудь порекомендовать решение или общий лучший подход к этому.

Благодарю вас,

Мартин.

...