Защита от переполнения в функции задержки

В моем проекте есть небольшая функция задержки, которую я написал сам, используя периферийное устройство таймера моего MCU:

статическая недействительная задержка100Us (недействительная)

{
  uint_64 ctr = TIMER_read(0); //10ns resolution
  uint_64 ctr2 = ctr + 10000;
  while(ctr <= ctr2) //wait 100 microseconds(10000)
  {
      ctr = TIMER_read(0);
  }
}

Счетчик представляет собой автономный аппаратный счетчик с разрешением 10 нс, поэтому я написал эту функцию так, чтобы она давала задержку примерно в 100 мкс. Я думаю, что это должно работать в принципе, однако может возникнуть ситуация, когда таймер меньше 10000 из-за переполнения, и поэтому ctr2 будет присвоено значение, которое больше, чем может фактически достичь ctr, и поэтому я бы в конечном итоге застрял в бесконечном цикле .

Мне нужно сгенерировать задержку, используя этот таймер в моем проекте, поэтому мне нужно как-то убедиться, что я всегда получаю одну и ту же задержку (100 мкс), и в то же время защитить себя от застревания там.

Есть ли способ сделать это или это просто ограничение, которое я не могу обойти?

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

Редактировать:

ctr_start = TimerRead(); //get initial value for the counter
interval = TimerRead() - ctr_start;
while(interval <= 10000)
{
  interval = ( TimerRead() - ctr_start  + countersize ) % countersize;
}

Where countersize = 0xFFFFFFFFFFFFFFFF;

person Cantaff0rd    schedule 28.01.2021    source источник
comment
Если счетчик не имеет знака, он должен быть обернут. Посмотрите на прошедший интервал мод максимальное значение счетчика. Время истекло, когда интервал равен (здесь) › 10000. interval = (timer - ctr + countersize) % countersize Если это 64-битный счетчик, то interval = timer - ctr. Выполните арифметические действия перед проверкой интервала (чтобы арифметические действия переносились).   -  person Weather Vane    schedule 28.01.2021
comment
Максимальное значение 64 бита равно 0xFFFFFFFFFFFFFFFF. IMO, лучше всего использовать счетчик свободного хода с общим периодом, превышающим максимальный, который вам когда-либо понадобится. Если счетчик 64-битный, то все просто. Отметьте начальное значение, затем вычислите истекший интервал и сравните его. Используйте >=, чтобы вам не нужно было улавливать точное значение. Если это 32-битный счетчик, используйте типы uint32_t и т. д.   -  person Weather Vane    schedule 28.01.2021
comment
... так что не вычисляйте цель, как вы сделали, работайте с прошедшим интервалом.   -  person Weather Vane    schedule 28.01.2021
comment
Хорошо, спасибо, я изменил это следующим образом: см. Исходное редактирование сообщения.   -  person Cantaff0rd    schedule 01.02.2021
comment
@WeatherVane Думаю, я понял ваше решение, если правильно то, что я отредактировал в основном посте, можете ли вы ответить, чтобы я мог принять его как ответ?   -  person Cantaff0rd    schedule 01.02.2021
comment
Возможно, вы могли бы сбросить таймер, а затем заставить программу ждать.   -  person linuxfan says Reinstate Monica    schedule 01.02.2021


Ответы (1)


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

Один из способов избежать этой проблемы — рассмотреть прошедший интервал с unsigned переменными и арифметическими действиями. Их поведение четко определено при переносе значений.

Аппаратный счетчик почти всегда имеет размер 8, 16, 32 или 64 бита, поэтому выберите подходящий тип переменной. Предположим, что счетчик 32-битный:

void delay(uint32_t period)
{
    uint32_t mark = TIMER_read(0);
    uint32_t interval;
    do {
        interval = TIMER_read(0) - mark;    // underflow is well defined
    } while(interval < period);
}

Очевидно, что требуемый период должен быть меньше периода счетчика. Если нет, либо масштабируйте часы таймера, либо используйте другой метод (например, счетчик, поддерживаемый прерыванием).

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

person Weather Vane    schedule 01.02.2021