Omnicake 0 7 мая, 2014 Опубликовано 7 мая, 2014 · Жалоба Здравствуйте, пытаюсь сделать простейший переключатель задач на миксе ассемблера и си, используя микропроцессор 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, мне это не поможет, потому что после выхода оно все равно сбросится на то значение, которое было до входа в прерывание? В общем, возможно, вопросы глупые, но сам до додуматься до решения пока не могуЮ потому прошу совета. Заранее спасибо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 7 мая, 2014 Опубликовано 7 мая, 2014 · Жалоба вроде как при написании диспетчера из прерывания не выходят.... То есть основная идея что вы всегда как бы в прерывании, которое разрешает вложенные прерывания, и прерывает само себя. Вроде как - то так было. А счетчики команд и стэка задач надо инициализировать при создании нитки и потом уже за ними следить. Как - то так... Правда оговорюсь, я пока только теоретически подкован, ручками этого не делал.... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 7 мая, 2014 Опубликовано 7 мая, 2014 · Жалоба Здравствуйте, пытаюсь сделать простейший переключатель задач на миксе ассемблера и си... ЗАЧЕМ??? Ведь есть готовые OS в исходниках под это камень и среду в т.ч, где все УЖЕ СДЕЛАНО как нужно и где все отлажено и работает как надо! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 7 мая, 2014 Опубликовано 7 мая, 2014 · Жалоба вроде как при написании диспетчера из прерывания не выходят.... То есть основная идея что вы всегда как бы в прерывании, которое разрешает вложенные прерывания, и прерывает само себя. Вроде как - то так было. А счетчики команд и стэка задач надо инициализировать при создании нитки и потом уже за ними следить. Как - то так... В реале - не совсем так. Переключатель контекста (задач) это собсно - ISR. Для Cortex - конкретно PendSV. И должен быть самым низкоприоритетным из всех прерываний. В нём переключается контекст (стек) задачи Thread-режима. Все задачи выполняются в Thread-режиме, обработчики (и PendSV) - в Handler-режиме. Выход из Handler - возврат к выполнению задачи (возможно новой, если было переключение в PendSV). Для переключения задачи из Thread-режима необходимо программно возбудить прерывание PendSV. PendSV собсно и создано для операционок. Это вкратце. Ведь есть готовые OS в исходниках под это камень и среду в т.ч, где все УЖЕ СДЕЛАНО как нужно и где все отлажено и работает как надо! Товарищ изобретает велосипед. Изобретать будет долго и получится он с квадратными колёсами, так как читать доки не хочет (ибо - писатель, а не читатель ;) и изучать существующие ОС тоже не хочет. Если-бы хоть что-то прочитал про режимы Cortex, его регистры, обработку прерываний/исключений, то глупых вопросов не задавал-бы. Ибо начинать надо всегда с глубокого изучения вопроса и читать-читать долго и долго, и только когда всё прояснится, тогда и только тогда можно начинать что-то писать. А если начинает с писания, то ничего путнего никогда не получится.... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RabidRabbit 0 7 мая, 2014 Опубликовано 7 мая, 2014 · Жалоба Однако здесь у меня возник вопрос: как мне узнать значения регистров 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, очень поможет в понимании. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 11 7 мая, 2014 Опубликовано 7 мая, 2014 · Жалоба Я бы посоветовал почитать "Джозеф Ю. Ядро Cortex-M3 компании ARM". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 7 мая, 2014 Опубликовано 7 мая, 2014 · Жалоба В реале - не совсем так. ну то есть в реальности выход из прерывания имеется. Просто есть одно прерывание которое переключает задачи, и из него выходим в конкретную выбранную задачу? И оно же сохраняет все потраха предыдущей задачи из которой его дернули? Товарищ изобретает велосипед. я тоже как то писал архиватор без углубления в теорию, просто потому что было интересно посмотреть сработает или нет, проверить принцип. Проверил, сработало, эффективность мизерная, но сам факт! Это я к тому что для изобретения велосипеда с теорией и без могут быть разные предпосылки. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 7 мая, 2014 Опубликовано 7 мая, 2014 · Жалоба ну то есть в реальности выход из прерывания имеется. Просто есть одно прерывание которое переключает задачи, и из него выходим в конкретную выбранную задачу? И оно же сохраняет все потраха предыдущей задачи из которой его дернули? В реальности любое переключение контекста - это выход из прерывания. Т.е. - исполняется ваша задача (в 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 отличаются по объёму в разы. Естественно - перед стартом ОС, стеки всех задач должны быть проинициализированы правильно (так как будто эта задача была прервана прерыванием), а в дескрипторах задач должны быть указатели на верхушки стеков. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Omnicake 0 7 мая, 2014 Опубликовано 7 мая, 2014 · Жалоба Если честно, разработка диспетчера (то самое изобретение велосипеда) это студенческая работа, которая по определенным обстоятельствам мне досталась и относится не совсем к моей специальности. К сожалению большинство руководств по микропроцессорам написано на английском, и понять оттуда я могу только основную суть, именно поэтому выбрал такой способ обучения, скажем так от знающих людей напрямую. Если я оскорбил чьи-то чувства своими вопросами, заранее извиняюсь. Но мне посоветовали обращаться за помощью именно на этот форум,и именно тут мне до этого давали действительно дельные советы, а не посылали куда подальше. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 7 мая, 2014 Опубликовано 7 мая, 2014 · Жалоба Так Вас и тут никуда дальше мануалов не посылали. А это как раз и есть дельный совет ;) К тому-же я только что почти подробно расписал весь механизм переключения задач в Cortex-M. А то что не можете найти описание (да хоть и на русском) на одно из самых распространённых ядер в настоящее время, говорит о том что плохо ищете. А перепостить сюда выдержки из мануалов - это значит просто захламлять форум. "Имеющий уши - да услышит, имеющий глаза - да увидит". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Omnicake 0 7 мая, 2014 Опубликовано 7 мая, 2014 · Жалоба Хорошо, буду искать. Спасибо. Хотя мне казалось что в переключении использовалось прерывания с системного таймера, дабы обеспечивать режим "реального времени", или прерывание PendSV тоже имеет ограничение по времени? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 7 мая, 2014 Опубликовано 7 мая, 2014 · Жалоба Если честно, разработка диспетчера (то самое изобретение велосипеда) это студенческая работа, которая по определенным обстоятельствам мне досталась и относится Скачивайте исходники любой ОС, имеющией "порт" под cortex-m3. Например: freertos, tnkernel, ucos. Там же в доке будет расписан механизм работы переключателя контекста задач. зы. Не вижу смысла выдумывать снова то, что уже придумано, обсосано и выложено другими в свободный доступ. По-моему, значительно проще скачать и изучить уже готовое, под нужде переделав его под себя, чем все это изобретать с нуля :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 7 мая, 2014 Опубликовано 7 мая, 2014 · Жалоба Хорошо, буду искать. Спасибо. Хотя мне казалось что в переключении использовалось прерывания с системного таймера, дабы обеспечивать режим "реального времени", или прерывание PendSV тоже имеет ограничение по времени? какое ограничение по времени? В прерывании таймера обычно ставится только запрос PendSV. Это чтобы всё переключение делалось в одном месте и не нужны были блокировки. И PendSV должно иметь низший приоритет, ниже любого другого ISR, в том числе таймера, чтобы не мешать работе аппаратных прерываний (не мешать "реальному времени"). Я уже писал об этом выше. А если вы сделаете в таймере, то как раз это будет хуже с точки зрения реалтаймовости, так как переключение будет на уровне приоритета аппаратного прерывания таймера. По-моему, значительно проще скачать и изучить уже готовое, под нужде переделав его под себя, чем все это изобретать с нуля :) ...тем более когда вы это изобретёте, если всё сделаете правильно, то с удивлением обнаружите, что ваш код полностью совпадает с уже существующим Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Omnicake 0 7 мая, 2014 Опубликовано 7 мая, 2014 · Жалоба Я скачал исходники FreeRTOS и первое на что обратил внимание - это то, что он написан на C, а я видимо забыл упомянуть, что диспетчер я делаю на ассемблере. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RabidRabbit 0 7 мая, 2014 Опубликовано 7 мая, 2014 · Жалоба В прерывании таймера обычно ставится только запрос PendSV. Это чтобы всё переключение делалось в одном месте и не нужны были блокировки. Небольшой хинт: для того, чтобы выставить запрос на PendSV, нужно установить бит PENDSVSET в регистре процессора "Interrupt Control State Register (ICSR)". После этого, когда обстановка позволит, процессор выполнит обработчик PendSV и переключит задачу (если надо). По поводу исходников на Си - скомпилируйте без оптимизации и посмотрите на ассемблерный листинг :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться