UART - приемный буфер

Я хочу получать и отправлять пакеты через UART. Проблема в том, что я хочу реагировать не сразу на полученный байт, а на определенную последовательность. Эта последовательность состоит из 4 байтов UART и должна оцениваться только после ее полного получения.

Как лучше всего это сделать? Создание только массива, который соответствует 4 байтам, и как только я получил 4 байта, просто проверьте, правильно ли это, или лучше использовать кольцевой буфер большего размера, где все полученные байты хранятся последовательно? (не уверен, как это реализовать)

Пример передачи:

-ПК отправляет нули, пока не получает никакого ответа

- подключена небольшая плата микроконтроллера и получает байты

-если микро получает 4 нулевых байта, он должен передать свои 4 байта на ПК

-ПК видит данные на своем TXD и перестает посылать нули и делает то, что запросил микро. Когда это сделано, ПК отправляет 4 байта обратно в микро, чтобы подтвердить его запрос и сообщить ему, что все готово.

Каков наилучший способ реализовать что-то подобное?

Чего (в целом) вы пытаетесь достичь?
Кольцевая буферизация и извлечение в удобное время для сборки в пакеты, которые обрабатываются по завершении, работоспособны и концептуально просты. Буферизация, которая запускает обработку по завершению пакета, возможно, лучше настроена для конкретного приложения, но не обязательно стоит проблем, если нет проблем с первым подходом.
@ Энди, он же я хочу откалибровать устройство (или, лучше, различные типы устройств). ПК устанавливает требуемое напряжение. Каждое устройство знает свой тип и запрашивает именно то напряжение, в котором оно нуждается. Когда ПК готов, он должен сообщить контроллеру, что он может начать измерение с помощью АЦП.
@canbus Внутренняя конструкция аппаратного буфера, связанного с UART, варьируется от одного семейства микроконтроллеров к другому. Вы имеете в виду конкретный микроконтроллер?
@Chris Stratton в кольцевом буфере мне нужно было бы подсчитать входящие байты и увеличить два указателя, один для позиции данных и один для последних прочитанных данных, я прав?
@Nick Alexeev Контроллер из семейства STM32F030.

Ответы (2)

Во-первых, я рекомендую протокол, структуру фрейма, в идеале начальный шаблон, которого нет в данных, или если он будет найден, он не будет повторяться, или будет иметь начальный шаблон и контрольную сумму. В любом случае вы должны выполнить проектирование/проектирование своей системы, чтобы убедиться, что вы не работаете с неправильными байтами или байтами в неправильном положении.

Во-вторых, сделайте свою системную инженерию, какова ваша скорость передачи данных, какова скорость обработки и выполнения. Если, например, вы можете обработать четыре байта данных за время передачи одного байта с достаточным запасом времени, то это сделает решение более простым. Вы, очевидно, должны хранить 4 байта информации где-то, будь то в UART, если UART имеет достаточно глубокий fifo или вне UART, если нет.

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

Если вам нужно передавать данные во время обработки других, и для обработки пакета требуется более одного байта времени, даже если это так, вероятно, лучше запланировать кольцевой буфер, размер которого вам, вероятно, придется настроить, потому что у вас, вероятно, нет достаточно ресурсов, чтобы сделать его достаточно большим, чтобы ему было все равно. Также вы должны спланировать, чтобы при обработке текущих данных вы собирали новые данные (если протокол требует, чтобы вы обрабатывали более одного за раз). Прерывания могут вступить в игру здесь, но их сложно заставить работать, прерывания не являются обязательным решением, но часто люди решают это сделать.

если вы используете пакетный/кадровый подход, то вам определенно нужен fifo, который собирает как минимум пакеты данных, каждый новый поступающий байт сдвигает данные через окно (или лучше используйте круговой буфер и сдвигайте голову и хвостовые указатели вокруг) как только у вас есть начальный шаблон и, по крайней мере, правильное количество байтов для пакета, затем проверьте его контрольную сумму, если вы решите реализовать это, и если пройдет, обработайте его, если не выбрасывайте все это, просто переместите указатель головы вокруг следующего начального шаблона, если он есть в накопленных данных, в противном случае сопоставьте его с хвостом и подождите еще.

если вы отправляете данные обратно, то же самое, какой протокол для этого, формат кадра/данных? Предполагается, что это одинаковая скорость передачи, поэтому, если, как вы упомянули, вы принимаете четыре и отправляете четыре обратно, это занимает одинаковое время в каждом направлении, даже если для обработки данных требуется небольшое количество тактовых циклов mcu, все равно требуется много тактов, чтобы отправить его обратно с этой скоростью передачи данных, если аппаратное обеспечение не имеет tx fifo, а ваш протокол не является полудуплексным, вам нужно будет обрабатывать ожидание открытия слота tx, перемещая следующий байт в там из какого-то буфера/кольца. ожидание может быть опросом или прерыванием, тот же ответ выше, не ДОЛЖЕН быть ни тем, ни другим, может быть тем, что вам удобно и что работает, для TX это намного проще, если протокол не имеет тайм-аута, так как вы не можете потерять байты На выходе, если ваш код недостаточно быстр, вы просто добавляете пробелы. На стороне RX, если вы не достаточно быстры, вы можете потерять байты.

Все это очень простые вещи и, надеюсь, не то, что вы уже знали и поняли. Начните с простого, отправьте один блок данных с компьютера, каким-то образом укажите от микроконтроллера вашему отладочному решению (для меня это распечатка данных через UART или мигание светодиода), что у вас есть данные. Затем либо разработайте ответ с фиктивными данными, либо разработайте следующий шаг обработки. По сути, займитесь системным проектированием, разбейте проблему на фрагменты размером с укус, определите интерфейсы между фрагментами и разработайте каждый фрагмент, а затем склейте их вместе, границы между фрагментами — это возможности, если необходимо разместить тестовый код / ​​инструменты для проверки кусок. Некоторые из этих фрагментов могут быть разработаны на хост-компьютере с использованием общего языка программирования (хороший язык C) с тестовым приспособлением вокруг кода. конечно, это будет только для общей обработки, если у вас есть какие-либо ресурсы, специфичные для оборудования mcu/board, вам придется либо имитировать это на хосте (больше кода для разработки и тестирования, чтобы обернуть тестируемый код). Это не обязательно означает симулятор для этой среды, но его поиск/разработка может быть полезным. Все зависит от того, насколько серьезной становится проблема.

Производительность, когда я говорил о байтах, стоящих времени, следует понимать, что простое добавление или удаление строки кода может значительно изменить производительность кода на 10%, 20% или более. Даже тот же код с измененным выравниванием (больше или меньше инструкций в начальной загрузке) может и иногда будет изменять производительность кода на 10%, 20% и более. Простое увеличение тактовой частоты микроконтроллера в N раз для повышения производительности не приводит к тому, что один и тот же код работает в N раз быстрее, особенно если флэш-память медленнее, чем максимальная скорость тактовой частоты микроконтроллера, и вам нужно добавлять дополнительные состояния ожидания по мере увеличения. скорость микроконтроллера, чтобы попытаться компенсировать требования к обработке. Рассмотрите возможность запуска из оперативной памяти, если у вас достаточно, если вы столкнетесь с этим, но нет никаких гарантий, что оперативная память или интерфейс памяти были разработаны для работы без состояний ожидания для более высоких тактовых частот. Точно так же тактовая частота процессора может работать с одной скоростью, но это не означает, что периферийные шины находятся на этой тактовой частоте. единственный способ пройти через это - протестировать и измерить (Майкл Абраш Дзен языка ассемблера, обратите внимание на природу x86 этой книги на основные концепции поиска похитителей циклов, можно найти бесплатно на github afaik)

очень короткий ответ, сделайте свою системную инженерию, есть ли у оборудования буфер, какие у вас есть другие ресурсы. сколько памяти вам нужно для связи, чтобы не потерять данные и не отстать. Очевидно, что вам нужно сохранить некоторое количество байтов, прежде чем вы сможете выполнить обработку, поэтому вам нужно как минимум столько места для хранения. Насколько больше, зависит от вашего протокола и анализа того, сколько времени потребуется, чтобы что-то сделать. Или спроектируйте протокол как полудуплексное рукопожатие и займите столько времени, сколько захотите.

Если чтение данных должно быть общим, например, вы анализируете несколько текстовых строк, тогда вам действительно придется реализовать кольцевой буфер FIFO (что довольно тривиально, для этого должно быть много кода в Интернете).

Если данные не являются общими, а представляют собой одну единственную константную последовательность, такую ​​как синхрослово, то вам не нужен буфер. Просто читайте посимвольно.

Концептуальный псевдокод:

#define LENGTH 4

void read_uart (void)
{
  static const char sync [LENGTH] = "WORD";
  static uint8_t counter = 0;

  char ch;

  uart_err_t error = uart_receive(&ch);

  if(!error && ch == sync[counter])
  {
    counter++;
  }
  else
  {
    counter=0; // reset

    if(error)
    {
      // handle errors, frame/overrun error etc etc
    }
  }

  if(counter == LENGTH)
  {
    // whole sync word found, everything ok
  }
}