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

 
 
> Проблема со стэком при переключении задач на STM32
Omnicake
сообщение May 17 2014, 10:30
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 56
Регистрация: 12-01-14
Из: Омск
Пользователь №: 80 002



Здравствуйте. Обнаружил в своем проекте ошибку, и никак не могу понять, в чем причина.
Сначала опишу то, где это возникает:
Я делаю простейший переключатель задач, используя Keil Uvision и процессор STM32. Диспетчер срабатывает от прерывания таймера и в зависимости от статуса и значения «количества шагов» либо выходит из прерывания на нужную задачу, либо переключается на следующую. Реализовано это таким образом:
1. Массив указателей на задачи.

Код
TaskPointer
    DCD    TaskTableStart
TaskTableStart
    DCD ddd1
    DCD ddd2
    DCD ddd3
    DCD ddd4
TaskTableEnd
    END


Где ddd – указатель на задачу, вида:

Код
ddd1={1,1,4,0,(int*)task1,(int*)task1,(int*)Stack_task1,(int*)Stack_task1};


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

Код
int Stack_task1[512]={0xfffffff9,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,(int*)task1,(int*)task1,0x21000000};


Структура полностью повторяет то, что делает Cortex-M3 при срабатывании прерывания (0 поставил на месте регистров R1-R4,R12 так как их состояние при первом запуске неважно)
При входе в прерывание диспетчер вызывается так

Код
Systick_Handler
{
PUSH {LR}
BL scheduler
POP {pc}
}


Вызов задачи делаю так:
Код
    LDR        r0,    =TaskPointer
    LDR     r0, [r0]
    LDR     r0, [r0]
    MOV     r1,    r0
    LDR     SP, [r1,#24]
    BX      LR


Тем самым после BX LR идет выход из диспетчера на команду POP {pc} и срабатывает выход из прерывания на задачу по метке записанной в стэке.
Смену указателей на задачу делаю прибавлением 4 битов к текущему адресу и записью в TaskTableStart. Тем самым перед следующим срабатыванием диспетчера указатель заменяется.
Задачи task1, task2, task3, task4 абсолютно идентичны (отличаются только метками) .
И вот тут возникает проблема со стэками этих задач.
При первом срабатывании диспетчер подгружает указатель и стэк для первой задачи и запускает ее, выходя из прерывания и потом вновь приходит на прерывание. Вид стэка задачи при первом заходе на прерывание и втором (после выполнения команды PUSH {LR} приведены на рисунках.





Как видно все отработало нормально и число 0xfffffff9 осталось на месте.
Однако при переключении на вторую задачу и выполнение тех же самых действий получается вот так:





Причем если выбрать адрес за 4 бита до метки до число 0xfffffff9, используемое для выхода из прерывания окажется там.



Однако так как я вызываю стэк по метке при выполнении команды POP {pc} туда грузится там самая 0x00000001 и уводит в ошибку.
Причем самое интересное, если поменять порядок указателей например на

Код
TaskTableStart
    DCD ddd1
    DCD ddd3
    DCD ddd2
    DCD ddd4


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

Почему в случае с первой задачей стэк по метке оказался без изменений, а во втором случилась такая беда?
Go to the top of the page
 
+Quote Post



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

 


RSS Текстовая версия Сейчас: 21st July 2025 - 01:11
Рейтинг@Mail.ru


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