Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Подскажите по реализации библиотеки для МК?
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Harvester
Добрый день.
Имеется плата с МК (STM32, но это не суть важно). Мне необходимо написать библиотеку, которая будет передана разработчикам основной программы в бинарном виде. Одна из функций моей библиотеки должна при вызове брать с частотой 100 кГц некоторое количество отсчетов с выводов МК.
Загвоздка в том, как организовать этот самый интервал между отсчетами. Мне приходят в голову следующие варианты:
1. Задержка в цикле - криво и не серьезно;
2. Задержка с использованием HAL-функций (SysTick);
3. Использование какого-либо аппаратного таймера;
4. Обязать разработчиков основной программы вызывать функцию взятия отсчетов с заданной периодичностью.
Из перечисленных вариантов мне больше нравится 4-й. Может я что-то упустил и есть другие решения?
Спасибо.
adnega
Цитата(Harvester @ Aug 25 2015, 11:20) *
Одна из функций моей библиотеки должна при вызове брать с частотой 100 кГц некоторое количество отсчетов с выводов МК.

А разработчики не могут сами взять эти отсчеты и передать в функцию?
Хоть программными задержками, хоть таймером с DMA.
Наличие задержек в функции - дурной тон. Там должен быть только матан.
zltigo
QUOTE (Harvester @ Aug 25 2015, 11:20) *
3. Использование какого-либо аппаратного таймера;
4. Обязать разработчиков основной программы вызывать функцию взятия отсчетов с заданной периодичностью.

Поскольку Вы уже заняли в "библиотеке" какие-то IO и видимо жестко, то так-же занять еще и таймер уже не страшно. А так, если в совсем общем случае, то "4".
Ну а правильный это "5", который назван постом выше.
Harvester
Цитата(adnega @ Aug 25 2015, 11:24) *
А разработчики не могут сами взять эти отсчеты и передать в функцию?
Хоть программными задержками, хоть таймером с DMA.

Изначально так и предполагалось - они копят сырые отсчеты, а я только обрабатываю. Но что-то пошло не так... biggrin.gif
adnega
Цитата(Harvester @ Aug 25 2015, 11:33) *
Но что-то пошло не так... biggrin.gif

Может, достаточно подсказать им как это делается?
Harvester
Цитата(zltigo @ Aug 25 2015, 11:24) *
Поскольку Вы уже заняли в "библиотеке" какие-то IO и видимо жестко, то так-же занять еще и таймер уже не страшно.

С одной стороны Вы правы, однако здесь я вижу две проблемы:
1. Никто не может гарантировать, что будет свободный таймер. Конечно, это весьма маловероятно, но все же...
2. Как его конфигурировать? В этом случае разработчики должны предоставить информацию о тактовой частоте. (Да, в CMSIS есть такая переменная, но кто сказал, что они будут использовать CMSIS или не вырежут эту функциональность?) А потом еще читать регистры RCC, высчитывать тактовую таймеров...

Раз уж все равно вводить требования к основной программе, то пусть будет пункт 4 - мне так проще sm.gif

Цитата(adnega @ Aug 25 2015, 11:35) *
Может, достаточно подсказать им как это делается?

Да они знают, просто на высшем уровне было принято такое решение. Может все еще и поменяется sm.gif
zltigo
QUOTE (Harvester @ Aug 25 2015, 11:57) *
С одной стороны Вы правы, однако здесь я вижу две проблемы:
1. Никто не может гарантировать, что будет свободный таймер. Конечно, это весьма маловероятно, но все же...

Но кто-то ведь гарантровал, то будут свободные пины, которые Вы читать собрались, или тоже нет sm.gif
QUOTE
2. Как его конфигурировать?

Так-же, как и все остальное - библиотека по любому имеет функцию инициализации. Вот и потребуйте вызов этой функции с указанием тактовой частоты.
Harvester
Цитата(zltigo @ Aug 25 2015, 12:12) *
Но кто-то ведь гарантровал, то будут свободные пины, которые Вы читать собрались, или тоже нет sm.gif

Они не свободны, а жестко подключены к внешней периферии! Но Вашу мысль я понял. Буду решать.

Возник еще вопрос.
Допустим я задействую таймер. Т.к. я не знаю, какая в основной программе будет система прерываний (приоритеты и пр.), я буду контролировать интервал ожиданием флага переполнения.
Если не принимать во внимание вопросы эстетики, то чем это решение принципиально будет отличаться от программной задержки с помощью цикла?
esaulenka
Цитата(Harvester @ Aug 25 2015, 12:29) *
Допустим я задействую таймер. Т.к. я не знаю, какая в основной программе будет система прерываний (приоритеты и пр.), я буду контролировать интервал ожиданием флага переполнения.
Если не принимать во внимание вопросы эстетики, то чем это решение принципиально будет отличаться от программной задержки с помощью цикла?

Я правильно понял, что эта "библиотека" будет содержать вечный цикл с ожиданием флажка таймера (с последующей обработкой данных) ?
Это принципиально плохое решение.
Хотя бы потому, что остальной, неизвестной части программы тоже нужно процессорное время.
Harvester
Цитата(esaulenka @ Aug 25 2015, 14:44) *
Я правильно понял, что эта "библиотека" будет содержать вечный цикл с ожиданием флажка таймера (с последующей обработкой данных) ?
Это принципиально плохое решение.
Хотя бы потому, что остальной, неизвестной части программы тоже нужно процессорное время.

Не совсем так. При вызове одной конкретной функции нужно взять 100 отсчетов с интервалом в 10 мкс (100 кГц) и обработать их. Т.е. весь вопрос в том, как реализовать, условно говоря, функцию delay_10us(). В любом случае возврат из функции возможен только после взятия всех отсчетов, а раз так, то какая разница как ждать: считать nop-ы или ждать флаг?
ViKo
Если все выводы принадлежат одному порту, можно попробовать читать порт и по DMA складывать в память. А пересылку DMA запускать таймером. Все будет работать аппаратно, регулярно. Только запускать процесс и ждать окончания придется в программе.
esaulenka
Цитата(Harvester @ Aug 25 2015, 15:16) *
При вызове одной конкретной функции нужно взять 100 отсчетов с интервалом в 10 мкс (100 кГц) и обработать их.
...
В любом случае возврат из функции возможен только после взятия всех отсчетов,

И почему бы это сразу не описать, в первом же сообщении?..

Цитата(Harvester @ Aug 25 2015, 15:16) *
Т.е. весь вопрос в том, как реализовать, условно говоря, функцию delay_10us().

Таймером, на мой взгляд - единственное нормальное решение. Без всяких прерываний, раз уж эту миллисекунду не жалко :-)
Если в контроллере не используется встроенный ЦАП, можно задействовать самые простые таймеры - TIM6/TIM7.

Считать nop'ы можно, но, во-первых, лениво (это после каждой правки расчётной части проверять, подбирать заново...), а во-вторых, частота опроса будет плавать, если алгоритм обработки нелинейный (например, входные значения меньше 100 обсчитаются по одной ветке, больше 100 - по другой).
adnega
Цитата(Harvester @ Aug 25 2015, 15:16) *
а раз так, то какая разница как ждать: считать nop-ы или ждать флаг?

Есть и третий вариант. Вызвать функцию, она почти сразу же вернет управление, а в фоне запустит сбор и обработку данных.
По окончанию обработки вызовется callback-функция.
Harvester
Цитата(ViKo @ Aug 25 2015, 15:34) *
Если все выводы принадлежат одному порту, можно попробовать читать порт и по DMA складывать в память. А пересылку DMA запускать таймером. Все будет работать аппаратно, регулярно. Только запускать процесс и ждать окончания придется в программе.

Это уже лишнее - все равно ведь ждать :D Но на будущее учту
demiurg1978
Я с этими МК не работаю. Но, как бы я сделал: насколько я понял, должна быть стабильная частота 100 кГц. Так как эта функция работает от и до, то договариваемся с программистами, что берем хиленький не особо нужный таймер. Функция простенький автомат. Хоть флаговый, хоть свитч-кейс. Нулевое состояние - Инициализируем таймер на нужную частоту, прерывание, при этом рубим все мешающие (опять же, если это можно). Установка следующего состояния. Следующее состояние просто ожидание флага, который устанавливается в прерывании по достижении нужного кол-ва отсчетов. В прерываниях считываем нужные порты и кол-во прерываний (100), кладем считанные данные куда требуется. По достижении нужного кол-ва прерываний-отсчетов отключаем прерывание, таймер, ставим флаг, ставим обратно нулевое состояние и выходим.

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

Что-то вроде такого:
Код
static unsigned char flags = 0;

void func (void)
{
   static unsigned char state;

   switch (state)
   {
      case 0:
         // инициализация ввода-вывода, переменных, таймера.
         state = 1;
         break;

      case 1:
         if (flags & (1<<0))
         {
            // отключение таймера, прерываний
            flags = 0;
            state = 0;
         }
         break;

      default:
         break;
   }
}
Harvester
Цитата(demiurg1978 @ Aug 26 2015, 21:20) *
Но, как бы я сделал...берем таймер...в прерываниях считываем нужные порты...По достижении нужного кол-ва прерываний-отсчетов отключаем прерывание, таймер, ставим флаг.

Так тоже можно. Но зачем? Зачем занимать таймер, настраивать его, выполнять другие телодвижения, когда достаточно простого цикла ожидания. Ведь из функции все равно не выйдешь, пока не наберешь все отсчеты и не обработаешь их.
jcxz
Цитата(Harvester @ Aug 27 2015, 12:52) *
Так тоже можно. Но зачем? Зачем занимать таймер, настраивать его, выполнять другие телодвижения, когда достаточно простого цикла ожидания. Ведь из функции все равно не выйдешь, пока не наберешь все отсчеты и не обработаешь их.

Затем чтобы освободить CPU для выполнения менее приоритетных задач в многозадачной среде. Или хотя-бы для выполнения WFE/WFI в фоновой задаче.
Harvester
Цитата(jcxz @ Aug 27 2015, 10:19) *
Затем чтобы освободить CPU для выполнения менее приоритетных задач в многозадачной среде. Или хотя-бы для выполнения WFE/WFI в фоновой задаче.

А как использование таймера в моем случае позволит освободить CPU? Простите, но я действительно не понимаю sad.gif
Смотрите. Есть некая программа, пусть даже с ОС. В какой-то момент она вызывает мою функцию, задача которой снять 100 отсчетов с ноги с интервалом в 10(+/-) мкс, обработать их блоком и вернуть результат.
Так вот, какая разница для основной программы, как будет отсчитываться интервал между считыванием в моей функции: циклом задержки с nop-ами, таймером с ожиданием флага переполнения, таймером с DMA и прочее и прочее? Ведь функция в любом случае вернет управление только после накопления ВСЕХ отсчетов и, чтобы я ни придумал, это в любом случае займет не менее 1 мс.
Если я не прав, то буду очень благодарен за разъяснение
jcxz
Правильное ожидание готовности:
Разрешаем прерывание по готовности периферии и уходим на ожидание готовности семафора (или другого средства синхронизации ОС). Соответственно после этого управление передаётся менее приоритетной ждущей задаче, если таковой нет - фоновой Idle-задаче ОС, которая выполняет команду WFE (либо крутит цикл со счётчиком, подсчитывая неиспользованные такты для расчёта загрузки CPU).
Когда возникает прерывание готовности, в ISR семафор переводится в состояние "готов" и управление вернётся в Вашу ждущую задачу. Всё.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.