Возник такой вопрос, связанный с прерыванием. Tаймер 3 работает в режиме компарирования с триггерным выходом. Если я правильно понял, то организовать прерывание можно только от переполнения счётчика.
не только по переполнению, есть прерывание по совпадению в зависимости от бита CC1IE
Вы бы даташиты открыли и читали все как есть, вместо того чтоб предполагать...
не только по переполнению, есть прерывание по совпадению в зависимости от бита CC1IE
Вы бы даташиты открыли и читали все как есть, вместо того чтоб предполагать...
Спасибо. Даташиты на английском, а у Мартина М сказано только о переполнении, но зто не оправдание. Проблема в том, что прерывания CC1IE формируются до триггера, поэтому к какому фронту они конкретно относятся сказать нельзя. Какое тут лучшее решение?
Проблема в том, что прерывания CC1IE формируются до триггера, поэтому к какому фронту они конкретно относятся сказать нельзя.
Если вы не читали datasheet то откуда такое смелое утверждение? Все прерывания генерируемые таймером относятся к конкретным, точно прогнозируемым событиям. Что такое триггер в вашем понимании?
Юрий48 - у вас как с английским? - а то могу порекомендовать найти вот эту книжку -
Carmine Noviello Mastering STM32
в интернете она есть - очень подробное описание всех особенностей CTM32 вполне понятным языком. Отличное дополнение к даташиту. Более 800 страниц, куча примеров на основе Куба. и совсем свежая - 2017г
Если вы не читали datasheet то откуда такое смелое утверждение? Все прерывания генерируемые таймером относятся к конкретным, точно прогнозируемым событиям. Что такое триггер в вашем понимании?
Я смотрю на Figure 1. TIM1 timer-peripheral block diagram из документа AN4776 и вижу, что события CCxI идут сразу после Capture/Compare 1 register вместе с OC1Ref, который в свою очередь уходит на триггер (это в триггерном режиме). И получается, что по отношению к выходному сигналу, эти события идут по каждому фронту выходного сигнала. Ну и как тут сказать, что текущее событие относится именно к положительному фронту. Хорошо раскажу, что такое триггер "в моём понимании". Самый простой, а их много, это пришёл импульс на вход - на выходе, скажем по положительному фронту изменилось состояние на противоположное. Если в Hal есть функция, которая генерирует прерывание по сигналу именно с выхода, и при этом от программируемого фронта, то я прошу прощения и не добивайте меня окончательно.
Юрий, какие нафик, положительные фронты?? :) Вы о чем вообще? вы понимаете, что прерывание по совпадению или по переполнению - это чисто математический процесс совпадения двух чисел? - там нет никких фронтов...
Юрий48 - у вас как с английским? - а то могу порекомендовать найти вот эту книжку -
Прямо в точку. Именно из за этого у меня основная часть проблемм. Скажу честно. Как это меня тормозило по работе, хотя и добился не малого. А за книжку большое спасибо., наверное, там много интересныых картинок. Но опять же сам мучаюсь, вас мучаю, но эта работа чисто эпизодическая, хотя, не скрою, интересная.
Юрий, какие нафик, положительные фронты?? :) Вы о чем вообще? вы понимаете, что прерывание по совпадению или по переполнению - это чисто математический процесс совпадения двух чисел? - там нет никких фронтов...
Но не сердитесь так. Меня то интересует вопрос и я говорил всё в этом ключе, что можно ли организовать прерывание по положительному фронту ВЫХОДНОГО сигнала.
Положительный фронт выходного сигнала програмируете вы при наступлении события равенства счетчика и канала. Запрограмируете положительный - будет положительный и никакого другого. Событие вызывает прерывание и другие запрограмированные вещи, а ни как не наоборот. Это основа. От неё и пляшем.
Возник такой вопрос, связанный с прерыванием. Tаймер 3 работает в режиме компарирования с триггерным выходом. Если я правильно понял, то организовать прерывание можно только от переполнения счётчика. По отношению к выходу это получается на каждый фронт выходного сигнала. Но мне надо сделать прерывание только от положительного фронта выхода канала 1. Единственный вариант, который пришёл в голову, это с этого выхода кинуть перемычку на какой либо другой вход и уж от него организовывать прерывание. Не в открытую ли дверь я ломлюсь?
Если бы это был TIM1 или TIM8, то там имеется, как раз для таких случаев, регистр TIMx_RCR -- Repetition counter. Когда в нем находится значение больше нуля, то вместо того, чтобы вызывать прерывание по переполнению счетчика, таймер уменьшает значение TIMx_RCR на единицу и перезапускает счет. Прерывание генерируется только тогда, когда значением TIMx_RCR достигнет нуля. Данный механизм позволяет пропускать перывания и делить частоту их следования.
Я сильно не вникал в вашу задачу, но если вы сможете заменить таймер 3 таймером 1, то данный функционал станет вам доступен.
Положительный фронт выходного сигнала програмируете вы при наступлении события равенства счетчика и канала. Запрограмируете положительный - будет положительный и никакого другого. Событие вызывает прерывание и другие запрограмированные вещи, а ни как не наоборот. Это основа. От неё и пляшем.
По мимо этого я использую (и это для меня принципиально) для получения меандра режим Toggle on match. В этом режиме частота выходного сигнала в два раза меньше частоты компарирования, то есть формирования события. А говорить о программировании положительного или отрицательного фронта можно только по отношению к старту таймера. И в этом случае однозначно говорить о положительном или отрицательном фронтах выходного сигнала можно, если отслеживать чётность или не чётность прерывания от начала старта таймера, но кто и как это будет делать. А за информацию большое спасибо. её то мне и не хватает. Правда этот djvu совсем не читаемый. Может , это только у меня всё не так.
Если бы это был TIM1 или TIM8, то там имеется, как раз для таких случаев, регистр TIMx_RCR -- Repetition counter. Когда в нем находится значение больше нуля, то вместо того, чтобы вызывать прерывание по переполнению счетчика, таймер уменьшает значение TIMx_RCR на единицу и перезапускает счет. Прерывание генерируется только тогда, когда значением TIMx_RCR достигнет нуля. Данный механизм позволяет пропускать перывания и делить частоту их следования.
Я сильно не вникал в вашу задачу, но если вы сможете заменить таймер 3 таймером 1, то данный функционал станет вам доступен.
Можно, но для рассматриваемой конфигурации делитель этого счётчика надо настраивать на два. И в этом случае частота прерывания совпадёт с частотой выходного сигнала. Но при этом на какой его фронт попадёт прерывание с ходу сказать нельзя. Вполне возможно, что их можно задать при старте. Но это ж надо понять как это сделать.
Что значит на какой фронт? У вас регистр считает вверх и вниз, если я правильно понял. Нечетные прерывания -- это когда досчитал до MAX, четные, когда до 0. Могу путать, но вроде еще можно на бит DIR регистра TIMx_CR1 ориентироваться. Его значение указывает, куда в данный момент счет идет.
Если нужно, чтобы прерывание было смещено относительно точек MIN и 0, то в прерывании по переполнению можно не делать ничего, кроме разрешения прерывания по COMPARE MATCH одного из каналов. Тогда при следующем совпадении этого канала бдует генерироваться прерывание, которое и будет запускать нужные задачи. Когда код обработчика закончит основные действия, нужно вновь запретить это прерывание.
Что значит на какой фронт? У вас регистр считает вверх и вниз, если я правильно понял. Нечетные прерывания -- это когда досчитал до MAX, четные, когда до 0. Могу путать, но вроде еще можно на бит DIR регистра TIMx_CR1 ориентироваться. Его значение указывает, куда в данный момент счет идет.
Если нужно, чтобы прерывание было смещено относительно точек MIN и 0, то в прерывании по переполнению можно не делать ничего, кроме разрешения прерывания по COMPARE MATCH одного из каналов. Тогда при следующем совпадении этого канала бдует генерироваться прерывание, которое и будет запускать нужные задачи. Когда код обработчика закончит основные действия, нужно вновь запретить это прерывание.
Начиная с поста 126 речь идёт о структуре, изложенной в посте 54. В которой генерация квадратурного сигнала осуществлена по варианту, предложенному mixail844 в посте 44. Он дал такую ссылку. Это вариант где таймер работает в режиме компарирования с Toggle on match. То есть тут счёт идёт только в одну сторону, а меандр получается именно за счёт Toggle on match.
Когда у вас таймер стартует, его состояние известно. Не представляет никакого труда отслеживать количество Compare Match, чтобы знать текущее состояние выхода.
Когда у вас таймер стартует, его состояние известно. Не представляет никакого труда отслеживать количество Compare Match, чтобы знать текущее состояние выхода.
Это надо делать программно и об этом уже говорилось, может, так и придётся делать. Но пока ищется путь красивого решения - чисто аппаратный.
nik182 пишет:
Прочитать состояние выходной ноги это 1 команда, с проверкой не займёт более 0.2 мкс.
Это первое, что приходит в голову. Но поскольку это надо будет уже делать программно, где гарантия того, что состояние выхода прочитается после того как оно будет изменено, а не до того или наоборот? Конечно для гарантии можно сделать небольшую задержечку на чтение.
Больше похоже, что вы пока внятно не поняли технику использования TIMx_RCR. С его помощью, без всяких проблем, можно организовать, чтобы событие возникало только в момент переключения выхода с низкого в высокое состояние, либо наоборот. Будучи однажды запущенным, сконфигурированный соответствующим образом таймер, обеспечивает нужный функционал полностью аппаратно, т.е. без выполнения какого-либо кода процессором.
Больше похоже, что вы пока внятно не поняли технику использования TIMx_RCR. С его помощью, без всяких проблем, можно организовать, чтобы событие возникало только в момент переключения выхода с низкого в высокое состояние, либо наоборот. Будучи однажды запущенным, сконфигурированный соответствующим образом таймер, обеспечивает нужный функционал полностью аппаратно, т.е. без выполнения какого-либо кода процессором.
a5021, извините. Отослал не на тот пост. Надо было писать не 162, а 165. Это уже исправил. А так согласен, вариант имеет право на жизнь. Но тут прикол в том, что, посмотрев ещё раз свой алгоритм обработки сигнала, увидел, что результат не зависит от того, к какому фронту будут привязаны вычисления. Главное, что бы к одному сигналу. Промежуточные вычисления будут зависеть, а окончательный результат нет. Так что у всех прошу прощения. Хотя думается, что эта часть переписки не была безполезной.
Я уже писал, что в микропроцессоре нет ничего неопределённого. Не может где-то лишний тик набежать, чтобы фронт перевернуть. Задали дважды четное количество тактов - на тогле получите четное количество переворотов - т.е. фронт будет тот же.
Продвинулся очень не плохо. Получаю данные, их обрабатываю. Но есть одна проблемма. Почему то в массиве данные начинаются с одной точки до фронта при таком коде.
Когда запуск DMA переместил за старты таймеров, результаты пошли правильные, но радость была не долгой. При другом количестве импульсов на период опять возникла таже ситуация с дополнительной точкой в начале массива. Решил принудительно запускать DMA по возникновению фронта с разным количеством пропускаемых фронтов (код ниже). Но это не помогло. Где собака порылась?
А АЦП чем тактируется? DMA вообще не причём. Это только способ передачи данных АЦП в память. Первая строка это не старт DMA. Это запуск АЦП. Вот с запуском и тактированием АЦП и надо разбираться. А так вообще прикольно. Особенно костыль в одиннадцатой (третьей) строке. Работает да и ладно.
А АЦП чем тактируется? DMA вообще не причём. Это только способ передачи данных АЦП в память. Первая строка это не старт DMA. Это запуск АЦП. Вот с запуском и тактированием АЦП и надо разбираться. А так вообще прикольно. Особенно костыль в одиннадцатой (третьей) строке. Работает да и ладно.
Хорошо, всё равно не понятно. Ведь я отлавливаю фронт генератора, а потом запускаю АЦП. Какие при этом могут быть причины попадания импульса до фронта. Что то у меня не то в этом отлавливании или другое. Правда, возможен такой вариант. АЦП то стартует после фронта, но пока это происходит пропускается часть тактирующих импульсов, ну, и случайно попадает на предпоследний. Попробую как то это проверить, но уже вечерком. А вообще крутится такой вариант - не знаю на сколько он возможен. Генератор и АЦП крутятся постоянно, а старт работы DMA - в нужный момент, скажем по фронту генератора.
Я ж написал только что. DMA нельзя стартануть. Можно дать разрешение передавать информацию от АЦП в память. После разрешения каждый сигнал АЦП готовы данные будет передавать в память результат. Т.е. Последовательность действий - заряжается АЦП, заряжается DMA, ждём нужного момента, даём АЦП команду начать преобразование, Минимум через 1.5 такта АЦП зарядит УВХ и через 12.5 такта выдаст результат, выставит флаг готовности. DMA возмёт данные и переместит в память. И АЦП, если запрограмировано на одно преобразование, будет ждать следующей команды запуска. Ваша задача дать эту команду в тот момент когда вам нужно получить значение вашего сигнала. Заметте, что вы получаете данные не в момент разрешения DMA, а точно в момента старта АЦП. Если АЦП уже имеет какие то данные, то после разрешения DMA вы получите первое старое значение, которое АЦП оцифровало до разрешения DMA, если АЦП разрешено и запущено до разрешения DMA.
nik182, спасибо за развёрнутое разъяснение. Вобщем то я так это и представлял. Но почему же во втором варианте (пост 178) проблема остаётся? Там то всё казалось бы железно. Пришёл фронт, запустилось АЦП. А получается, что к этому моменту там уже было значение, то есть преобразование уже было. Как оно могло появиться, если АЦП ещё не было запущено. Что то тут я упускаю. Тогда какой алгоритм должен быть, что бы запись в DMA начиналась с первого импульса после фронта генератора?
Сначала запускаем АЦП, потом таймер 3 ( он всё равно тактуется от второго) и наконец запуск второго и всё работает без потерь тиков.
nik182, огромное спасибо. Вы как палочка выручалочка. Всего делов то. Я как то не сомневался, что всё достаточно просто, но сам дойти не смог. Этот этап игры с большим трудом, но с вашей помощью прошёл. На какую же ступень я поднялся? Следующие этапы это освоение LCD дисплея и вывод по COM порту. А за тем непременно надо замахнуться на TFT дисплей. Но всё это уже другие темы.
Юрий у меня вопрос. Вы в ТЗ писали про 80 мс, а у меня получается 16. Это нормально?
То, что писалось в ТЗ это предельные параметры. Что будет на самом деле я пока не знаю, всё ещё в переди - исследования покажут, пока придут микросхемы, связанные с аналоговой частью. А пока структура и сама программа делалась так, что бы было удобно менять частоту генератора, количество оцифровки на период и их фазовый сдвиг относительно сигнала генератора. На данном этапе я считаю, что цель достигнута. А то, что получилось 16 мс, это просто последний вариант проверки без привязки к чему то реальному. Спассибо за беспокойство.
Тед, Лаконично, но для меня пока ещё трудно читаемо. Чего не хватает в большенстве примеров, которые я смотрел так это пояснений, коментарий.
Продолжение следует. За это время по моим меркам добился многого. Дисплей подключил и вижу на нём данные, научился принимать и передавать данные по COM порту, на ПК вижу сигнал и сделал свой удобный интерфейс для передачи параметров таймеров для проведения эксперементов. Данные передаются и подписываются в таймера првильно, сигнал адекватно меняется - его вижу на ПК. Но вот незадача - синхронизация о которой я так пекусь разлетается и это понятно - ведь параметры подписываюся асинхронно. Какие действия я вижу, что бы обеспечить требования, выдвинутые мной в начале?
1. Остановить таймера. Я так понимаю, что в соответствии со структурой из поста 178 достаточно остановить таймер Т2
2. Прописать в таймера все необходимые параметры, включая исходные состояния выходов.
3. Обнулить счётчики таймеров.
4. Сбросить счётчик DMA
5. Запустить таймера. Эта часть усилиями nik182 уже есть.
6. Может ещё чего, что упустил.
Пошёл следующим путём, может, не очень красивым, но, как мне кажется, "железным". Взял Кубовские функции инициации таймеров, переименовал их и прописал в соответствующих местах вместо констант, задаваемых Кубом, требуемые переменные. Это работает, но синхронизации как не было, так и нет. В качестве останова таймеров использовал функции, см.код.
Так и не получается побороть эту проблемму, хотя чего только не перепробовал за это время. Ещё на двух форумах поднял эту тему, но ничего путного не получил. nik182, если есть возможность, пожалуйста посмотрите эту тему.
Посмотрел. Сейчас я не могу вникать глубоко, по крайней мере ещё 2 недели. Ваша проблема мне была понятна ещё с вашей прошлой реализации. У вас несинхронно работают таймеры. Вам повезло случайно запустится так, что получилось примерно то что вы хотели, но сама идея такой работы таймеров ущербна. При любой смене параметров у вас должна получаться чушь. Я не зря предлагал использовать три таймера. При этом два из них должны запускаться от третьего. Только в этом случае можно менять как угодно параметры. И писать надо на LL а не на HAL. На HAL этого ни как не сделать. Причину я описал раньше.
Есть положительный результат, но с некоторым ограничением. Небольшое резюме.
1. Генерация квадратурного сигнала (меандр) с заданой частотой. Работает без вопросов.
2. Генерация импульсов, запускающих АЦП, с необходимым количеством импульсов на период генератора и возможностью задавать необходимый сдвиг относительно фронта генератора квадратурного сигнала (положительный фронт первого канала) . Работает без вопросов.
3. Циклическая буфиризация результатов преобразования АЦП с помощью DMA так, чтобы начало буфера совпадало с фронтом генератора (тот же положительный фронт первого канала). Вот тут то и происходят все пляски, имеется ввиду синхронизация начала заполнения буфера с фронтом генератора.
Основным мотивом решения проблемы было замораживание DMA и таймеров, прописывание в них новых требуемых значений предделителей, автоперезагрузки и уровней компарирования с последующей активацией таймеров и DMA. Пробовал кучу вариантов, но ничего путного не получил. В результате решил откатить на запасные окопы. Это - по прерыванию ловить фронт генератора и инициализировать в этот момент буфер DMA или инициализацию не делать, а считывать значение его счётчика и использовать его для коррекции синхронизации. Другими словами таким образом определять номер точки в буфере, соответствующей требуемому фронту генератора. Вот тут то началось что то осмысленное. При чём два последних варианта оказались равнозначными - остановился на втором как более простом. Немного поподробнее. После прописывания всех изменённых параметров (оперативно без всяких остановок) выставляю признак, что изменения сделаны, и, когда он появляется в обработчеке прерывания компаратора первого канала таймера3 (фаза А), тогда считываю значение счётчика DMA. А, чтобы это точно был положительный фронт, то ещё проверяю состояние выхода второго канала этого таймера (фаза Б) Это работает, но что интересно. Если считывать значение счётчика DMA сразу после появления признака изменения данных, то положительного результата нет. Но, если пропускать более двух периодов генератора, то получается правильный сто процентный результат вне зависимости от изменяемых параметров, что очень хорошо. Казалось бы вопрос закрыт, но вот ещё одна интересная заковыка. Всё идёт хорошо пока частота опроса АЦП ниже ~72 кГц. Но стоит частоту повысить, как появляется дополнительный сдвиг на 2 импульса. При чём, что удивительно - происходит это скачком, а не плавно в зависимости от частоты. Или это сдвиг 0 или 2, если частота опроса АЦП больше 72 кГц. И второе этот сдвиг больше ни отчего не зависит. Я имею ввиду не зависит от параметров, которые я изменяю. Если кто смог дочитать эту писанину до конца и имеет свои мысли почему такое происходит, то, пожалуйста, расскжите о своих соображениях.
1. почему для устаканивания необходимо два периода генератора квадратурного сигнала?
Возник такой вопрос, связанный с прерыванием. Tаймер 3 работает в режиме компарирования с триггерным выходом. Если я правильно понял, то организовать прерывание можно только от переполнения счётчика.
не только по переполнению, есть прерывание по совпадению в зависимости от бита CC1IE
Вы бы даташиты открыли и читали все как есть, вместо того чтоб предполагать...
Вы бы даташиты открыли и читали все как есть, вместо того чтоб предполагать...
Спасибо. Даташиты на английском, а у Мартина М сказано только о переполнении, но зто не оправдание. Проблема в том, что прерывания CC1IE формируются до триггера, поэтому к какому фронту они конкретно относятся сказать нельзя. Какое тут лучшее решение?
Проблема в том, что прерывания CC1IE формируются до триггера, поэтому к какому фронту они конкретно относятся сказать нельзя.
Если вы не читали datasheet то откуда такое смелое утверждение? Все прерывания генерируемые таймером относятся к конкретным, точно прогнозируемым событиям. Что такое триггер в вашем понимании?
Юрий48 - у вас как с английским? - а то могу порекомендовать найти вот эту книжку -
Carmine Noviello Mastering STM32
в интернете она есть - очень подробное описание всех особенностей CTM32 вполне понятным языком. Отличное дополнение к даташиту. Более 800 страниц, куча примеров на основе Куба. и совсем свежая - 2017г
Правда перевода нет, только английский
Если вы не читали datasheet то откуда такое смелое утверждение? Все прерывания генерируемые таймером относятся к конкретным, точно прогнозируемым событиям. Что такое триггер в вашем понимании?
Я смотрю на Figure 1. TIM1 timer-peripheral block diagram из документа AN4776 и вижу, что события CCxI идут сразу после Capture/Compare 1 register вместе с OC1Ref, который в свою очередь уходит на триггер (это в триггерном режиме). И получается, что по отношению к выходному сигналу, эти события идут по каждому фронту выходного сигнала. Ну и как тут сказать, что текущее событие относится именно к положительному фронту. Хорошо раскажу, что такое триггер "в моём понимании". Самый простой, а их много, это пришёл импульс на вход - на выходе, скажем по положительному фронту изменилось состояние на противоположное. Если в Hal есть функция, которая генерирует прерывание по сигналу именно с выхода, и при этом от программируемого фронта, то я прошу прощения и не добивайте меня окончательно.
Юрий, какие нафик, положительные фронты?? :) Вы о чем вообще? вы понимаете, что прерывание по совпадению или по переполнению - это чисто математический процесс совпадения двух чисел? - там нет никких фронтов...
Юрий48 - у вас как с английским? - а то могу порекомендовать найти вот эту книжку -
Прямо в точку. Именно из за этого у меня основная часть проблемм. Скажу честно. Как это меня тормозило по работе, хотя и добился не малого. А за книжку большое спасибо., наверное, там много интересныых картинок. Но опять же сам мучаюсь, вас мучаю, но эта работа чисто эпизодическая, хотя, не скрою, интересная.
Юрий, какие нафик, положительные фронты?? :) Вы о чем вообще? вы понимаете, что прерывание по совпадению или по переполнению - это чисто математический процесс совпадения двух чисел? - там нет никких фронтов...
https://m.vk.com/wall-51126445%3Fq%3D%2523stm&ved=2ahUKEwjTxICCyqLfAhWFjSwKHQBcA20QFjACegQIChAB&usg=AOvVaw2jLUtHP5kggNwmeDwg2d2eут нашёл книжку, а к ней прицепом книгу по stm8 на русском. Таймеры stm8 точно такие же как и stm32. Да и другое оборудование в основном похоже. Почитайте.
Положительный фронт выходного сигнала програмируете вы при наступлении события равенства счетчика и канала. Запрограмируете положительный - будет положительный и никакого другого. Событие вызывает прерывание и другие запрограмированные вещи, а ни как не наоборот. Это основа. От неё и пляшем.
Возник такой вопрос, связанный с прерыванием. Tаймер 3 работает в режиме компарирования с триггерным выходом. Если я правильно понял, то организовать прерывание можно только от переполнения счётчика. По отношению к выходу это получается на каждый фронт выходного сигнала. Но мне надо сделать прерывание только от положительного фронта выхода канала 1. Единственный вариант, который пришёл в голову, это с этого выхода кинуть перемычку на какой либо другой вход и уж от него организовывать прерывание. Не в открытую ли дверь я ломлюсь?
Если бы это был TIM1 или TIM8, то там имеется, как раз для таких случаев, регистр TIMx_RCR -- Repetition counter. Когда в нем находится значение больше нуля, то вместо того, чтобы вызывать прерывание по переполнению счетчика, таймер уменьшает значение TIMx_RCR на единицу и перезапускает счет. Прерывание генерируется только тогда, когда значением TIMx_RCR достигнет нуля. Данный механизм позволяет пропускать перывания и делить частоту их следования.
Я сильно не вникал в вашу задачу, но если вы сможете заменить таймер 3 таймером 1, то данный функционал станет вам доступен.
По мимо этого я использую (и это для меня принципиально) для получения меандра режим Toggle on match. В этом режиме частота выходного сигнала в два раза меньше частоты компарирования, то есть формирования события. А говорить о программировании положительного или отрицательного фронта можно только по отношению к старту таймера. И в этом случае однозначно говорить о положительном или отрицательном фронтах выходного сигнала можно, если отслеживать чётность или не чётность прерывания от начала старта таймера, но кто и как это будет делать. А за информацию большое спасибо. её то мне и не хватает. Правда этот djvu совсем не читаемый. Может , это только у меня всё не так.
Правда этот djvu совсем не читаемый. Может , это только у меня всё не так.
"нечитаемый" - это значит не открывается или открывается, но качество плохое?
У меня файл открывается нормально, а что касается качество - то читать можно и ладно.
"нечитаемый" - это значит не открывается или открывается, но качество плохое?
У меня файл открывается нормально, а что касается качество - то читать можно и ладно.
Скачал другую читалку и мне стало счастливо.
Если бы это был TIM1 или TIM8, то там имеется, как раз для таких случаев, регистр TIMx_RCR -- Repetition counter. Когда в нем находится значение больше нуля, то вместо того, чтобы вызывать прерывание по переполнению счетчика, таймер уменьшает значение TIMx_RCR на единицу и перезапускает счет. Прерывание генерируется только тогда, когда значением TIMx_RCR достигнет нуля. Данный механизм позволяет пропускать перывания и делить частоту их следования.
Я сильно не вникал в вашу задачу, но если вы сможете заменить таймер 3 таймером 1, то данный функционал станет вам доступен.
Можно, но для рассматриваемой конфигурации делитель этого счётчика надо настраивать на два. И в этом случае частота прерывания совпадёт с частотой выходного сигнала. Но при этом на какой его фронт попадёт прерывание с ходу сказать нельзя. Вполне возможно, что их можно задать при старте. Но это ж надо понять как это сделать.
Что значит на какой фронт? У вас регистр считает вверх и вниз, если я правильно понял. Нечетные прерывания -- это когда досчитал до MAX, четные, когда до 0. Могу путать, но вроде еще можно на бит DIR регистра TIMx_CR1 ориентироваться. Его значение указывает, куда в данный момент счет идет.
Если нужно, чтобы прерывание было смещено относительно точек MIN и 0, то в прерывании по переполнению можно не делать ничего, кроме разрешения прерывания по COMPARE MATCH одного из каналов. Тогда при следующем совпадении этого канала бдует генерироваться прерывание, которое и будет запускать нужные задачи. Когда код обработчика закончит основные действия, нужно вновь запретить это прерывание.
Что значит на какой фронт? У вас регистр считает вверх и вниз, если я правильно понял. Нечетные прерывания -- это когда досчитал до MAX, четные, когда до 0. Могу путать, но вроде еще можно на бит DIR регистра TIMx_CR1 ориентироваться. Его значение указывает, куда в данный момент счет идет.
Если нужно, чтобы прерывание было смещено относительно точек MIN и 0, то в прерывании по переполнению можно не делать ничего, кроме разрешения прерывания по COMPARE MATCH одного из каналов. Тогда при следующем совпадении этого канала бдует генерироваться прерывание, которое и будет запускать нужные задачи. Когда код обработчика закончит основные действия, нужно вновь запретить это прерывание.
Начиная с поста 126 речь идёт о структуре, изложенной в посте 54. В которой генерация квадратурного сигнала осуществлена по варианту, предложенному mixail844 в посте 44. Он дал такую ссылку. Это вариант где таймер работает в режиме компарирования с Toggle on match. То есть тут счёт идёт только в одну сторону, а меандр получается именно за счёт Toggle on match.
Когда у вас таймер стартует, его состояние известно. Не представляет никакого труда отслеживать количество Compare Match, чтобы знать текущее состояние выхода.
Прочитать состояние выходной ноги это 1 команда, с проверкой не займёт более 0.2 мкс.
Когда у вас таймер стартует, его состояние известно. Не представляет никакого труда отслеживать количество Compare Match, чтобы знать текущее состояние выхода.
Это надо делать программно и об этом уже говорилось, может, так и придётся делать. Но пока ищется путь красивого решения - чисто аппаратный.
Прочитать состояние выходной ноги это 1 команда, с проверкой не займёт более 0.2 мкс.
Это первое, что приходит в голову. Но поскольку это надо будет уже делать программно, где гарантия того, что состояние выхода прочитается после того как оно будет изменено, а не до того или наоборот? Конечно для гарантии можно сделать небольшую задержечку на чтение.
Это надо делать программно и об этом уже говорилось, может, так и придётся делать. Но пока ищется путь красивого решения - чисто аппаратный.
Чисто аппаратный я вам уже озвучил -- Repetition Counter.
Чисто аппаратный я вам уже озвучил -- Repetition Counter.
Тут тоже есть проблеммы, см. пост 165. Видимо, я не сумел их внятно изложить.
Больше похоже, что вы пока внятно не поняли технику использования TIMx_RCR. С его помощью, без всяких проблем, можно организовать, чтобы событие возникало только в момент переключения выхода с низкого в высокое состояние, либо наоборот. Будучи однажды запущенным, сконфигурированный соответствующим образом таймер, обеспечивает нужный функционал полностью аппаратно, т.е. без выполнения какого-либо кода процессором.
Больше похоже, что вы пока внятно не поняли технику использования TIMx_RCR. С его помощью, без всяких проблем, можно организовать, чтобы событие возникало только в момент переключения выхода с низкого в высокое состояние, либо наоборот. Будучи однажды запущенным, сконфигурированный соответствующим образом таймер, обеспечивает нужный функционал полностью аппаратно, т.е. без выполнения какого-либо кода процессором.
a5021, извините. Отослал не на тот пост. Надо было писать не 162, а 165. Это уже исправил. А так согласен, вариант имеет право на жизнь. Но тут прикол в том, что, посмотрев ещё раз свой алгоритм обработки сигнала, увидел, что результат не зависит от того, к какому фронту будут привязаны вычисления. Главное, что бы к одному сигналу. Промежуточные вычисления будут зависеть, а окончательный результат нет. Так что у всех прошу прощения. Хотя думается, что эта часть переписки не была безполезной.
Не понятный дублёж.
Опять дублёж
Я уже писал, что в микропроцессоре нет ничего неопределённого. Не может где-то лишний тик набежать, чтобы фронт перевернуть. Задали дважды четное количество тактов - на тогле получите четное количество переворотов - т.е. фронт будет тот же.
Продвинулся очень не плохо. Получаю данные, их обрабатываю. Но есть одна проблемма. Почему то в массиве данные начинаются с одной точки до фронта при таком коде.
Когда запуск DMA переместил за старты таймеров, результаты пошли правильные, но радость была не долгой. При другом количестве импульсов на период опять возникла таже ситуация с дополнительной точкой в начале массива. Решил принудительно запускать DMA по возникновению фронта с разным количеством пропускаемых фронтов (код ниже). Но это не помогло. Где собака порылась?
А АЦП чем тактируется? DMA вообще не причём. Это только способ передачи данных АЦП в память. Первая строка это не старт DMA. Это запуск АЦП. Вот с запуском и тактированием АЦП и надо разбираться. А так вообще прикольно. Особенно костыль в одиннадцатой (третьей) строке. Работает да и ладно.
А АЦП чем тактируется? DMA вообще не причём. Это только способ передачи данных АЦП в память. Первая строка это не старт DMA. Это запуск АЦП. Вот с запуском и тактированием АЦП и надо разбираться. А так вообще прикольно. Особенно костыль в одиннадцатой (третьей) строке. Работает да и ладно.
Хорошо, всё равно не понятно. Ведь я отлавливаю фронт генератора, а потом запускаю АЦП. Какие при этом могут быть причины попадания импульса до фронта. Что то у меня не то в этом отлавливании или другое. Правда, возможен такой вариант. АЦП то стартует после фронта, но пока это происходит пропускается часть тактирующих импульсов, ну, и случайно попадает на предпоследний. Попробую как то это проверить, но уже вечерком. А вообще крутится такой вариант - не знаю на сколько он возможен. Генератор и АЦП крутятся постоянно, а старт работы DMA - в нужный момент, скажем по фронту генератора.
Я ж написал только что. DMA нельзя стартануть. Можно дать разрешение передавать информацию от АЦП в память. После разрешения каждый сигнал АЦП готовы данные будет передавать в память результат. Т.е. Последовательность действий - заряжается АЦП, заряжается DMA, ждём нужного момента, даём АЦП команду начать преобразование, Минимум через 1.5 такта АЦП зарядит УВХ и через 12.5 такта выдаст результат, выставит флаг готовности. DMA возмёт данные и переместит в память. И АЦП, если запрограмировано на одно преобразование, будет ждать следующей команды запуска. Ваша задача дать эту команду в тот момент когда вам нужно получить значение вашего сигнала. Заметте, что вы получаете данные не в момент разрешения DMA, а точно в момента старта АЦП. Если АЦП уже имеет какие то данные, то после разрешения DMA вы получите первое старое значение, которое АЦП оцифровало до разрешения DMA, если АЦП разрешено и запущено до разрешения DMA.
nik182, спасибо за развёрнутое разъяснение. Вобщем то я так это и представлял. Но почему же во втором варианте (пост 178) проблема остаётся? Там то всё казалось бы железно. Пришёл фронт, запустилось АЦП. А получается, что к этому моменту там уже было значение, то есть преобразование уже было. Как оно могло появиться, если АЦП ещё не было запущено. Что то тут я упускаю. Тогда какой алгоритм должен быть, что бы запись в DMA начиналась с первого импульса после фронта генератора?
Я уже потерялся в вашей программе. Покажите проект куба и программу целиком. Надо посмотреть как АЦП инициализировано и запускается.
Я уже потерялся в вашей программе. Покажите проект куба и программу целиком. Надо посмотреть как АЦП инициализировано и запускается.
https://yadi.sk/d/Zz05zcHF-mGrfA
https://yadi.sk/d/B241kYoYtUebQA
У меня программа вот так взлетела.
Сначала запускаем АЦП, потом таймер 3 ( он всё равно тактуется от второго) и наконец запуск второго и всё работает без потерь тиков.
У меня программа вот так взлетела.
Сначала запускаем АЦП, потом таймер 3 ( он всё равно тактуется от второго) и наконец запуск второго и всё работает без потерь тиков.
nik182, огромное спасибо. Вы как палочка выручалочка. Всего делов то. Я как то не сомневался, что всё достаточно просто, но сам дойти не смог. Этот этап игры с большим трудом, но с вашей помощью прошёл. На какую же ступень я поднялся? Следующие этапы это освоение LCD дисплея и вывод по COM порту. А за тем непременно надо замахнуться на TFT дисплей. Но всё это уже другие темы.
Юрий у меня вопрос. Вы в ТЗ писали про 80 мс, а у меня получается 16. Это нормально?
Юрий у меня вопрос. Вы в ТЗ писали про 80 мс, а у меня получается 16. Это нормально?
То, что писалось в ТЗ это предельные параметры. Что будет на самом деле я пока не знаю, всё ещё в переди - исследования покажут, пока придут микросхемы, связанные с аналоговой частью. А пока структура и сама программа делалась так, что бы было удобно менять частоту генератора, количество оцифровки на период и их фазовый сдвиг относительно сигнала генератора. На данном этапе я считаю, что цель достигнута. А то, что получилось 16 мс, это просто последний вариант проверки без привязки к чему то реальному. Спассибо за беспокойство.
Тед, Лаконично, но для меня пока ещё трудно читаемо. Чего не хватает в большенстве примеров, которые я смотрел так это пояснений, коментарий.
Продолжение следует. За это время по моим меркам добился многого. Дисплей подключил и вижу на нём данные, научился принимать и передавать данные по COM порту, на ПК вижу сигнал и сделал свой удобный интерфейс для передачи параметров таймеров для проведения эксперементов. Данные передаются и подписываются в таймера првильно, сигнал адекватно меняется - его вижу на ПК. Но вот незадача - синхронизация о которой я так пекусь разлетается и это понятно - ведь параметры подписываюся асинхронно. Какие действия я вижу, что бы обеспечить требования, выдвинутые мной в начале?
1. Остановить таймера. Я так понимаю, что в соответствии со структурой из поста 178 достаточно остановить таймер Т2
2. Прописать в таймера все необходимые параметры, включая исходные состояния выходов.
3. Обнулить счётчики таймеров.
4. Сбросить счётчик DMA
5. Запустить таймера. Эта часть усилиями nik182 уже есть.
6. Может ещё чего, что упустил.
Пошёл следующим путём, может, не очень красивым, но, как мне кажется, "железным". Взял Кубовские функции инициации таймеров, переименовал их и прописал в соответствующих местах вместо констант, задаваемых Кубом, требуемые переменные. Это работает, но синхронизации как не было, так и нет. В качестве останова таймеров использовал функции, см.код.
Что не так?
Так и не получается побороть эту проблемму, хотя чего только не перепробовал за это время. Ещё на двух форумах поднял эту тему, но ничего путного не получил. nik182, если есть возможность, пожалуйста посмотрите эту тему.
Посмотрел. Сейчас я не могу вникать глубоко, по крайней мере ещё 2 недели. Ваша проблема мне была понятна ещё с вашей прошлой реализации. У вас несинхронно работают таймеры. Вам повезло случайно запустится так, что получилось примерно то что вы хотели, но сама идея такой работы таймеров ущербна. При любой смене параметров у вас должна получаться чушь. Я не зря предлагал использовать три таймера. При этом два из них должны запускаться от третьего. Только в этом случае можно менять как угодно параметры. И писать надо на LL а не на HAL. На HAL этого ни как не сделать. Причину я описал раньше.
Есть положительный результат, но с некоторым ограничением. Небольшое резюме.
1. Генерация квадратурного сигнала (меандр) с заданой частотой. Работает без вопросов.
2. Генерация импульсов, запускающих АЦП, с необходимым количеством импульсов на период генератора и возможностью задавать необходимый сдвиг относительно фронта генератора квадратурного сигнала (положительный фронт первого канала) . Работает без вопросов.
3. Циклическая буфиризация результатов преобразования АЦП с помощью DMA так, чтобы начало буфера совпадало с фронтом генератора (тот же положительный фронт первого канала). Вот тут то и происходят все пляски, имеется ввиду синхронизация начала заполнения буфера с фронтом генератора.
Основным мотивом решения проблемы было замораживание DMA и таймеров, прописывание в них новых требуемых значений предделителей, автоперезагрузки и уровней компарирования с последующей активацией таймеров и DMA. Пробовал кучу вариантов, но ничего путного не получил. В результате решил откатить на запасные окопы. Это - по прерыванию ловить фронт генератора и инициализировать в этот момент буфер DMA или инициализацию не делать, а считывать значение его счётчика и использовать его для коррекции синхронизации. Другими словами таким образом определять номер точки в буфере, соответствующей требуемому фронту генератора. Вот тут то началось что то осмысленное. При чём два последних варианта оказались равнозначными - остановился на втором как более простом. Немного поподробнее. После прописывания всех изменённых параметров (оперативно без всяких остановок) выставляю признак, что изменения сделаны, и, когда он появляется в обработчеке прерывания компаратора первого канала таймера3 (фаза А), тогда считываю значение счётчика DMA. А, чтобы это точно был положительный фронт, то ещё проверяю состояние выхода второго канала этого таймера (фаза Б) Это работает, но что интересно. Если считывать значение счётчика DMA сразу после появления признака изменения данных, то положительного результата нет. Но, если пропускать более двух периодов генератора, то получается правильный сто процентный результат вне зависимости от изменяемых параметров, что очень хорошо. Казалось бы вопрос закрыт, но вот ещё одна интересная заковыка. Всё идёт хорошо пока частота опроса АЦП ниже ~72 кГц. Но стоит частоту повысить, как появляется дополнительный сдвиг на 2 импульса. При чём, что удивительно - происходит это скачком, а не плавно в зависимости от частоты. Или это сдвиг 0 или 2, если частота опроса АЦП больше 72 кГц. И второе этот сдвиг больше ни отчего не зависит. Я имею ввиду не зависит от параметров, которые я изменяю. Если кто смог дочитать эту писанину до конца и имеет свои мысли почему такое происходит, то, пожалуйста, расскжите о своих соображениях.
1. почему для устаканивания необходимо два периода генератора квадратурного сигнала?
2. с чем связан скачёк в 2 импульса?
Захватил осциллом момент старта генерации:
[/quote]
А как добавить еще один канал выход на