Точная задержка между двумя короткими импульсами

Не проверял, но скорее всего там адрес OCR1A который как бы “первый”, из которого потом запишется в другой с которым уже идет сравнение.

Если стоп без старта несущественен, можно автоматом формировать стоп-старт-стоп, во время формирования первого стопа записывая значения OCR.

Есть, но это адрес буферизованного регистра.
Думаю, раз в даташите написано, что в FastPWM режиме OCR1A обновляется только при переходе таймера через TOP/BOTTOM - то никак вы это не обойдете.
Да и зачем? Регистр ICR1 не имеет такого ограничения, он обновляется сразу. Замена одного варианта на другой - один бит в настройке режима таймера. Вы можете взять свой код и использовать его с ICR1

OCR обновляется не при старт-стопе, а при прохождении счетчика таймера через TOP/BOTTOM

Я про это же. На выходе имеем 2 импульса - старт и стоп. Стоп формируем с помощью таймера с прохождением через TOP. Первый стоповый фиктивный, во время его формирования записываем новое значение OCR, пока не достигли ТОП. После этого формируем стартовый импульс и через время заданное с помощью (уже требуемого) OCR, стоповый.

А с чем связаны эти выбросы: с переводом пина, настроенного на выход, в ноль или с переводом пина в высокоимпедансное состояние?
Если второе - выброс можно устранить внешней подтяжкой. Если первое - можно попытаться так переконфигурировать пин, чтобы в предполагаемый момент выброса он был настроен на вход (и свести тем самым первый вариант ко второму).

Это я ввел всех в заблуждение. Нет там выбросов, если даташит читать внимательно :slight_smile:
см код в следующем сообщении

Переделал
Теперь импульсы подаются всегда в одном порядке - AB - AB - AB…
Чтобы можно было управлять интервалом, добавил функцию генерации pulse_train(uint16_t pp) с параметром, равным задержке между импульсами. Каждый раз можете вызывать функцию с новой задержкой. Число вызовов не ограничено, главное не вызывать функцию раньше, чем завершила работу прежняя. Длительность работы функции - 4х кратная задержка между импульсами.

// interval between first pulse falling edge 
// and raising edge of the second pulse (in timer ticks)
volatile uint16_t period =1000;

volatile uint8_t cc =1;
void setup() {
  
  DDRB |= (1<<PB1) | (1<<PB2);
  PORTB |= (1<<PB1) | (1<<PB2);
  
  cli(); //stop interrupts for till we make the settings

  TCCR1A = 0; // Reset entire TCCR1A to 0
  TCCR1B = 0; // Reset entire TCCR1B to 0
  TCNT1 = 0; //reset clock value

  ////set to fast PWM mode 14 via WGM bits(count from 0 to ICR1):
  ////TOP = ICR1 
  TCCR1A |= (0 << WGM10) | (1 << WGM11) ;
  TCCR1B |= (1 << WGM12) | (1 << WGM13) ;

  ////Timer/Counter1 Interrupt Mask Register:
  TIMSK1 |= (1 << OCIE1A); // enable compare OCR1A itrerrupt 
  TIMSK1 |= (1 << OCIE1B); // enable compare OCR1B itrerrupt 
  //TIMSK1 |= (1 << TOIE1); //enable overflow vector interrupt
  

  OCR1A = period - 1; //match 1 tick before TOP 
  ICR1 = period;      //top value
  OCR1B = 0xFFFE;          // never match value
  
  //Clear OC1A/OC1B on Compare Match, set OC1A/OC1B at
  // BOTTOM (non-inverting PWM mode)
  TCCR1A |=  (1 << COM1A1) | (1 << COM1B1);
  // clear all irq flags
  TIFR1  = B111; // (1<<TOV1)| (1<< OCFB) |(1<< OCFA);;
  sei();
  TCCR1B|= 1;  //start timer at 16 MHz, no prescaling
 
}

ISR(TIMER1_COMPB_vect) {
 OCR1A = period -1;                // match 1 tick before TOP
 OCR1B = 0xFFFE;                  // never match value
 TCCR1A &=  ~((1 << COM1A1) | (1 << COM1B1));  // disable pin outputs
}

ISR(TIMER1_COMPA_vect) {
 OCR1A = 0xFFFE;                // never match value
 OCR1B = period -1;            // match 1 tick before TOP
 ICR1 = period;
 if (cc) TCCR1B &= ~bit(0);  // stop the timer
 cc++;
}

//generate impulse pairs with interval pp clock ticks
void pulse_train(uint16_t pp) {
   cc=0;
   period = pp;
   OCR1B = period -1;
   TCCR1A |=  (1 << COM1A1) | (1 << COM1B1);  // enable pin outputs
   TCCR1B|= 1;          //start timer at 16 MHz, no prescaling
}

void loop() {
static bool flag = true;
if (flag) 
 {
   delay(100);
   pulse_train(1000);
   
   delay(50);
   pulse_train(500);
   
   delay(50);
   pulse_train(1500);
   
   delay(50);
   pulse_train(600);
  
   flag = false;
 }
}
1 лайк

Попробовал немного, как то странно себя ведёт при задержке в 50тактов.
И в целом как будто останавливается после одного цикла намертво. В общем до конца не разобрался, там хитро написано, но предварительно понял, что:

  1. сработало совпадение А и задались значения для В, а так же канал А выдал импульс.
  2. после нужной задержки импульс В сработал и выставились настройки под А.

Надо сидеть разбираться , не особо много времени есть.

50 тактов я не пробовал… 500 тактов работает стабильно.

может вы вызывали функцию 2 раза подряд? - так нельзя, надо с перерывом

Насколько я вижу, вы так и не ответили на несколько раз заданный вопрос - какие именно характеристики импульсов вам нужны ? - не в тактах, а в микро или нано-секундах.

Ширина самих импульсов?
Диапазон задержки? - мин и макс?
Сколько пар импульсов надо генерить в последовательности?
Интервал между парами - минимум и максимум?

А я не понимаю почему не использовать два таймер? Второй 8 битный формирует первый импульс на одной ноге. Одновременно запускаем первый 16 битный, который через необходимую задержку формирует импульс на другой ноге. между импульсами будет всегда точная задержка.

она и на одном таймере точная получается

Тут все упирается в ТС - ему надо сесть и вдумчиво все проверить. Но ему все время некогда… решать свою проблему…
У других ведь полно свободного времени, ага…вот пусть они и думают.

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

Стартовый 100-200нс
Стоповый 100±30нс

Задержка между ними от 3 до 35 микросекунд.
Точность задержки, чем выше тем лучше. Ардуиновский шаг в 62,5нс, что бы скорректировать при необходимости нужное значение это на грани. По этому и нужна в данном случае точность а 1 такт

Всегда одна пара импульсов.

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

Перед парой будет всегда идти ещё один сигнал, но задержка между ним и парой не строгая 15-25us и длительность 700-1000нс.


Если в pulse_train забить 63 то всё ещё работает. Если 62 то выдает 2 импульса и зависает. Не выдает больше импульсов.
При 63 задержка выходит 4uS

значит это минимум. Вход в прерывание, вызов обработчика, выполнение кода и выход требует времени,
Период должен быть длиннее, чем сумма всего вышеперечисленного.

1 лайк

менять МК или аппаратное решение на микросхемах

1 лайк

+100
давно бы на СТМ32 сделали

Так и предполагал. Но все равно гениально, до такого не додумался бы:)
Сделаю тогда пока с костылем либо на fastpwm+wgm mode 15, либо можно разбить задержку: дольше 62 тактов wgm14 с вашим методом, меньше wgm15 + настроечный стоповый сигнал.

Можно каких то пару советов на последок по stm32 на чем там делать подобную задержку, что изучить, пока они идут и уже быть готовым к доработке?

Спасибо.

нет никаких советов :frowning:
таймеры в STM32 целая огромная тема, читать читать…вникать, программировать.
в Arduino IDE с STM32 не работал, поэтому пусть другие коллеги подскажут насколько там реально произвести тонкую настройку с регистрами МК.
но я б посоветовал сразу ставить STM32 Cube IDE и писать сразу на регистрах, вдумчиво читая даташит на МК.
И калокуб (HAL/CubeMX) с моей точки зрения не стоит сил на изучение, сразу пишите по уму, да, сложно, но оно стОит того.

1 лайк

Б707! Напиши мне, плз, ТЗ от ТС, как ты его понял.
Мне интересно написать это на прямой задержке. Я слышал, что нужно на низкой тактовой частоте? В качестве прокрастинации… ;))

1 лайк