Синхронизация вывода и обработки

b707
Offline
Зарегистрирован: 26.05.2017

Юрий48 пишет:

Возник такой вопрос, связанный с прерыванием. Tаймер 3 работает в режиме компарирования с триггерным выходом. Если я правильно понял, то организовать прерывание можно только от переполнения счётчика.

не только по переполнению, есть прерывание по совпадению в зависимости от бита CC1IE

Вы бы даташиты открыли и читали все как есть, вместо того чтоб предполагать...

Юрий48
Offline
Зарегистрирован: 19.06.2018

b707 пишет:
не только по переполнению, есть прерывание по совпадению в зависимости от бита CC1IE

Вы бы даташиты открыли и читали все как есть, вместо того чтоб предполагать...

Спасибо. Даташиты на английском, а у Мартина М сказано только о переполнении, но зто не оправдание. Проблема в том, что прерывания CC1IE формируются до триггера, поэтому к какому фронту они конкретно относятся сказать нельзя. Какое тут лучшее решение?

nik182
Offline
Зарегистрирован: 04.05.2015

Юрий48 пишет:

Проблема в том, что прерывания CC1IE формируются до триггера, поэтому к какому фронту они конкретно относятся сказать нельзя. 

 

Если вы не читали datasheet то откуда такое смелое утверждение? Все прерывания генерируемые таймером относятся к конкретным, точно прогнозируемым событиям. Что такое триггер в вашем понимании?

b707
Offline
Зарегистрирован: 26.05.2017

Юрий48 - у вас как с английским? - а то могу порекомендовать найти вот эту книжку -

Carmine Noviello Mastering STM32

в интернете она есть - очень подробное описание всех особенностей CTM32 вполне понятным языком. Отличное дополнение к даташиту. Более 800 страниц, куча примеров на основе Куба. и совсем свежая - 2017г

Правда перевода нет, только английский

Юрий48
Offline
Зарегистрирован: 19.06.2018

nik182 пишет:

Если вы не читали datasheet то откуда такое смелое утверждение? Все прерывания генерируемые таймером относятся к конкретным, точно прогнозируемым событиям. Что такое триггер в вашем понимании?

Я смотрю на Figure 1. TIM1 timer-peripheral block diagram из документа AN4776 и вижу, что события CCxI идут сразу после Capture/Compare 1 register вместе с OC1Ref, который в свою очередь уходит на триггер (это в триггерном режиме). И получается, что по отношению к выходному сигналу, эти события идут по каждому фронту выходного сигнала. Ну и как тут сказать, что текущее событие относится именно к положительному фронту. Хорошо раскажу, что такое триггер "в моём понимании". Самый простой, а их много, это пришёл импульс на вход - на выходе, скажем по положительному фронту изменилось состояние на противоположное. Если в Hal есть функция, которая генерирует прерывание по сигналу именно с выхода, и при этом от программируемого фронта, то я прошу прощения и не добивайте меня окончательно.

b707
Offline
Зарегистрирован: 26.05.2017

Юрий, какие нафик, положительные фронты?? :) Вы о чем вообще? вы понимаете, что прерывание по совпадению или по переполнению - это чисто математический процесс совпадения двух чисел? - там нет никких фронтов...

Юрий48
Offline
Зарегистрирован: 19.06.2018

b707 пишет:

Юрий48 - у вас как с английским? - а то могу порекомендовать найти вот эту книжку -

Прямо в точку. Именно из за этого у меня основная часть проблемм. Скажу честно. Как это меня тормозило по работе, хотя и добился не малого. А за книжку большое спасибо., наверное, там  много интересныых картинок. Но опять же сам мучаюсь, вас мучаю, но эта работа чисто эпизодическая, хотя, не скрою, интересная.

Юрий48
Offline
Зарегистрирован: 19.06.2018

b707 пишет:

Юрий, какие нафик, положительные фронты?? :) Вы о чем вообще? вы понимаете, что прерывание по совпадению или по переполнению - это чисто математический процесс совпадения двух чисел? - там нет никких фронтов...

Но не сердитесь так. Меня то интересует вопрос и я говорил всё в этом ключе, что можно ли организовать прерывание по положительному фронту ВЫХОДНОГО сигнала.

nik182
Offline
Зарегистрирован: 04.05.2015

https://m.vk.com/wall-51126445%3Fq%3D%2523stm&ved=2ahUKEwjTxICCyqLfAhWFjSwKHQBcA20QFjACegQIChAB&usg=AOvVaw2jLUtHP5kggNwmeDwg2d2eут нашёл книжку, а к ней прицепом книгу по stm8 на русском. Таймеры stm8 точно такие же как и stm32. Да и другое оборудование в основном похоже. Почитайте.

nik182
Offline
Зарегистрирован: 04.05.2015

Положительный фронт выходного сигнала програмируете вы при наступлении события равенства счетчика и канала. Запрограмируете положительный - будет положительный и никакого другого. Событие вызывает прерывание и другие запрограмированные вещи, а ни как не наоборот. Это основа. От неё и пляшем.

a5021
Offline
Зарегистрирован: 07.07.2013

Юрий48 пишет:

Возник такой вопрос, связанный с прерыванием. Tаймер 3 работает в режиме компарирования с триггерным выходом. Если я правильно понял, то организовать прерывание можно только от переполнения счётчика. По отношению к выходу это получается на каждый фронт выходного сигнала. Но мне надо сделать прерывание только от положительного фронта выхода канала 1. Единственный вариант, который пришёл в голову, это с этого выхода кинуть перемычку на какой либо другой вход и уж от него организовывать прерывание. Не в открытую ли дверь я ломлюсь?

Если бы это был TIM1 или TIM8, то там имеется, как раз для таких случаев, регистр TIMx_RCR -- Repetition counter. Когда в нем находится значение больше нуля, то вместо того, чтобы вызывать прерывание по переполнению счетчика, таймер уменьшает значение TIMx_RCR на единицу и перезапускает счет. Прерывание генерируется только тогда, когда значением TIMx_RCR достигнет нуля. Данный механизм позволяет пропускать перывания и делить частоту их следования.

Я сильно не вникал в вашу задачу, но если вы сможете заменить таймер 3 таймером 1, то данный функционал станет вам доступен.

Юрий48
Offline
Зарегистрирован: 19.06.2018

nik182 пишет:
Положительный фронт выходного сигнала програмируете вы при наступлении события равенства счетчика и канала. Запрограмируете положительный - будет положительный и никакого другого. Событие вызывает прерывание и другие запрограмированные вещи, а ни как не наоборот. Это основа. От неё и пляшем.

По мимо этого я использую (и это для меня принципиально) для получения меандра режим Toggle on match. В этом режиме частота выходного сигнала в два раза меньше частоты компарирования, то есть формирования события. А говорить о программировании положительного или отрицательного фронта можно только по отношению к старту таймера. И в этом случае однозначно говорить о положительном или отрицательном фронтах выходного сигнала можно, если отслеживать чётность или не чётность прерывания от начала старта таймера, но кто и как это будет делать. А за информацию большое спасибо. её то мне и не хватает. Правда этот djvu совсем не читаемый. Может , это только у меня всё не так.

b707
Offline
Зарегистрирован: 26.05.2017

Юрий48 пишет:

Правда этот djvu совсем не читаемый. Может , это только у меня всё не так.

"нечитаемый" - это значит не открывается или открывается, но качество плохое?

У меня файл открывается нормально, а что касается качество - то читать можно и ладно.

Юрий48
Offline
Зарегистрирован: 19.06.2018

b707 пишет:

"нечитаемый" - это значит не открывается или открывается, но качество плохое?

У меня файл открывается нормально, а что касается качество - то читать можно и ладно.

Скачал другую читалку и мне стало счастливо.

Юрий48
Offline
Зарегистрирован: 19.06.2018

a5021 пишет:

Если бы это был TIM1 или TIM8, то там имеется, как раз для таких случаев, регистр TIMx_RCR -- Repetition counter. Когда в нем находится значение больше нуля, то вместо того, чтобы вызывать прерывание по переполнению счетчика, таймер уменьшает значение TIMx_RCR на единицу и перезапускает счет. Прерывание генерируется только тогда, когда значением TIMx_RCR достигнет нуля. Данный механизм позволяет пропускать перывания и делить частоту их следования.

Я сильно не вникал в вашу задачу, но если вы сможете заменить таймер 3 таймером 1, то данный функционал станет вам доступен.

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

a5021
Offline
Зарегистрирован: 07.07.2013

Что значит на какой фронт? У вас регистр считает вверх и вниз, если я правильно понял. Нечетные прерывания -- это когда досчитал до MAX, четные, когда до 0. Могу путать, но вроде еще можно на бит DIR регистра TIMx_CR1 ориентироваться. Его значение указывает, куда в данный момент счет идет.

Если нужно, чтобы прерывание было смещено относительно точек MIN и 0, то в прерывании по переполнению можно не делать ничего, кроме разрешения прерывания по  COMPARE MATCH одного из каналов. Тогда при следующем совпадении этого канала бдует генерироваться прерывание, которое и будет запускать нужные задачи. Когда код обработчика закончит основные действия, нужно вновь запретить это прерывание.

Юрий48
Offline
Зарегистрирован: 19.06.2018

a5021 пишет:

Что значит на какой фронт? У вас регистр считает вверх и вниз, если я правильно понял. Нечетные прерывания -- это когда досчитал до MAX, четные, когда до 0. Могу путать, но вроде еще можно на бит DIR регистра TIMx_CR1 ориентироваться. Его значение указывает, куда в данный момент счет идет.

Если нужно, чтобы прерывание было смещено относительно точек MIN и 0, то в прерывании по переполнению можно не делать ничего, кроме разрешения прерывания по  COMPARE MATCH одного из каналов. Тогда при следующем совпадении этого канала бдует генерироваться прерывание, которое и будет запускать нужные задачи. Когда код обработчика закончит основные действия, нужно вновь запретить это прерывание.

Начиная с поста 126 речь идёт о структуре, изложенной в посте 54. В которой генерация квадратурного сигнала осуществлена по варианту, предложенному mixail844 в посте 44. Он дал такую ссылку.  Это вариант где таймер работает в режиме компарирования с Toggle on match. То есть тут счёт идёт только в одну сторону, а меандр получается именно за счёт Toggle on match.

a5021
Offline
Зарегистрирован: 07.07.2013

Когда у вас таймер стартует, его состояние известно. Не представляет никакого труда отслеживать количество Compare Match, чтобы знать текущее состояние выхода.

nik182
Offline
Зарегистрирован: 04.05.2015

Прочитать состояние выходной ноги это 1 команда, с проверкой не займёт более 0.2 мкс. 

Юрий48
Offline
Зарегистрирован: 19.06.2018

a5021 пишет:

Когда у вас таймер стартует, его состояние известно. Не представляет никакого труда отслеживать количество Compare Match, чтобы знать текущее состояние выхода.

Это надо делать программно и об этом уже говорилось, может, так и придётся делать. Но пока ищется путь красивого решения - чисто аппаратный.

nik182 пишет:

Прочитать состояние выходной ноги это 1 команда, с проверкой не займёт более 0.2 мкс.

Это первое, что приходит в голову. Но поскольку это надо будет уже делать программно, где гарантия того, что состояние выхода прочитается после того как оно будет изменено, а не до того или наоборот? Конечно для гарантии можно сделать небольшую задержечку на чтение.

 

a5021
Offline
Зарегистрирован: 07.07.2013

Юрий48 пишет:

Это надо делать программно и об этом уже говорилось, может, так и придётся делать. Но пока ищется путь красивого решения - чисто аппаратный.

Чисто аппаратный я вам уже озвучил -- Repetition Counter.

Юрий48
Offline
Зарегистрирован: 19.06.2018

a5021 пишет:

Чисто аппаратный я вам уже озвучил -- Repetition Counter.

Тут тоже есть проблеммы, см. пост 165. Видимо, я не сумел их внятно изложить.

a5021
Offline
Зарегистрирован: 07.07.2013

Больше похоже, что вы пока внятно не поняли технику использования TIMx_RCR. С его помощью, без всяких проблем, можно организовать, чтобы событие возникало только в момент переключения выхода с низкого в высокое состояние, либо наоборот. Будучи однажды запущенным, сконфигурированный соответствующим образом таймер, обеспечивает нужный функционал полностью аппаратно, т.е. без выполнения какого-либо кода процессором.

Юрий48
Offline
Зарегистрирован: 19.06.2018

a5021 пишет:

Больше похоже, что вы пока внятно не поняли технику использования TIMx_RCR. С его помощью, без всяких проблем, можно организовать, чтобы событие возникало только в момент переключения выхода с низкого в высокое состояние, либо наоборот. Будучи однажды запущенным, сконфигурированный соответствующим образом таймер, обеспечивает нужный функционал полностью аппаратно, т.е. без выполнения какого-либо кода процессором.

a5021, извините. Отослал не на тот пост. Надо было писать не 162, а 165. Это уже исправил. А так согласен, вариант имеет право на жизнь. Но тут прикол в том, что, посмотрев ещё раз свой алгоритм обработки сигнала, увидел, что результат не зависит от того, к какому фронту будут привязаны вычисления. Главное, что бы к одному сигналу. Промежуточные вычисления будут зависеть, а окончательный результат нет. Так что у всех прошу прощения. Хотя думается, что эта часть переписки не была безполезной.

Юрий48
Offline
Зарегистрирован: 19.06.2018

Не понятный дублёж.

Юрий48
Offline
Зарегистрирован: 19.06.2018

Опять дублёж

nik182
Offline
Зарегистрирован: 04.05.2015

Я уже писал, что в микропроцессоре нет ничего неопределённого. Не может где-то лишний тик набежать, чтобы фронт перевернуть. Задали дважды четное количество тактов - на тогле получите четное количество переворотов - т.е. фронт будет тот же.   

Юрий48
Offline
Зарегистрирован: 19.06.2018

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

if (HAL_ADC_Start_DMA(&hadc1,
                                   (uint32_t *)aADCConvertedValues,
                                    ADCCONVERTEDVALUES_BUFFER_SIZE
                                  ) != HAL_OK)
          {
            /* Start Error */
             Error_Handler();
          }
  HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
  TIM3->PSC = n_4_ - 1;
  HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_1);
  HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_2);

Когда запуск DMA переместил за старты таймеров, результаты пошли правильные, но радость была не долгой. При другом количестве импульсов на период опять возникла таже ситуация с дополнительной точкой в начале массива. Решил принудительно запускать DMA по возникновению фронта с разным количеством пропускаемых фронтов (код ниже). Но это не помогло. Где собака порылась?

  HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
  TIM3->PSC = n_4_ - 1;
  HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_1);
  HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_2);
  
     for (int i=0; i<2; i++)
      {
        TIM3->SR = ~TIM_SR_CC1IF;  
        while(!(TIM3->SR & TIM_SR_CC1IF))
        {}
      }
        TIM3->SR = ~TIM_SR_CC1IF;
        if (HAL_ADC_Start_DMA(&hadc1,
                                   (uint32_t *)aADCConvertedValues,
                                    ADCCONVERTEDVALUES_BUFFER_SIZE
                                  ) != HAL_OK)
          {
            /* Start Error */
             Error_Handler();
          }

 

nik182
Offline
Зарегистрирован: 04.05.2015

А АЦП чем тактируется? DMA вообще не причём. Это только способ передачи данных АЦП в память. Первая строка это не старт DMA. Это запуск АЦП. Вот с запуском и тактированием АЦП и надо разбираться. А так вообще прикольно. Особенно костыль в одиннадцатой (третьей) строке. Работает да и ладно.

Юрий48
Offline
Зарегистрирован: 19.06.2018

nik182 пишет:

А АЦП чем тактируется? DMA вообще не причём. Это только способ передачи данных АЦП в память. Первая строка это не старт DMA. Это запуск АЦП. Вот с запуском и тактированием АЦП и надо разбираться. А так вообще прикольно. Особенно костыль в одиннадцатой (третьей) строке. Работает да и ладно.

Хорошо, всё равно не понятно. Ведь я  отлавливаю фронт генератора, а потом запускаю АЦП. Какие при этом могут быть причины попадания импульса до фронта. Что то у меня не то в этом отлавливании или другое. Правда, возможен такой вариант. АЦП то стартует после фронта, но пока это происходит пропускается часть тактирующих импульсов, ну, и случайно попадает на предпоследний. Попробую как то это проверить, но уже вечерком. А вообще крутится такой вариант - не знаю на сколько он возможен. Генератор и АЦП крутятся постоянно, а старт работы DMA - в нужный момент, скажем по фронту генератора.

nik182
Offline
Зарегистрирован: 04.05.2015

Я ж написал только что. DMA нельзя стартануть. Можно дать разрешение передавать информацию от АЦП в память. После разрешения каждый сигнал АЦП готовы данные  будет передавать в память результат. Т.е. Последовательность действий - заряжается АЦП, заряжается DMA, ждём нужного момента, даём АЦП команду начать преобразование, Минимум через 1.5 такта АЦП зарядит УВХ и через 12.5 такта выдаст  результат, выставит флаг готовности. DMA возмёт данные и переместит в память. И АЦП, если запрограмировано на одно преобразование, будет ждать следующей команды запуска. Ваша задача дать эту команду в тот момент когда вам нужно получить значение вашего сигнала. Заметте, что вы получаете данные не в момент разрешения DMA, а точно в момента старта АЦП. Если АЦП уже имеет какие то данные, то после разрешения DMA вы получите первое старое значение, которое АЦП оцифровало до разрешения DMA, если АЦП разрешено и запущено  до разрешения DMA. 

    

Юрий48
Offline
Зарегистрирован: 19.06.2018

nik182, спасибо за развёрнутое разъяснение. Вобщем то я так это и представлял. Но почему же во втором варианте (пост 178) проблема остаётся? Там то всё казалось бы железно. Пришёл фронт, запустилось АЦП. А получается, что к этому моменту там уже было значение, то есть преобразование уже было. Как оно могло появиться, если АЦП ещё не было запущено. Что то тут я упускаю. Тогда какой алгоритм должен быть, что бы запись в DMA начиналась с первого импульса после фронта генератора?

nik182
Offline
Зарегистрирован: 04.05.2015

Я уже потерялся в вашей программе. Покажите проект куба и программу целиком. Надо посмотреть как АЦП инициализировано и запускается.     

Юрий48
Offline
Зарегистрирован: 19.06.2018

nik182 пишет:

Я уже потерялся в вашей программе. Покажите проект куба и программу целиком. Надо посмотреть как АЦП инициализировано и запускается.     

https://yadi.sk/d/Zz05zcHF-mGrfA

https://yadi.sk/d/B241kYoYtUebQA

 

nik182
Offline
Зарегистрирован: 04.05.2015

У меня программа вот так взлетела. 

 /* USER CODE BEGIN 2 */
  
      if (HAL_ADC_Start_DMA(&hadc1,
                                   (uint32_t *)aADCConvertedValues,
                                    ADCCONVERTEDVALUES_BUFFER_SIZE
                                  ) != HAL_OK)
          {
            /* Start Error */
             Error_Handler();
          }
    
  TIM3->PSC = n_4_ - 1;
  HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_1);
  HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_2);
  
  //HAL_TIM_Base_Start(&htim2);
  HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);

Сначала запускаем АЦП, потом таймер 3 ( он всё равно тактуется от второго) и наконец запуск второго и всё работает без потерь тиков.  

Юрий48
Offline
Зарегистрирован: 19.06.2018

nik182 пишет:

У меня программа вот так взлетела.

Сначала запускаем АЦП, потом таймер 3 ( он всё равно тактуется от второго) и наконец запуск второго и всё работает без потерь тиков.  

nik182, огромное спасибо. Вы как палочка выручалочка. Всего делов то. Я как то не сомневался, что всё достаточно просто, но сам дойти не смог. Этот этап игры с большим трудом, но с вашей помощью прошёл. На какую же ступень я поднялся? Следующие этапы это освоение LCD дисплея и вывод по COM порту. А за тем непременно надо замахнуться на TFT дисплей. Но всё это уже другие темы.

Тед
Offline
Зарегистрирован: 06.11.2017
// 12.5 kHz

HardwareTimer pwmtimer3(3);
HardwareTimer pwmtimer2(2);

void setup() {
  pinMode(PA7, PWM);
  pwmtimer3.pause();
  pwmtimer3.setPrescaleFactor(1);       
  pwmtimer3.setOverflow(5760 - 1);         
  pwmtimer3.setCompare(TIMER_CH2, 2880);  
  pwmtimer3.refresh();
  pwmtimer3.resume();
  delay(50); // регулировка фазового сдвига
  pinMode(PA3, PWM);
  pwmtimer2.pause();
  pwmtimer2.setPrescaleFactor(1);       
  pwmtimer2.setOverflow(5760- 1);          
  pwmtimer2.setCompare(TIMER_CH4, 2880);  
  pwmtimer2.refresh();
  pwmtimer2.resume();
}

void loop() {
}

 

nik182
Offline
Зарегистрирован: 04.05.2015

Юрий у меня вопрос. Вы в ТЗ писали про 80 мс, а у меня получается 16. Это нормально? 

Юрий48
Offline
Зарегистрирован: 19.06.2018

nik182 пишет:

Юрий у меня вопрос. Вы в ТЗ писали про 80 мс, а у меня получается 16. Это нормально? 

То, что писалось в ТЗ это предельные параметры. Что будет на самом деле я пока не знаю, всё ещё в переди - исследования покажут, пока придут микросхемы, связанные с аналоговой частью. А пока структура и сама программа делалась так, что бы было удобно менять частоту генератора, количество оцифровки на период и их фазовый сдвиг относительно сигнала генератора. На данном этапе я считаю, что цель достигнута. А то, что получилось 16 мс, это просто последний вариант проверки без привязки к чему то реальному. Спассибо за беспокойство.

Тед, Лаконично, но для меня пока ещё трудно читаемо. Чего не хватает в большенстве примеров, которые я смотрел так это пояснений, коментарий.

Юрий48
Offline
Зарегистрирован: 19.06.2018

Продолжение следует. За это время по моим меркам добился многого. Дисплей подключил и вижу на нём данные, научился принимать и передавать данные по COM порту, на ПК вижу сигнал и сделал свой удобный интерфейс для передачи параметров таймеров для проведения эксперементов. Данные передаются и подписываются в таймера првильно, сигнал адекватно меняется - его вижу на ПК. Но вот незадача - синхронизация о которой я так пекусь разлетается и это понятно - ведь параметры подписываюся  асинхронно. Какие действия я вижу, что бы обеспечить требования, выдвинутые мной в начале?

1. Остановить таймера. Я так понимаю, что в соответствии со структурой из поста 178 достаточно остановить таймер Т2

2. Прописать в таймера все необходимые параметры, включая исходные состояния выходов.

3. Обнулить счётчики таймеров.

4. Сбросить счётчик DMA

5. Запустить таймера. Эта часть усилиями nik182  уже есть.

6. Может ещё чего, что упустил.

Пошёл следующим путём, может, не очень красивым, но, как мне кажется, "железным". Взял Кубовские функции инициации таймеров, переименовал их и прописал в соответствующих местах вместо констант, задаваемых Кубом, требуемые переменные. Это работает, но синхронизации как не было, так и нет.  В качестве останова таймеров использовал функции, см.код.

void Init_TIM (void)
      {
        //__HAL_TIM_DISABLE(&htim2);
        HAL_TIM_OC_MspDeInit(&htim2);
        HAL_TIM_OC_MspDeInit(&htim3);
        MX_DMA_Init();
        Moi_TIM2_Init();
        Moi_TIM3_Init();
        MX_ADC1_Init();
        //HAL_TIM_Base_Start(&htim2);
        if (HAL_ADC_Start_DMA(&hadc1,
                                   (uint32_t *)aADCConvertedValues,
                                    ADCCONVERTEDVALUES_BUFFER_SIZE
                                  ) != HAL_OK)
          {
            /* Start Error */
             Error_Handler();
          }
        HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_1);
        HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_2);
          
        HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);
        HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
      }

Что не так?

Юрий48
Offline
Зарегистрирован: 19.06.2018

Так и не получается побороть эту проблемму, хотя чего только не перепробовал за это время. Ещё на двух форумах поднял эту тему, но ничего путного не получил. nik182, если есть возможность, пожалуйста посмотрите эту тему.

nik182
Offline
Зарегистрирован: 04.05.2015

Посмотрел. Сейчас я не могу вникать глубоко, по крайней мере ещё 2 недели. Ваша проблема мне была понятна ещё с вашей прошлой реализации. У вас несинхронно работают таймеры. Вам повезло случайно запустится так, что получилось примерно то что вы хотели, но сама идея такой работы таймеров ущербна. При любой смене параметров у вас должна получаться чушь. Я не зря предлагал использовать три таймера. При этом два из них должны запускаться от третьего. Только в этом случае можно менять как угодно параметры. И писать надо на LL а не на HAL. На HAL этого ни как не сделать. Причину я описал раньше. 

Юрий48
Offline
Зарегистрирован: 19.06.2018

Есть положительный результат, но с некоторым ограничением. Небольшое резюме.

1. Генерация квадратурного сигнала (меандр) с заданой частотой. Работает без вопросов.

2. Генерация импульсов, запускающих АЦП, с необходимым количеством импульсов на период генератора и возможностью задавать необходимый сдвиг относительно фронта генератора квадратурного сигнала (положительный фронт первого канала) . Работает без вопросов.

3. Циклическая буфиризация результатов преобразования АЦП с помощью DMA так, чтобы начало буфера совпадало с фронтом генератора (тот же положительный фронт первого канала). Вот тут то и происходят все пляски, имеется ввиду синхронизация начала заполнения буфера с фронтом генератора.

Основным мотивом решения проблемы было замораживание DMA и таймеров, прописывание в них новых требуемых значений предделителей, автоперезагрузки и уровней компарирования с последующей активацией таймеров и DMA. Пробовал кучу вариантов, но ничего путного не получил. В результате решил откатить на запасные окопы. Это - по прерыванию ловить фронт генератора и инициализировать в этот момент буфер DMA или инициализацию не делать, а считывать значение его счётчика и использовать его для коррекции синхронизации. Другими словами таким образом определять номер точки в буфере, соответствующей требуемому фронту генератора. Вот тут то началось что то осмысленное. При чём два последних варианта оказались равнозначными - остановился на втором как более простом. Немного поподробнее. После прописывания всех изменённых параметров (оперативно без всяких остановок) выставляю признак, что изменения сделаны, и, когда он появляется в обработчеке прерывания компаратора первого канала таймера3 (фаза А), тогда считываю значение счётчика DMA. А, чтобы это точно был положительный фронт, то ещё проверяю состояние выхода второго канала этого таймера (фаза Б) Это работает, но что интересно. Если считывать значение счётчика DMA сразу после появления признака изменения данных, то положительного результата нет. Но, если пропускать более двух периодов генератора, то получается правильный сто процентный результат вне зависимости от изменяемых параметров, что очень хорошо. Казалось бы вопрос закрыт, но вот ещё одна интересная заковыка. Всё идёт хорошо пока частота опроса АЦП ниже ~72 кГц. Но  стоит частоту повысить, как появляется дополнительный сдвиг на 2 импульса. При чём, что удивительно - происходит это скачком, а не плавно в зависимости от частоты. Или это сдвиг 0 или 2, если частота опроса АЦП больше 72 кГц. И второе этот сдвиг больше ни отчего не зависит. Я имею ввиду не зависит от параметров, которые я изменяю. Если кто смог дочитать эту писанину до конца и имеет свои мысли почему такое происходит, то, пожалуйста, расскжите о своих соображениях.

1. почему для устаканивания необходимо два периода генератора квадратурного сигнала?

2. с чем связан скачёк в 2 импульса?

gena321
Offline
Зарегистрирован: 19.01.2019

dimax пишет:

 

 void setup() {
pinMode(PA8,PWM); 
pinMode(PA9,PWM); 
RCC_BASE->APB2RSTR |= 1<<11; //reset timer 1
RCC_BASE->APB2RSTR&= ~(1<<11); 
TIMER1_BASE->CCER=(1<<4)|(1<<0);//cc1e/cc2e enable 
TIMER1_BASE->CCMR1=(1<<13)|(1<<12)|(1<<5)|(1<<4);//toogle mode 
TIMER1_BASE->PSC=0;
TIMER1_BASE->ARR=2879;
TIMER1_BASE->CCR1=0 ;
TIMER1_BASE->CCR2=1439 ;
TIMER1_BASE->BDTR= 1<<14; //Automatic output enable
TIMER1_BASE->CCMR1=(1<<13)|(1<<12)|(1<<5)|(1<<4);//toogle mode 
TIMER1_BASE->CR2= 1<<10 | 1<<8 ; // SET output idle state OC1, OC2 = HIGH
delay(5000);
TIMER1_BASE->CR1=1;
}

Захватил осциллом момент старта генерации:

 

[/quote]

А как добавить еще один канал выход на