Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Выход из handler-mode в cortex-m3
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Omnicake
Здравствуйте, столкнулся с проблемой. Сделал обработку прерывания на системный таймер Systick, во время обработки прерывания производится изменения битов и в конце грузятся значения регистров LR и SP для другой подзадачи (тем самым реализовано переключение задач), однако при выходе на задачу процессор почему-то остается в handler-mode - то есть по сути не выходит из прерывания. Соответственно на последующие срабатывания прерывания от таймера процессор никак не реагирует. Прочитал, что для корректного переключения режимов, надо в регистр LR заносить специальное значение EXC_RETURN, однако как это сделать если в LR мне одновременно нужно занести и значение для переключения на задачу? Как быть?
1113
разве режим - Handler или Thread - каким-либо образом влияют на факт срабатывания прерывания или факт исполнения соответствующего обработчика?
Omnicake
Как мне казалось, handler-mode включается при обработке прерывания, а при его выходе возвращается в thread-mode с обнулением флага прерывания, что позволяет прерыванию снова сработать. Возможно я ошибаюсь, но в противном случае я не могу понять почему прерывание от таймера у меня срабатывает только один раз.
1113
приведите код настройки таймера и код обработчика
Omnicake
Инициализация таймера
Код
    AREA HEAP, CODE, READONLY
    
systick        PROC
            EXPORT systick
            MOV R0,#0x03e8; 0x03e8 = 1000 - количество тактов до прерывания
            MOV    R1,#0xe000e000
            STR    R0,[r1,#0x14]
            STR    R0,[r1,#0x18]
            MOVS R0,#0x07
            STR    R0,[r1,#0x10]
            ENDP        
            BX LR
            END

Обработчик вызывается из main.c таким образом
Код
void SysTick_Handler()
{
scheduler();
}

В scheduler() выполняются следующие действия:
Код
    LDR    r0,    =TaskPointer
    LDR     r0, [r0]
    LDR     r0, [r0]
    MOV     r1,    r0
        LDR sp, [r1,#24]
    LDR lr, [r1,#16]
    BX  LR

Где TaskPointer - это массив в котором содержится определенная информация о задачах, которые нужно переключать, соответственно [r1,#24] - адрес указателя стэка для задачи 1, [r1,#16] - значение pc регистра для задачи 1.
После BX LR прграмма выходит на зацикленную задачу task1.c
Код
int task1(des1* ddd)
{
int i, j, x, y;
ddd->temp = 0x12345678;
while(1)
  for( i = 0; i < 30000; i++ )
      for( j = 0; j < 30000; j++ )
    {
     x = 1;
     y = x;
     x = y;
    }
}

И на ней и остается, то есть при попытке поставить breakpoint на моменте до входа в scheduler() программа не останавливается а продолжает выполнять task1.c
1113
инициализация и обработчик - правильные. но для переключения режимов добавьте в шедулере перед bx lr

orr lr, lr, #0x4
Omnicake
Не помогло, на задаче он все также в handler-mode и на прерывание не возвращается.
1113
предлагаю вам отладиться без переключения контекста. имхо у вас со стеками проблема, а не с таймерами. уберите из обработчика изменения указателя стэка.
Omnicake
Забыл кстати упомянуть, что компилируется все это с одним ворнингом ..\scheduler.asm(40): warning: A1581W: Added 2 bytes of padding at address 0x3e, возможно в этом причина.
Также в дизасемблере при входе в scheduler() выполняется команда PUSH{r4,lp} а на выходе - POP {r4,pc}. Попробовал сейчас оставить в шедулере только BX LR (то есть возврат на main) режим процессора переключился на thread, как и должно быть.
1113
Цитата(Omnicake @ May 11 2014, 12:15) *
Забыл кстати упомянуть, что компилируется все это с одним ворнингом ..\scheduler.asm(40): warning: A1581W: Added 2 bytes of padding at address 0x3e, возможно в этом причина.
нет. компилятор для выравнивания границ добавил два "пустых" байта.
Omnicake
Попробовал убрать загрузку указателя стэка - ничего не изменилось.

А есть ли в cortex-m3 аналог команды reti? Я поспрашивал у людей, говорят на других процессорах она помогает из прерывания выходить.
1113
а вы уверены, что таймер считает, а не находится в выключенном состоянии из-за отладки или режима сна какого-нибудь?

Цитата(Omnicake @ May 11 2014, 13:22) *
Попробовал убрать загрузку указателя стэка - ничего не изменилось.

А есть ли в cortex-m3 аналог команды reti? Я поспрашивал у людей, говорят на других процессорах она помогает из прерывания выходить.
нет.
Цитата
Exception return
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.
The processor saves an EXC_RETURN value to the LR on exception entry. The exception mechanism relies on this value to detect when the processor has completed an exception handler. Bits[31:4] of an EXC_RETURN value are 0xFFFFFFF. When the processor loads a value matching this pattern to the PC it detects that the operation is a not a normal branch operation and, instead, that the exception is complete. Therefore, it starts the exception return sequence. Bits[3:0] of the EXC_RETURN value indicate the required return stack and processor mode, as Table 2.17 shows.

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


в связи с этим, что у вас в LR перед выполнением bx lr?
Omnicake
Таймер точно работает и генерирует прерывания, для примера убрал вызов шедулера и поставил простейшую команду i++, он корректно увеличивает ее через равные промежутки времени. В инструкции меня смущает строка "The processor saves an EXC_RETURN value to the LR on exception entry." Получается когда я заменяю LR внутри прерывания на LR задачи, я затираю тот самый EXC_RETURN value?
1113
Цитата(Omnicake @ May 11 2014, 13:31) *
Таймер точно работает и генерирует прерывания, для примера убрал вызов шедулера и поставил простейшую команду i++, он корректно увеличивает ее через равные промежутки времени. В инструкции меня смущает строка "The processor saves an EXC_RETURN value to the LR on exception entry." Получается когда я заменяю LR внутри прерывания на LR задачи, я затираю тот самый EXC_RETURN value?
походу так. потому как по его значению "процессор определяет, что это не простой переход, а выход из эксепшена"

... переключение контекста должно происходить только в exception, тогда в какой бы стек не попал LR и какой бы задаче он ни принадлежал, по входу в exception, и, соответственно, по выходу из него значение будет правильным и одинаковым для любой задачи. нужно только откорректировать биты режима процессора.
Omnicake
Оно и происходит внутри прерывания, ведь scheduler() выполняется внутри SysTick_Handler. Сейчас обратил внимание на другую особенность при обработке задачи. В Cortex-M# есть регистр xPSR, которые содержит в себе под-регистр ISR в момент до прерывания значение этого регистра равно 0, при входе в прерывание оно изменяется на 15 (что как я понимаю соответствует прерыванию от системного таймера), однако при выходе на task1 ISR не обнуляется, а так и остается равным 15. Есть ли возможность ручной корректировке этого бита, и можно ли с помощью этого решить проблему?
1113
имхо это не влияет. у вас оно равно 0 потому что прерываний ещё не было. по идее уже разобрались - LR должен содержать конкретные значения, записываемые в него ядром по умолчанию, то есть их не надо изменять. кроме битов режима.
Golikov A.
А правильно я понимаю что LR служит для того чтобы определить откуда мы попали в прерывание и не более того? То есть на самом деле для задачи LR не имеет смысла.
в нем может храниться всего 3 разных значения
0xFFFFFFF1 -return handler mode
0xFFFFFFF9 -return thread mode используя MSP
0xFFFFFFFD -retrun thread mode используя PSP
и запись значения LR в PC просто запускает процесс возврата. То есть если нет вложенных прерываний, и вы всегда попадаете в ваше прерывание из подзадачи, вы можете просто в PC заносить одно из 3 значений выше (какой режим вам нужен) и забыть про LR вообще?


1113
Цитата(Golikov A. @ May 11 2014, 16:42) *
А правильно я понимаю что LR служит для того чтобы определить откуда мы попали в прерывание и не более того? То есть на самом деле для задачи LR не имеет смысла.
в нем может храниться всего 3 разных значения
0xFFFFFFF1 -return handler mode
0xFFFFFFF9 -return thread mode используя MSP
0xFFFFFFFD -retrun thread mode используя PSP
и запись значения LR в PC просто запускает процесс возврата. То есть если нет вложенных прерываний, и вы всегда попадаете в ваше прерывание из подзадачи, вы можете просто в PC заносить одно из 3 значений выше (какой режим вам нужен) и забыть про LR вообще?
верна лишь логика, потому PC тут вообще не причём. определяющим регистром является не PC а LR. если LR имеет одно из указанных значений, процессор вместо тупого перехода по адресу [LR] обновляет его из стэка и только потом переходит.
Golikov A.
а я вот доки почитал повнимательнее...

если говорить про конртекс м3
значение счетчика команд для возврата из прерывания храниться в СТЕКЕ! И восстанавливается во время процедуры выхода из прерывания.
в LR сохраняется режим из которого мы попали в прерывание

команда загрузки LR в PC - это не задание адреса выхода, это кодовая команда запуска процедуры выхода. и в зависимости от кода что лежит в LR, будет из разных мест восстановлен контекст задачи...
то есть другими словами выйти из прерывания можно явно загрузив в PC коды
0xFFFFFFF1, 0xFFFFFFF9, 0xFFFFFFFD.

если загрузим код ....1, то контекст будет восстановлен из MSP, и выйдем мы в hedlre режим
если загрузим код ....9, то контекст будет восстановлен из MSP, но выйдем в thread режим, и дальше будет использоваться как указатель стэка MSP
если код ....D? то как в 9, только PSP.


другими словами понимая задачу ТС, надо делать вот как.

1. Задачи надо запустить с использованием PSP, по умолчанию после ресета все работают на MSP.
2. Во время возникновения прерывания таймера для смены задачи, вам надо сохранить значение PSP, при этом поскольку вы в прерывании у вас используется MSP, в него и сохраняйте PSP прерванной задачи.
3. задать новое значение в PSP для новой задачи
4. записать в PC значение 0xFFFFFFFD, это запустить выход из прерывания с использованием PSP, при этом поскольку вы его подменили на PSP новой задачи, выйдете вы в новую задачу.


Важный момент это создание контекста задачи первый раз, я себе это вижу так. Каждая задача добавляется таким образом
1. Вы переводите работу задачи на PSP, сохраняете в ее стэк все ее локальные переменные,
2. вызываете прерывание смены задачи, или ждете таймера, первый вход в прерывание смены задачи сохранит контекст, и в задачу можно будет попадать по переключению. До первого перехода в прерывание в задачу попасть нельзя, она должна быть запущена явна.


1113
Цитата(Golikov A. @ May 11 2014, 17:56) *
а я вот доки почитал повнимательнее...

в LR сохраняется режим из которого мы попали в прерывание
не так. вот оригинал:
Цитата
The processor performs a vector fetch that reads the exception handler start address from the vector table. When stacking is complete, the processor starts executing the exception handler. At the same time, the processor writes an EXC_RETURN value to the LR. This indicates which stack pointer corresponds to the stack frame and what operation mode the processor was in before the entry occurred.
таким образом в начале выполнения эксепшена в LR ничего кроме "волшебного значения" нет и никогда не будет не зависимо ни от чего.
Цитата(Golikov A. @ May 11 2014, 17:56) *
До первого перехода в прерывание в задачу попасть нельзя, она должна быть запущена явна.
нет - стэк этой задачи не будет изолирован от стэка ядра. надо просто в стэке задачи установить сохранённый PC как адрес main`а этой задачи.
Golikov A.
Цитата
This indicates which stack pointer corresponds to the stack frame and what operation mode the processor was in before the entry occurred.


если исходить что в задачах используем PSP, то если мы попадем в прерывание из задачи в LR будет лежать магическое число говорящая что выходить надо через PSP, если же вложенное прерывание то мы попадем из hendler режима, в котором будет только MSP.
Если бы в LR лежало магическое значение которое не от чего не зависит, то его не надо было бы делать. Зависимость есть. А в других кортексах вариантов больше....

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

задача -> прерывание -> вложенное прерывание, если вернутся по коду с 9 или D на конце мы из вложенного прерывания выйдем в задачу, а не в прошлое прерывание, и будет ваще беда! кусок кода потеряется, и стэк раздуется, если так делать часто он ваще кончится...


Цитата
нет - стэк этой задачи не будет изолирован от стэка ядра.

в данном случая я имею ввиду что если основной метод переключения задач, это задание PSP на стэк задачи и выход из прерывания, то так можно делать только если начальный стэк задачи проинициализирован в состояние которое он принимает при заходе в прерывание. Самый простой способ инициализации - войти в прерывание, хотя наверное нереальный, и все таки придется это сделать ручками
1113
Цитата(Golikov A. @ May 11 2014, 19:03) *
Самый простой способ инициализации - войти в прерывание, хотя наверное нереальный, и все таки придется это сделать ручками
тогда шедулер должен знать и проверять, в первый или не в первый раз он переключает эту задачу. делать такие проверки 10 тыщ раз в секунду не разумно по сравнению с единовременной инициализацией стэка задачи десятком слов.
Golikov A.
вот и я о том же думаю...
но с другой стороны он все равно проверяет активна ли задача, придержана и так далее... , флаг инициализации может быть среди них...
какой-то контроль все равно должен быть
Omnicake
Перепробовал вчера такие варианты:
1) Запись в LR или PC значения EXC_RETURN уводит в HardFault исключение, то есть он воспринимает это как просто переход в неадреуемую область.
2) Проверил, что пишется в стэк при простом выходе из прерывания (то есть в шедулере оставил просто команду BX LR), и скопировал записанные значения в стэк задачи. Результат тот же, значения он не подцепил. Хотя в стэк были записаны и PC регистры и LR и значение FFFFFFF9(EXC_RETURN).
Golikov A.
Цитата
Запись в LR или PC значения EXC_RETURN уводит в HardFault исключение

а в стэке в этот момент было записано куда вернуться из прерывания? Вы находились в handler режиме?

Цитата
Проверил, что пишется в стэк при простом выходе из прерывания

пишется в стэк не при выходе, а при входе, при выходе из стэка читается куда выйти. А значение FFFFFFF9 проводит выход по стеку не задачи, а главному стэку. Надо было выходить по FFFFFFFD, при этом в LR ничего писать не надо, только в PC


надо попробовать
1. войти в прерывание,
2. в обработчике записать в маин стэк данные как будто-то вошли из какой-то известной функции
3. записать в PC значение FFFFFFF9


утверждаю что после этого попадете в эту функцию...
Omnicake
Да, находился в Handler mode. Под "простым выходом из прерывания" я имел ввиду процесс входа в прерывание и выход на ту же функцию, откуда оно было вызвано, потому что при таком режиме все работало нормально. Сейчас нет возможности проверить ваш способ, вечером попробую. Спасибо за совет.
Omnicake
Цитата
надо попробовать
1. войти в прерывание,
2. в обработчике записать в маин стэк данные как будто-то вошли из какой-то известной функции
3. записать в PC значение FFFFFFF9

Попробовал сделать такое после входа в обработчик
Код
        LDR    r0,    =TaskPointer
    LDR     r0, [r0]
    LDR     r0, [r0]
    MOV     r1,  r0
    LDR sp, [r1,#24];Загрузил стэк программы
    MOVW R2,#0x00d0; в котором по адресу 0x200000d0
    MOVT R2,#0x2000; положил число 0xFFFFFFF9
    LDR pc, [r2]; Загрузил его в PC

И улетел на HardFault. Что я не так сделал?
Сергей Борщ
Цитата(Omnicake @ May 12 2014, 15:29) *
И улетел на HardFault. Что я не так сделал?
Какой стек используется, MSP или PSP? Есть подозрение, что используется PSP, тогда как в момент возврата по вашему магическому числу сотояние восстанавливается из PSP.

Прочитал ветку (каюсь, по диагонали). Не могу понять - зачем вы чешете правое ухо левой ногой? После входа в обработчик у вас в LR уже лежит нужное для выхода магическое число. Хотите подменить адрес возврата - меняйте его в сохраненном на стеке в момент входа в обработчик контексте. Потом стандартный возврат из любой функции - bx LR. Все. Если вам нужно сходить из обработчика куда-то еще - делайте push lr, ходите как обычно и в конце делайте pop pc. Остальной механизм при этом сработает сам, без всяких сохранений магического числа по магическому адресу 0x200000d0. Кстати, а по этому адресу действительно лежит нужное число? Не может там случайно оказаться мусор?
Omnicake
Используется MSP, число там лежит точно, так как в симуляторе я могу свободно просматривать память и пошагово следить за программой. После входа в прерывание у меня лежит LR возврата на main, а мне нужно из прерывания уйти в другую задачу, я и меняю LR внутри обработчика но по выходу на задачу процессор остается в обработке прерывания.
adnega
Цитата(Omnicake @ May 12 2014, 18:16) *
Используется MSP, число там лежит точно, так как в симуляторе я могу свободно просматривать память и пошагово следить за программой. После входа в прерывание у меня лежит LR возврата на main, а мне нужно из прерывания уйти в другую задачу, я и меняю LR внутри обработчика но по выходу на задачу процессор остается в обработке прерывания.

В соседней Вашей ветке про переключение задач Вам подробно ответили. Что-то еще не ясно?
Вероятно, что нет точного понимания.
Регистр PC не так прост, как в других архитектурах. Используется для переходов, но не только для них.
Как Вы узнаете, что прерывание нужно завершить, если нет аналога reti?
Если обработчик нужно закончить и передать управление в другое место, то меняйте данные в стековом кадре -
после записи магического EXC_RETURN в PC будет произведен выход и PC перезапишется восстановленным со стека (измененным) значением.
Но если там находится не стековый кадр main, а стековый кадр вложенного прерывания (main->ISRx->Systick), то поимем при таком подходе,
мягко говоря, не то что ожидалось: вместо подмены адреса возврата в main, переключимся на main, не закончив ISRx.
Использование PendSV с низшим приоритетом очень помогает (упрощает жизнь).
Какую задачу Вы решаете?
Omnicake
Видимо действительно у меня нет понимания. Я решаю, извините за каламбур, задачу переключения задач в ассемблере. Для этого хотелось использовать прерывание от системного таймера, так как там вполне ясный и понятный режим срабатывания (время прошло - сработало прерывание - задача сменилась). Про PendSV мне удалось найти только информацию о том, что он пригодится при переключении задач. Но то как его вызывать, как он срабатывает и что делает - нет. Каким образом тогда построить стэк, чтобы при записи числа EXC он правильно подцеплялся?
adnega
Цитата(Omnicake @ May 12 2014, 20:17) *
Видимо действительно у меня нет понимания. Я решаю, извините за каламбур, задачу переключения задач в ассемблере. Для этого хотелось использовать прерывание от системного таймера, так как там вполне ясный и понятный режим срабатывания (время прошло - сработало прерывание - задача сменилась). Про PendSV мне удалось найти только информацию о том, что он пригодится при переключении задач. Но то как его вызывать, как он срабатывает и что делает - нет. Каким образом тогда построить стэк, чтобы при записи числа EXC он правильно подцеплялся?

Понимаю тягу к ассемблеру Cortex-M, но считаю, что это всего лишь инструмент.
Для переключения контекста не обязательно писать на Си или Асм - нужно разобраться в архитектуре.
SysTick это всего лишь таймер, одинаковый для всех производителей микроконтроллеров на ядре Cortex-M.
Для переключения задач Вам нужно либо в задаче вызавать системную функцию, в которой произойдет переключение.
Либо переключить задачу по прерыванию. В том числе от таймера. В том числе от таймера SysTick.
Можно переключать задачи в SysTick, но в случае, если SysTick у Вас с самым низким приоритетом - это гарантирует, что Вы точно знаете положение
стекового кадра main. Можно использовать два стека, что в какой-то степени решит проблему вложенных прерываний. Но когда Вы сделаете такой
переключатель задач по таймеру, вряд ли легко сможете переключать задачи где-либо еще. Задачи в некоторый случаях (где есть ассинхронная пауза)
будут "тупить" до момента сработки таймера SysTick.

Если в конце SysTick взводить PendSv (ровно как и в функциях ядра), то переключение будет:
- гарантированно происходить после каждого срабатывания SysTick;
- в функциях ядра;
- гарантированно происходить до момента передачи управления в main.

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

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

2.
Цитата
LDR sp, [r1,#24];Загрузил стэк программы
MOVW R2,#0x00d0; в котором по адресу 0x200000d0
MOVT R2,#0x2000; положил число 0xFFFFFFF9
LDR pc, [r2]; Загрузил его в PC


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

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

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

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

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

далее в прерывании вам надо, сохранять PSP задачи из которой пришли, далее РSP устанавливать на стэк нвоой задачи, и записывать магическое число. Все!
1113
Цитата(Omnicake @ May 12 2014, 19:17) *
Про PendSV мне удалось найти только информацию о том, что он пригодится при переключении задач. Но то как его вызывать, как он срабатывает и что делает - нет.
как систик, только вызывается не аппаратно а програмно там и тогда когда вам надо. этот эксепшен используют из мэйна для запуска операционки, то есть для входа в первую задачу. ну а все последующие переключения задач - в систик.
Omnicake
Цитата
вам надо сделать задачи со своими локальными стэками
положить в них структуру которая кладется когда вызовиться прерывание из этой задача, в место где хранится РС положить начало вашей задачи.

Локальные стэки я задал, в каждой задаче у меня прописано Stack_task1[512]. LDR sp, [r1,#24] как раз и грузить адрес метки Stack_task1.
А по поводу
Цитата
если вы находитесь в hendlre режиме, как только вы в счетчик команд запишите 0xFFFFFFF9, обращаю внимание именно в счетчик команд, ни в стэк, ни в память, а именно в него.

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

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 пунктам....
Omnicake
1. Ну у меня и отображается активным MSP все это время, и до прерывания и внутри него. Командой LDR я меняю указатель на метку Stack_task1 - массив из 512 чисел, который я взял за стэк задачи.
2. Как корректно класть туда эту структуру? Заранее прописывать ее в массив в самой задаче или загонять через PUSH необходимые регистры?
Сергей Борщ
Цитата(Omnicake @ May 12 2014, 17:16) *
в симуляторе я могу свободно просматривать память и пошагово следить за программой. После входа в прерывание у меня лежит LR возврата на main,
Начните с чтения документации. В момент входа в обработчик исключения адрес возврата вместе с содержимым некоторых регистров кладется на стек. В LR заносится магическое число. Если вы наблюдаете в LR адрес возврата - выкиньте свой симулятор. Или вы попадаете в исключение каким-то нестандартным методом, вроде прямого вызова функции?
Omnicake
Цитата
В LR заносится магическое число. Если вы наблюдаете в LR адрес возврата - выкиньте свой симулятор. Или вы попадаете в исключение каким-то нестандартным методом, вроде прямого вызова функции?

Тут возможно я недостаточно подробно описал, при входе в прерывание там действительно лежит число EXC_RETURN но затем, из за того что в обработчике у меня стоит вызов другой программы (а именно переключателя задач), он уходит на ту программу, помещая в LR адрес возврата.
Сергей Борщ
Цитата(Omnicake @ May 13 2014, 09:37) *
он уходит на ту программу, помещая в LR адрес возврата.
Так сохраните старое значение LR куда-нибудь. Например, на стек. И потом со стека восстанавливайте сразу в PC командой POP.
Omnicake
Видимо это Keil uVision и делает: после того как я добавил ассемблерные вставки в main, написанный на C, он создал автоматически файл main.s и там функция
Код
SysTick_Handler
{
scheduler();
}

Выглядит вот так
Код
SysTick_Handler
     PUSH {r4,lr}
     BL systick
     POP {r4,pc}

Однако из-за того, что из systick я прыгаю на другую программу, POP {r4,pc} пропускается. Значит, судя по всему, нужно делать это внутри шедулера.
1113
Omnicake, ваше желание разобраться похвально, но такими темпами вы будете делать это ещё полгода. предлагаю вам почитать о coocox os. она написана очень просто, имеет документацию на русском, процедуры переключения контекста написаны на ассемблере, что позволит вам за несколько дней разобраться в сути вопроса.
Omnicake
Хорошо. Спасибо.
Сергей Борщ
Цитата(Omnicake @ May 13 2014, 11:11) *
Однако из-за того, что из systick я прыгаю на другую программу, POP {r4,pc} пропускается.
Так вы вернитесь из "другой подпрограммы". Или, если не собираетесь возвращаться, переходите на SysTick не по BL, а по B. И в LR останется магическое число.
Omnicake
Починил, правда, для меня, это шаманством осталось. Я говорил выше, что компилятор создает файл 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} и прыгнул на задачу. Метод скорее всего "напролом" но от него уже можно плясать. Спасибо всем за советы и помощь, буду работать дальше.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.