Перейти к содержанию
    

Переключение задач на STM32f10x в Keil

Здравствуйте, пытаюсь сделать простейший переключатель задач на миксе ассемблера и си, используя микропроцессор STM32f10x и среду Keil uVision 5, но постоянно натыкаюсь на непонятные моменты. У меня есть основная функция main, из которой инициализируется процессор и включается таймер systick, по прерыванию таймера запускается диспетчер, в котором я хочу сохранить состояние регистров и при выходе выйти уже не на main а на задачу.

Задачи оформлены в виде c-файлов task1.c task2.c и.т.д., к каждой задаче прикреплена структура(массив из 8 чисел) в который заносятся данные о статусе программы, ее длительности и значения SP и PC-регистров, а также зарезервирована величина стэка командой int Stack_task1[512];. Под все это дело организован еще один массив с указателем на массивы каждой из задач. В теории, при инициализации я должен загрузить в массив для каждой задачи значения SP и PC регистров, чтобы после сохранения/восстановления регистров загрузить в регистры SP и PC числа из массива и командой BX выйти на задачу, до следующего срабатывания таймера.

Однако здесь у меня возник вопрос: как мне узнать значения регистров SP и PC для каждой задачи, если она нигде не запускается? То есть она просто прикреплена к проекту, на нее ссылается массив но при выполнении программы она не выполняется нигде. ТАкже мне известно, что у STM32 два SP регистра, один из которых работает в прерывании, а другой в главной программе. Получается если я перед самым выходом из прерывания изменю значение SP, мне это не поможет, потому что после выхода оно все равно сбросится на то значение, которое было до входа в прерывание? В общем, возможно, вопросы глупые, но сам до додуматься до решения пока не могуЮ потому прошу совета. Заранее спасибо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Здравствуйте, пытаюсь сделать простейший переключатель задач на миксе ассемблера и си...

ЗАЧЕМ???

Ведь есть готовые OS в исходниках под это камень и среду в т.ч, где все УЖЕ СДЕЛАНО как нужно и где все отлажено и работает как надо!

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

В реале - не совсем так.

Переключатель контекста (задач) это собсно - ISR. Для Cortex - конкретно PendSV. И должен быть самым низкоприоритетным из всех прерываний.

В нём переключается контекст (стек) задачи Thread-режима. Все задачи выполняются в Thread-режиме, обработчики (и PendSV) - в Handler-режиме.

Выход из Handler - возврат к выполнению задачи (возможно новой, если было переключение в PendSV).

Для переключения задачи из Thread-режима необходимо программно возбудить прерывание PendSV.

PendSV собсно и создано для операционок.

Это вкратце.

 

Ведь есть готовые OS в исходниках под это камень и среду в т.ч, где все УЖЕ СДЕЛАНО как нужно и где все отлажено и работает как надо!

Товарищ изобретает велосипед.

Изобретать будет долго и получится он с квадратными колёсами, так как читать доки не хочет (ибо - писатель, а не читатель ;) и изучать существующие ОС тоже не хочет.

Если-бы хоть что-то прочитал про режимы Cortex, его регистры, обработку прерываний/исключений, то глупых вопросов не задавал-бы.

Ибо начинать надо всегда с глубокого изучения вопроса и читать-читать долго и долго, и только когда всё прояснится, тогда и только тогда можно начинать что-то писать.

А если начинает с писания, то ничего путнего никогда не получится....

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Однако здесь у меня возник вопрос: как мне узнать значения регистров SP и PC для каждой задачи, если она нигде не запускается? То есть она просто прикреплена к проекту, на нее ссылается массив но при выполнении программы она не выполняется нигде. ТАкже мне известно, что у STM32 два SP регистра, один из которых работает в прерывании, а другой в главной программе. Получается если я перед самым выходом из прерывания изменю значение SP, мне это не поможет, потому что после выхода оно все равно сбросится на то значение, которое было до входа в прерывание?

Про то, как и что сохраняется в стеке - смотрите ARMv7-M Architecture Reference Manual, главу "Exception entry behavior". Далее, если специально не заморачиваться, считайте, что у Вас один регистр SP. Второй задействуется только если Вы специально захотели использовать исполнение кода в "непривелегированном" режиме.

В стеке для каждой задачи перед первым их запуском необходимо проинициализировать "сохранённые регистры", что-то вроде

xPSR, ReturnAddress(), LR (R14), R12, R3, R2, R1, and R0. PC (ReturnAddress()) устанавливается равным адресу функции задачи (task1() или task2() у Вас). xPSR - читайте руководство, что там должно быть. Остальные регистры - по вкусу. При возврате из прерывания SP должен содержать адрес xPSR той задачи, на которую осуществляется переключение.

Как-то так. И ещё раз - читайте мануалы и разглядывайте исходники портов RTOS для STM32, очень поможет в понимании.

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я бы посоветовал почитать "Джозеф Ю. Ядро Cortex-M3 компании ARM".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В реале - не совсем так.

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

 

Товарищ изобретает велосипед.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

В реальности любое переключение контекста - это выход из прерывания.

Т.е. - исполняется ваша задача (в thread-mode) ===>>

происходит прерывание (либо PendSV (вызванное программно из этой-же самой задачи) либо любое другое аппаратное или исключение) ===>>

контекст прерванной задачи сохраняется частично аппаратно (механизм Stacking: R0-R3, R12, SP, PC, PSR) частично программно (остальные регистры на входе в ISR) на стеке ===>>

в этот момент, так как находимся внутри ISR, то активным является MSP, а на прерванный контекст указывает PSP (это если прерван thread-mode, а не handler-mode) ===>>

если это обработчик PendSV, то он проверяет необходимость переключения задачи, если нужно переключать -

просто сохраняет указатель из PSP в текущий указатель стека в дескрипторе данных прерванной задачи, а в PSP загружает значение текущего указателя стека из

дескриптора данных новой задачи (которая теперь будет исполняться) ===>>

дальше - просто выходит из прерывания, а так как PSP теперь указывает на новую задачу, то после выхода будет продолжено выполнение уже её, как будто прерыванием

была прервана она, а не старая задача. Вот и всё.

 

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

 

Так как PendSV имеет низший приоритет, то соответственно он не может прервать другой ISR, и не нужно в нём делать проверку случая прерывания другого ISR

(и соответственно прерванным всегда будет PSP). Такой метод переключения задач хорошо совместим и с механизмом вложенных прерываний Cortex и с механизмом tail-chaining.

Не требует много телодвижений для переключения (как например было в ARM7/ARM9 - там ужас какие выкрутасы приходилось делать с множественными переключениями режимов и копированиями контекстов).

Исходники самого переключателя контекстов у Cortex и у ARM7/9 отличаются по объёму в разы.

 

Естественно - перед стартом ОС, стеки всех задач должны быть проинициализированы правильно (так как будто эта задача была прервана прерыванием), а в дескрипторах задач должны быть указатели на верхушки стеков.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так Вас и тут никуда дальше мануалов не посылали. А это как раз и есть дельный совет ;)

К тому-же я только что почти подробно расписал весь механизм переключения задач в Cortex-M.

А то что не можете найти описание (да хоть и на русском) на одно из самых распространённых ядер в настоящее время,

говорит о том что плохо ищете.

А перепостить сюда выдержки из мануалов - это значит просто захламлять форум.

"Имеющий уши - да услышит, имеющий глаза - да увидит".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хорошо, буду искать. Спасибо. Хотя мне казалось что в переключении использовалось прерывания с системного таймера, дабы обеспечивать режим "реального времени", или прерывание PendSV тоже имеет ограничение по времени?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если честно, разработка диспетчера (то самое изобретение велосипеда) это студенческая работа, которая по определенным обстоятельствам мне досталась и относится

Скачивайте исходники любой ОС, имеющией "порт" под cortex-m3.

Например: freertos, tnkernel, ucos.

Там же в доке будет расписан механизм работы переключателя контекста задач.

 

зы. Не вижу смысла выдумывать снова то, что уже придумано, обсосано и выложено другими в свободный доступ.

По-моему, значительно проще скачать и изучить уже готовое, под нужде переделав его под себя, чем все это изобретать с нуля :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хорошо, буду искать. Спасибо. Хотя мне казалось что в переключении использовалось прерывания с системного таймера, дабы обеспечивать режим "реального времени", или прерывание PendSV тоже имеет ограничение по времени?

какое ограничение по времени?

В прерывании таймера обычно ставится только запрос PendSV. Это чтобы всё переключение делалось в одном месте и не нужны были блокировки.

И PendSV должно иметь низший приоритет, ниже любого другого ISR, в том числе таймера, чтобы не мешать работе аппаратных прерываний (не мешать "реальному времени").

Я уже писал об этом выше.

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

 

По-моему, значительно проще скачать и изучить уже готовое, под нужде переделав его под себя, чем все это изобретать с нуля :)

...тем более когда вы это изобретёте, если всё сделаете правильно, то с удивлением обнаружите, что ваш код полностью совпадает с уже существующим :biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я скачал исходники FreeRTOS и первое на что обратил внимание - это то, что он написан на C, а я видимо забыл упомянуть, что диспетчер я делаю на ассемблере.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В прерывании таймера обычно ставится только запрос PendSV. Это чтобы всё переключение делалось в одном месте и не нужны были блокировки.

Небольшой хинт: для того, чтобы выставить запрос на PendSV, нужно установить бит PENDSVSET в регистре процессора "Interrupt Control State Register (ICSR)". После этого, когда обстановка позволит, процессор выполнит обработчик PendSV и переключит задачу (если надо).

 

По поводу исходников на Си - скомпилируйте без оптимизации и посмотрите на ассемблерный листинг :)

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...