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

Проблема со стэком при переключении задач на STM32

Здравствуйте. Обнаружил в своем проекте ошибку, и никак не могу понять, в чем причина.

Сначала опишу то, где это возникает:

Я делаю простейший переключатель задач, используя 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} приведены на рисунках.

 

91f51dfa2ea5.png

 

d4cf381ec7ca.png

 

Как видно все отработало нормально и число 0xfffffff9 осталось на месте.

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

 

0a0a1e4e9e9f.png

 

ed7fd0099e8f.png

 

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

 

8b98669a6dbc.png

 

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

Причем самое интересное, если поменять порядок указателей например на

 

TaskTableStart
    DCD ddd1
    DCD ddd3
    DCD ddd2
    DCD ddd4

 

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

 

Почему в случае с первой задачей стэк по метке оказался без изменений, а во втором случилась такая беда?

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


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

Проще всего наверное, скачать CoOX, там простенькая ассемблерная программка переключения и сравнить.

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


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

да уже обсуждали, ноги растут оттуда, откуда не надо качать какос и другой ОС....

 

Теперь вопрос, что есть за 4 бита до? Имелось ввиду за 4 байта? То есть у первой задачи стэк сохраняется куда надо, а у второй смещено на 1 слово 4 байтное в памяти?

 

А если стэки именно на это слово? Может там есть какое дурное правильно на выравнивание адресов? Указатель стэка на последние НЕ пустое слово в обоих задачах? Может в какой-то ошиблись?

 

я вот сейчас поглядел документацию....

 

LDR        r0,    =TaskPointer
    LDR     r0, [r0]
    LDR     r0, [r0]
    MOV     r1,    r0
    LDR     SP, [r1,#24]
    BX      LR

 

это выглядит странно,

в r0 пихаете метку TaskPointer (адрес я так понимаю)

в r0 пихаете данные по адресу r0, то есть фактически адрес TaskPointer

зачем опять LDR r0, [r0] ?

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

 

ну и как то странно выглядят данные в стэке, здесь

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

другая последовательность... ну и константа у вас F9, то есть работа с основным стэком....

 

думаю из за неправильного смещения в стэке после первой задачи вы возвращаетесь сдвинуто, и запуск второй задачи выбирает криво... все таки я бы разделил стэки и Маин стэк использовал для нужд ОС, а задачам раздал бы программ стэки.

 

 

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


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

Второй LDR r0, [r0] грузит метку TaskTableStart ее адрес смещен на 4 байта относительно TaskPointer и используется как активный указатель плюс его адрес потом записывается по достижению конца списка. По поводу возвращения из 1 задачи я уже написал: я поставил последовательность - 1,3,4,2 задача. Они все отработали нормально до 2ой. Меня смущает, что все указатели и описания задач при этом абсолютно одинаковы и отличаются лишь номером. А на 24 смещено, из за того что в ddd1 со смещением на 24 байта лежит указатель на стэк задачи, которым я командой LDR sp, [r1,#24] подменяю текущий.

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

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


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

А если стэки именно на это слово? Может там есть какое дурное правильно на выравнивание адресов? Указатель стэка на последние НЕ пустое слово в обоих задачах? Может в какой-то ошиблись?

Я думаю ТС-у и невдомёк, что Cortex-M3 может опционально выравнивать стек на 8 при выполнении стекинга (при прерывании).

А всё потому, что "не читатель, а писатель..." :smile3046:

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


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

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

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

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

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

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

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

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

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

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