2009-08-03 8 views
3

Это вопрос дизайна для прошивки во встроенной системе У меня есть два ISR (одного приоритета), выполненных независимо. Эти ISR запускаются, когда h/w генерирует данные. Я хочу, чтобы механизм, который должен быть установлен для синхронизации между task1 и task2. задача 2 должна знать о определенных значениях, вычисленных в задаче 1, которые затем должны приниматься во внимание при вычислении определенных значений в задаче2. У меня нет примитивов ОС для использования, т.е. в системе нет операционной системы. Task1 выполняется в контексте ISR1 и task2 в контексте ISR2. Процессор, который мы используем, является контроллером STMicroelectronics 32синхронизация между двумя задачами

EDIT: дополнительная информация Процессор подключен к определенным IP-адресам, которые вызывают прерывания, когда они готовы с данными. Эти IP-адреса действуют как тип Аккумуляторов для данных входных потоковых кадров.

+0

На какой платформе вы работаете? – Amber

+0

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

+0

@Matthem - обычно ISR отключает прерывания при вводе. Но это было бы хорошо проверить. – Robert

ответ

2
  • Отключить прерывания перед тем чтение или запись общих значений
  • Re разрешить прерывания после чтения или записи общих значений
2

Я постараюсь дать вам ответ на основании ограниченной информации, при условии, что:

  • простой, доморощенный планировщик используется для invoke task1 и task2 на основе простого критерия
  • task1 и task2 выполняются до завершения (т. не вытеснять друг друг)
  • данных представляют собой поток байт на основе (немного другая реализация требуется, если вам нужны пакеты)

То, что я обычно стараюсь при проектировании встраиваемых систем является минимизацией использования семафоров, и не зависящие от модели потоки данных. Я проиллюстрирую это ниже:

asynchronous (lock free) communication queues http://www.freeimagehosting.net/uploads/477741db06.gif ISR можно отделить от задач с помощью потоковой FIFO-очереди. Пример можно найти в: http://msmvps.com/blogs/vandooren/archive/2007/01/05/creating-a-thread-safe-producer-consumer-queue-in-c-without-using-locks.aspx

Такая реализация (без блокировок) не имеет зависимостей между ОС и должна быть тривиально проста в поддержке. Это также дает четкий дизайн производителя-потребителя, который свободен от тупиков.

Предполагая, что задачи запускаются планировщиком на дому, вы можете выбрать для проверки события (непустые fifo). т. Е. Если (TRUE == fifo_filled (my_read_queue)) {invoke task 1}

Теперь о синхронизации задач1 и task2. Если task1 просто создает данные, может использоваться один и тот же механизм: если у вас есть очередь (fifo), в которой task1 может записывать данные, которые могут быть прочитаны задачей 2, тогда задачи отключаются. Опять же, это можно проверить в вашем планировщике (если (TRUE == fifo_filled (task1_to_2_queue()) {invoke task2)}

Если вам нужно больше (т.е. если задачи не выполняются до завершения, но вытесняются) Мне нужен какой-то механизм для синхронизации.Варианты включают в себя: - использовать (бесплатно) операционную систему или простой планировщик в любом случае - заваривать свой собственный (мой опыт: должен быть выполнен, если он такой же простой, как цикл for и несколько операторов if) - используйте простой планировщик (гораздо более легкий вес, чем полный RTOS) - код рефакторинга для интеграции task1 и task2 в один. В этом случае вы будете эффективно составлять часть планировщика вашего кода приложения.

Примечание: примерная функция, которую я использовал в этом объяснении (fifo_filled()), не является частью кода примера. Он должен возвращать true if (read! = Write) Кроме того, в примере кода используются глобальные переменные, которые читаются и записываются; вы можете либо запустить функцию, способную обрабатывать несколько очередей, либо переместить переменные чтения/записи и буфера в структуру и обратиться к структуре параметров.

Альтернативный способ - создать критический раздел посредством отключения прерывания. Тем не менее, я пытаюсь ограничить это, поскольку он часто создает сильную связь системы, и код становится сложнее повторного использования.

+0

Не могли бы вы сделать свою иллюстрацию более крупной, пожалуйста? –

+0

сделано. Случайно была ссылка на миниатюру .... – Adriaan

+0

Отлично, спасибо! –

4

Я бы не делал тяжелую обработку в контексте прерывания, просто прочитал данные и установил флаг.

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

Задача также может установить такой флаг для активации другой задачи. Например. Task1 может активировать Task2, потому что Task2 нуждается в значениях из Task1.

Для данных, которые читаются в ISR, вам нужен буфер. В зависимости от времени ваших входящих данных, которые могут быть кольцевым буфером или двойным буфером.

2

Я прихожу к этому с точки зрения отсутствия ОС, нет реальной структуры, отличной от C, и регистров и т. Д. Как бы я это сделал, это иметь переменную состояния для каждого ISR, которая может быть видна другим ISR. Затем, когда вы вводите ISR1, вы просто проверяете состояние задачи ISR2 и работаете при необходимости. Затем ISR2 вызывается и проверяет свое состояние и состояние ISR1 и работает по своему усмотрению. Я бы использовал ENUM в файле заголовка, чтобы перечислять состояния для ясности (INIT, WAITONDATA и т. Д.), А затем переключатель в ISR для обработки каждого состояния. Затем вам нужно только убедиться, что данные, которые должны быть разделены, видны обоими ISR, и вы настроены.

Конечно, как говорили другие, вы не хотите делать много расчетов в ISR. Вы просто хотите установить флаг, что произошло событие или какие-то данные присутствуют, а затем обрабатывать данные в основном цикле. Тогда ваша система не блокируется слишком долго для обработки ISR. Вы делаете это таким же образом - переменную состояния, которая может быть видна в основном цикле (или, по крайней мере, функция, которую вы вызываете для обработки данных из основного цикла) и ISR. Измените его состояние в ISR и проверьте это состояние в функции основного цикла. Делайте хлопоты по мере необходимости.

Не забудьте - , если вы обновляете переменные в ISR, они должны быть определены как изменчивые!

volatile uint8 state = INIT;

например.

 Смежные вопросы

  • Нет связанных вопросов^_^