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

Выход из handler-mode в cortex-m3

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

Изменено пользователем Omnicake

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


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

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

Понимаю тягу к ассемблеру Cortex-M, но считаю, что это всего лишь инструмент.

Для переключения контекста не обязательно писать на Си или Асм - нужно разобраться в архитектуре.

SysTick это всего лишь таймер, одинаковый для всех производителей микроконтроллеров на ядре Cortex-M.

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

Либо переключить задачу по прерыванию. В том числе от таймера. В том числе от таймера SysTick.

Можно переключать задачи в SysTick, но в случае, если SysTick у Вас с самым низким приоритетом - это гарантирует, что Вы точно знаете положение

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

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

будут "тупить" до момента сработки таймера SysTick.

 

Если в конце SysTick взводить PendSv (ровно как и в функциях ядра), то переключение будет:

- гарантированно происходить после каждого срабатывания SysTick;

- в функциях ядра;

- гарантированно происходить до момента передачи управления в main.

 

Идеально. Что при таком подходе Вам не нравится? На Асме красиво реализуется.

 

 

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


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

1. PendSv - это просто особое прерывание, приоритет которого можно поставить минимальным, это позволит вам быть уверенным что в него вы попали из задачи а не из другого прерывания. В вашем случае PendSV и Прерывания таймера не различимы, задайте таймеру минимальный приоритет, и будет почти тоже самое. То есть во взрослых системах PendSV вызывается во многих случаях, те только через заданное время после прошлого вызова, у вас же только так.

 

2.

LDR sp, [r1,#24];Загрузил стэк программы

MOVW R2,#0x00d0; в котором по адресу 0x200000d0

MOVT R2,#0x2000; положил число 0xFFFFFFF9

LDR pc, [r2]; Загрузил его в PC

 

чет я не понимаю:)... Видать я как то непонятно пишу... Попробую еще раз.

 

если вы находитесь в hendlre режиме, как только вы в счетчик команд запишите 0xFFFFFFF9, обращаю внимание именно в счетчик команд, ни в стэк, ни в память, а именно в него. То процессор запустить процедуру выхода из hendler режима в thread режим (он не перейдет по указанному адресу, а запустить процедуру). В ходе этой процедуры процессор из стэка восстановит значения счетчика команд куда ему надо идти. При этом процессор будет использовать главный стэк в случае если на конце 9, и стэк программ если на конце D.

В стэке к моменту записи магического числа должно лежать правильной последовательности PC, LR, r0-r3, и чего-то там еще, то есть полный набор сохраняемых данных для входа в прерывание.

 

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

 

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

 

То есть в начале работы

вам надо сделать задачи со своими локальными стэками

положить в них структуру которая кладется когда вызовиться прерывание из этой задача, в место где хранится РС положить начало вашей задачи.

 

далее в прерывании вам надо, сохранять PSP задачи из которой пришли, далее РSP устанавливать на стэк нвоой задачи, и записывать магическое число. Все!

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


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

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

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


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

вам надо сделать задачи со своими локальными стэками

положить в них структуру которая кладется когда вызовиться прерывание из этой задача, в место где хранится РС положить начало вашей задачи.

Локальные стэки я задал, в каждой задаче у меня прописано Stack_task1[512]. LDR sp, [r1,#24] как раз и грузить адрес метки Stack_task1.

А по поводу

если вы находитесь в hendlre режиме, как только вы в счетчик команд запишите 0xFFFFFFF9, обращаю внимание именно в счетчик команд, ни в стэк, ни в память, а именно в него.

Может я чего-то не увидел, но напрямую через команду MOV в PC на Cortex M3 вроде бы писать нельзя, компилятор мне выдает ошибку. Да и в инструкции написано, что грузятся значения в PC только через LDR или POP, а для этого нужно магическое число куда-то положить (я и положил его в стэк задачи).

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


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

обращаемся к первоисточнику

 

http://infocenter.arm.com/help/index.jsp?t...9125006491.html

1. есть мнение что LDR sp - изменит не PSP а MSP, вернее через sp вы вообще меняете 13 регистр, который по сути есть только отображение указателя стэка. А надо менять именно psp или msp

 

2. положили ли вы в стэк задач http://infocenter.arm.com/help/index.jsp?t...a/Babefdjc.html структуру как на рисуночке с указателями и прочей байдой, где в РС лежит первая команда задачи? А указатель показывает на последнюю непустую ячейку

 

3.

Exception return occurs when the processor is in Handler mode and executes one of the following instructions attempts to set the PC to an EXC_RETURN value:

an LDM or POP instruction that loads the PC

an LDR instruction with PC as the destination

a BX instruction using any register.

 

EXC_RETURN - это магическое число. Причем 0xFFFFFFF9 - это возврат через MSP, а 0xFFFFFFFD это возврат через PSP

 

 

Третий пункт вы вроде бы выполнили правильно (хотя я воспользовался бы командой BX, наверное), значит остается вопросы к 1, 2 пунктам....

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


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

1. Ну у меня и отображается активным MSP все это время, и до прерывания и внутри него. Командой LDR я меняю указатель на метку Stack_task1 - массив из 512 чисел, который я взял за стэк задачи.

2. Как корректно класть туда эту структуру? Заранее прописывать ее в массив в самой задаче или загонять через PUSH необходимые регистры?

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


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

в симуляторе я могу свободно просматривать память и пошагово следить за программой. После входа в прерывание у меня лежит LR возврата на main,
Начните с чтения документации. В момент входа в обработчик исключения адрес возврата вместе с содержимым некоторых регистров кладется на стек. В LR заносится магическое число. Если вы наблюдаете в LR адрес возврата - выкиньте свой симулятор. Или вы попадаете в исключение каким-то нестандартным методом, вроде прямого вызова функции?

 

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


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

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

Тут возможно я недостаточно подробно описал, при входе в прерывание там действительно лежит число EXC_RETURN но затем, из за того что в обработчике у меня стоит вызов другой программы (а именно переключателя задач), он уходит на ту программу, помещая в LR адрес возврата.

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


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

он уходит на ту программу, помещая в LR адрес возврата.
Так сохраните старое значение LR куда-нибудь. Например, на стек. И потом со стека восстанавливайте сразу в PC командой POP.

 

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


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

Видимо это Keil uVision и делает: после того как я добавил ассемблерные вставки в main, написанный на C, он создал автоматически файл main.s и там функция

SysTick_Handler
{
scheduler();
}

Выглядит вот так

SysTick_Handler
     PUSH {r4,lr}
     BL systick
     POP {r4,pc}

Однако из-за того, что из systick я прыгаю на другую программу, POP {r4,pc} пропускается. Значит, судя по всему, нужно делать это внутри шедулера.

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


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

Omnicake, ваше желание разобраться похвально, но такими темпами вы будете делать это ещё полгода. предлагаю вам почитать о coocox os. она написана очень просто, имеет документацию на русском, процедуры переключения контекста написаны на ассемблере, что позволит вам за несколько дней разобраться в сути вопроса.

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


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

Однако из-за того, что из systick я прыгаю на другую программу, POP {r4,pc} пропускается.
Так вы вернитесь из "другой подпрограммы". Или, если не собираетесь возвращаться, переходите на SysTick не по BL, а по B. И в LR останется магическое число.

 

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


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

Починил, правда, для меня, это шаманством осталось. Я говорил выше, что компилятор создает файл main.s вместо main.c, а так как внутри него я не мог ничего редактировать (он создан компилятором) я решил просто скопировать его и заменить им файл main.c, после этого когда я запустил в шедулере этот код:

    LDR        r0,    =TaskPointer
    LDR     r0, [r0]
    LDR     r0, [r0]
    MOV     r1,    r0
    LDR sp, [r1,#24]
    BX  lr

При этом стэк для задачи я задал вручную вот так:

int Stack_task1[512]={0x00000000,0xfffffff9,0x00000007,0xe000e000,0x200021e8,0x200021e8,0x200021
c4,0x08000211,0x08000212,0x21000000};

поместив в него нужные метки и то самое число. С этим стэком я уже запускал до этого (на main.c) и ничего не работало, однако тут удалось: после BX LR он вышел из шедулера на хэндлер, выполнил POP {pc} и прыгнул на задачу. Метод скорее всего "напролом" но от него уже можно плясать. Спасибо всем за советы и помощь, буду работать дальше.

 

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


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

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

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

Гость
Ответить в этой теме...

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

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

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

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

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

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