Arsenii Iarmolinskii

Эксперименты со скоростью отправки данных по Serial

Известно, что отправка данных с помощью Serial является достаточно долгой операцией. Вопрос, насколько долгой и как можно оптимизировать обмен по последовательному порту?

Теория

Согласно информации из интернета, операции отправки данных по Serial являются неблокирующими (до поры до времени).

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

Практика

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

Таким образом мы минимизируем процент времени МК, который тратится на отправку данных.

Эксперимент

Для определения оптимальных параметров для такой отправки был поставлен эксперимент:

С помощью функции Serial.write было измерено время отправки данных по Serial для различных количеств байт на скорости 115200 бод/с.

Код приведен ниже:

int charCount = 0;
uint32_t send0 = 0;
uint32_t sendTime = 0;

void serialBenchmark()
{
  char buf[256] = {0};

  Serial.print("Char count,send time [us],req period [us],time density [%]\n");

  for(charCount = 0; charCount < 256; charCount++)
  {
    Serial.flush();
    send0 = micros();
    Serial.write(buf, charCount);
    sendTime = micros() - send0;

    Serial.print(charCount);
    Serial.print(',');
    Serial.print(sendTime);
    Serial.print(',');
    Serial.print(charCount * 1000000 / 11520);
    Serial.print(',');
    Serial.print(sendTime * 100.0 / (charCount * 1000000 / 11520));
    Serial.println();
  }
}

void setup()
{
    Serial.begin(115200);

    serialBenchmark();
}

void loop()
{
}

Результаты эксперимента показаны ниже:

Результаты эксперимента

Исходя из результатов видно, что при отправке более 71 байта данных мы начинаем упираться в скорость отправки данных по Serial. Для максимальной эффективности стоит отправлять данные посылками от 6 до 70 байт. При отправке меньше 6 байт за раз начинают проявляться накладные расходы на вызов функций и тд, а при отправке более 71 - данные не успевают отправлятся.

Минимальная загрузка мк при отправке данных на скорости 115200 бод/с составила около 8.5% и достигается при отправке за раз от 6 до 70 байт.