реклама на сайте
подробности

 
 
> Вопрос по применению PendSV в простом планировщике
arhiv6
сообщение Sep 25 2016, 08:52
Сообщение #1


Знающий
****

Группа: Свой
Сообщений: 633
Регистрация: 21-05-10
Из: Томск
Пользователь №: 57 423



Добрый день. Есть вопрос по правильному применению PendSV в Cortex-M4.
Пару раз использовал простой планировщик, написанный на Си. В нем задачи - это простые функции, которые, в отличии от обычных вытесняющих OS, не содержат в своем теле бесконечного цикла, а выполняются до завершения. Решил добавить задачам приоритеты и добавить возможность более приоритетным задачам приостанавливать менее приоритетные, как в Super Simple Tasker (SST). Как я это вижу:
Стек общий на все задачи. При выполнении задачи (A), если требуется передать управлении более приоритетной (B) - в кольцевой буфер кладём указатель на необходимую задачу и вызываем прерывание PendSV. Попадаем в обработчик прерывания PendSV_Handler (при этом стек предыдущей задачи сохранился, в него мы попадём при выходе из прерывания). В обработчике видим, что есть потребность исполнения более приоритетной задачи B -> вызываем её (как функцию), выполняем, возвращаемся в тело обработчика прерывания и выходим из прерывания, возвращаясь задачу A и продолжаем её выполнение.
Проблема в том, что вызывая задачу В я остаюсь в контексте прерывания PendSV и я не смогу передать (если это потребуется) управление ещё более приоритетной задаче (С), т.к. нельзя ещё раз вызвать прерывание PendSV. Как-то можно это обойти?

Сообщение отредактировал arhiv6 - Sep 25 2016, 15:14


--------------------
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
arhiv6
сообщение Sep 25 2016, 11:24
Сообщение #2


Знающий
****

Группа: Свой
Сообщений: 633
Регистрация: 21-05-10
Из: Томск
Пользователь №: 57 423



Для совсем простых вещей работаю без ОС, для некоторых - хватает упомянутого планировщика, для чего-то сложнее - разумеется, использую готовую ОС. Появилась идея немного доработать планировщик, это скорее для самообразования (для этих же целей, например, писал простой кооперативный планировщик на setjmp/longjmp - чтобы научиться работать с setjmp/longjmp, чтобы на своём опыте попробовать карусельную ОС).
Исходники смотрел. Например, scmRtos - на сколько хватает моего понимания - для каждой задачи выделяется в памяти своя область для хранения стека, в PendSV_Handler происходит сохранение текущего указателя на стек, сохранение регистров, восстановление значений регистров новой задачи, в регистр указателя стека записывается указатель на стек новой задачи и происходит выход из прерывания - и т.к. указатель на стек мы поменял -> автоматически переходим в новую задачу. Но, к сожалению, у меня не хватает знаний о том, какой алгоритм должен быть для переключения задач в моём случае.
Первое, что пришло в голову - использование прерывания и работа в его контексте. При этом при вызове обработчика прерывания автоматически сохранится контекст текущей задачи, создастся новый - для обработчика прерывания. Даже ассемблер не нужен, всё сделает компилятор. Но, т.к. вложенные прерывания запрещены, все ограничивается одним уровнем приоритета. Какие есть средства обойти это? Только использовать подмену адреса в указателе на стек и выходить из обработчика прерывания? Или можно как-то сообщить ядру что обработка прерывания закончена и при этом остаться в контексте прерывания (по сути - разрешить вложенные прерывания)? Или как-то по другому?


--------------------
Go to the top of the page
 
+Quote Post
AVI-crak
сообщение Sep 26 2016, 12:31
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 182
Регистрация: 16-10-15
Пользователь №: 88 894



Цитата(arhiv6 @ Sep 25 2016, 18:24) *
Даже ассемблер не нужен, всё сделает компилятор.

Очень большое заблуждение. GCC настолько оптимизирует код - что функции ос размазываются по всему контексту. Прямые вставки на асме заставляют выполнятся код в нужном месте, в уникальном порядке.
Второе, сам переключатель не столь важен, он просто должен быть быстрым. Важна сама организация стеков. Тут всего три подхода:

Глобальное использование препроцесора, при этом новых задач создать невозможно, так-же как и удалить - но зато моментальный старт.

Создание/удаление задач в области хелпа, когда маллок выделяет кусок памяти единый для переменных и стека одной задачи - применяется почти всеми ос, недостатки - система деревянная по пояс. В случае когда в задаче временно используется массив большого размера - остальное время получим перерасход памяти.

Третий вариант: статический стек прерываний + динамический стек задач - есно вниз. Динамическое выделение памяти под переменные в области хелпа - есно в верх. Ещё больше гибкости, но и больше накладных расходов.

Четвёртый вариант: аналог третьего с небольшим исключением - плавающая граница между нижней планкой стека и верхней планкой памяти переменных. Позволяет впихнуть невпихуемое в самый маленький мк, и заставить двигаться то - что двигаться чисто физически не может. (почти автоваз)

Литература для обучения и создания собственной ос http://badembed.ru/assembler-pereklyuchenie-konteksta/
Моё https://bitbucket.org/AVI-crak/rtos-cortex-.../branch/default на орфографию не обращать внимания - это глюки.
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 22:53
Рейтинг@Mail.ru


Страница сгенерированна за 0.01384 секунд с 7
ELECTRONIX ©2004-2016