Последовательная запись Arduino пропускает / задерживает сообщения - PullRequest
0 голосов
/ 07 мая 2020

Идея: Мы с другом создаем метроном с (Elegoo) Arduino-Mega, который дополнительно может посылать сигнал MIDI-Clock через последовательный порт. Мигающий светодиод синхронно c с установленным значением BPM, BPM-Control над поворотными энкодерами и все остальное работает нормально. Только отправка MIDI-сигнала по последовательному каналу вызывает у нас головную боль.

Проблема: Сигнал MIDI Clock (0xF8) необходимо отправлять 24 раза на каждую долю. Поэтому мы просто рассчитали время между тактами часов и после того, как временной интервал пройден, мы отправляем 0xF8 через Serial. Легко. Но когда мы подключили его к гитарному луперу Ditto X4, мигание светодиодов нашего метронома и лупера не синхронизировалось c. Итак, мы написали небольшой скрипт в C#. NET, чтобы проверить, что отправляется через Serial, и оказывается, что в зависимости от установленного BPM некоторые сообщения не отправляются вообще или задерживаются, что приводит к вычислению петлителем другой BPM, чем мы пытаемся отправить ( Скриншот вывода скрипта ).

Но мы полностью потерялись здесь. Почему некоторые сообщения задерживаются / не отправляются? Даже на "обычных" скоростях передачи вроде 9600 проблема та же. И, похоже, он не масштабируется с использованием процессора Arduino или установленным BPM:

Set BPM:      Lost Message every x Messages:
  300                      24-26
  150                      10-12
  50                       4-5

Мы также тестировали Arduino Uno R3 (также от Elegoo), но проблема та же.

Этот пример сценария можно использовать для репликации проблемы:

#include <Arduino.h> //Einbinden der Arduino Bibliothek

//Timer Variables
unsigned long startTimeMIDI = 0;
unsigned long currentTime = 0;
unsigned long intervalLED;
unsigned long intervalMIDI;

short counter_BPM = 300 * 2; // Internally we use BMP*2

void setup()
{
  Serial.begin(31250); //Forced by the MIDI standard
  while ( !Serial ) /*wait for serial init*/ ;
}

void loop()
{
  currentTime = micros();

  intervalLED = (120000000/counter_BPM); //60000000*(BPM/2)
  intervalMIDI = intervalLED/24; //Midi Clock has to be sent 24 times for each beat

  if (currentTime - startTimeMIDI > intervalMIDI){
    Serial.write(0xF8);    //send MIDI Clock signal
    startTimeMIDI = currentTime;  //reset timer value
  }
}

Это сценарий C#, используемый для отслеживания отправляемой информации:

static void Main(string[] args)
    {
        serial = new SerialPort("COM4", 31250);
        serial.Open();

        int cycleSize = 50; //Averaging over 50 Values

        long[] latencyList = new long[cycleSize+1];

        Stopwatch watch = new Stopwatch();
        watch.Start();

        int n = 0;
        while(true)
        {
            n++;
            watch.Start();

            int response = serial.ReadByte();
            watch.Stop();

            long latency = watch.ElapsedTicks/(Stopwatch.Frequency/(1000L*1000L));
            watch.Reset();

            if (n <= cycleSize)
            {
                latencyList[n] = latency;
            }
            else
            {
                latencyList[n % cycleSize] = latency;
            }

            double average = latencyList.Average();
            Console.WriteLine("" + n + " " + latency.ToString("000000") + "µs - response:" + response + " - Average: " + average.ToString("##0.00") + " - BPM: " + (int)(60000000/(average * 24)));

        }
}

EDIT: (May 9, 2020) Мне нужно прояснить проблему с гитарным лупером: поскольку лупер используется для синхронизации c его эффектов с остальной группой, это самая важная проблема. Мигание светодиода Arduinos BPM (мы нажали и подошли достаточно близко к множеству установленных BPM, чтобы считать его достаточно точным) и мигание светодиода Loopers слишком быстро дрейфуют друг от друга, чтобы быть приемлемым . Мы ставим светодиоды рядом друг с другом, и они go из синхронного c мигают попеременно в течение ~ 30 секунд, так что на живом концерте все развалится. Поскольку мигание светодиода луперов запускается входом MIDI, который он получает, мы проверили согласованность отправленных тактовых сигналов и обнаружили нечетную задержку между сигналами.

Ответы [ 2 ]

0 голосов
/ 09 мая 2020

Почему некоторые сообщения задерживаются / не отправляются? Даже на "обычных" скоростях передачи вроде 9600 проблема та же. И, похоже, он не масштабируется с использованием процессора Arduino или установленным BPM

Похоже, это проблема с тем, как вы измеряете время между сообщениями.

C# код использует класс Stopwatch, который имеет это примечание:

На многопроцессорном компьютере не имеет значения, на каком процессоре выполняется поток. Однако из-за ошибок в B IOS или уровне аппаратной абстракции (HAL) вы можете получить разные результаты синхронизации на разных процессорах . Чтобы указать привязку к процессору для потока, используйте метод ProcessThread.ProcessorAffinity .

Мое выделение добавлено из https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.stopwatch?view=netcore-3.1

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

Этой проблемы можно избежать, установив привязку процессора при запуске консольного приложения, используя:

В противном случае альтернативным способом измерения периода между сообщениями может быть CRO / DSO или даже использование одного Arduino для измерения вывода другого.

Но когда мы подключили его к Ditto X4 Guitar Looper мигание светодиодов нашего метронома и лупера вышло из синхронизации c.

Что касается вашего фактического приложения, из вопроса не ясно, насколько быстро и на сколько светодиод и петлитель не синхронизированы c. * 1 048 *

Есть несколько вопросов, которые следует учитывать в той или иной степени:

  • micros() разрешение составляет 4 мкс. Из-за проблем с целочисленным округлением и задержек опроса сообщения от Arduino могут выходить на 4-8 мкс на такт.
  • Точность тактовой частоты Arduino. Из изображений на веб-сайте Elegoo видно, что в их платах используются резонаторы из керамики c, которые менее стабильны и точны, чем кристаллы. не имеет значения , если Arduino является «проводником», отправляющим тактовый сигнал. Я предполагаю, что светодиод на подключенном MIDI-устройстве не получает свою частоту из сигнала синхронизации MIDI Arduino.
0 голосов
/ 08 мая 2020

Скрипт вычисляет время следующего сообщения относительно времени, когда фактически было отправлено предыдущее сообщение. Это означает, что любые задержки будут суммироваться.

Вместо этого вычислите следующее время как фиксированный интервал с момента, когда должно было быть отправлено последнее сообщение:

...