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

Omnicake

Участник
  • Постов

    56
  • Зарегистрирован

  • Посещение

Репутация

0 Обычный

Информация о Omnicake

  • Звание
    Участник
    Участник

Информация

  • Город
    Array
  1. Второй LDR r0, [r0] грузит метку TaskTableStart ее адрес смещен на 4 байта относительно TaskPointer и используется как активный указатель плюс его адрес потом записывается по достижению конца списка. По поводу возвращения из 1 задачи я уже написал: я поставил последовательность - 1,3,4,2 задача. Они все отработали нормально до 2ой. Меня смущает, что все указатели и описания задач при этом абсолютно одинаковы и отличаются лишь номером. А на 24 смещено, из за того что в ddd1 со смещением на 24 байта лежит указатель на стэк задачи, которым я командой LDR sp, [r1,#24] подменяю текущий.
  2. Здравствуйте. Обнаружил в своем проекте ошибку, и никак не могу понять, в чем причина. Сначала опишу то, где это возникает: Я делаю простейший переключатель задач, используя 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 То сработает первая задача, переключится на третью, третья переключится на вторую и та опять выдаст ошибку. Понять такую ненависть программы к двойке я не могу, потому спрашиваю здесь. Почему в случае с первой задачей стэк по метке оказался без изменений, а во втором случилась такая беда?
  3. Починил, правда, для меня, это шаманством осталось. Я говорил выше, что компилятор создает файл 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} и прыгнул на задачу. Метод скорее всего "напролом" но от него уже можно плясать. Спасибо всем за советы и помощь, буду работать дальше.
  4. Видимо это Keil uVision и делает: после того как я добавил ассемблерные вставки в main, написанный на C, он создал автоматически файл main.s и там функция SysTick_Handler { scheduler(); } Выглядит вот так SysTick_Handler PUSH {r4,lr} BL systick POP {r4,pc} Однако из-за того, что из systick я прыгаю на другую программу, POP {r4,pc} пропускается. Значит, судя по всему, нужно делать это внутри шедулера.
  5. Тут возможно я недостаточно подробно описал, при входе в прерывание там действительно лежит число EXC_RETURN но затем, из за того что в обработчике у меня стоит вызов другой программы (а именно переключателя задач), он уходит на ту программу, помещая в LR адрес возврата.
  6. 1. Ну у меня и отображается активным MSP все это время, и до прерывания и внутри него. Командой LDR я меняю указатель на метку Stack_task1 - массив из 512 чисел, который я взял за стэк задачи. 2. Как корректно класть туда эту структуру? Заранее прописывать ее в массив в самой задаче или загонять через PUSH необходимые регистры?
  7. Локальные стэки я задал, в каждой задаче у меня прописано Stack_task1[512]. LDR sp, [r1,#24] как раз и грузить адрес метки Stack_task1. А по поводу Может я чего-то не увидел, но напрямую через команду MOV в PC на Cortex M3 вроде бы писать нельзя, компилятор мне выдает ошибку. Да и в инструкции написано, что грузятся значения в PC только через LDR или POP, а для этого нужно магическое число куда-то положить (я и положил его в стэк задачи).
  8. Видимо действительно у меня нет понимания. Я решаю, извините за каламбур, задачу переключения задач в ассемблере. Для этого хотелось использовать прерывание от системного таймера, так как там вполне ясный и понятный режим срабатывания (время прошло - сработало прерывание - задача сменилась). Про PendSV мне удалось найти только информацию о том, что он пригодится при переключении задач. Но то как его вызывать, как он срабатывает и что делает - нет. Каким образом тогда построить стэк, чтобы при записи числа EXC он правильно подцеплялся?
  9. Используется MSP, число там лежит точно, так как в симуляторе я могу свободно просматривать память и пошагово следить за программой. После входа в прерывание у меня лежит LR возврата на main, а мне нужно из прерывания уйти в другую задачу, я и меняю LR внутри обработчика но по выходу на задачу процессор остается в обработке прерывания.
  10. Попробовал сделать такое после входа в обработчик 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. Что я не так сделал?
  11. Да, находился в Handler mode. Под "простым выходом из прерывания" я имел ввиду процесс входа в прерывание и выход на ту же функцию, откуда оно было вызвано, потому что при таком режиме все работало нормально. Сейчас нет возможности проверить ваш способ, вечером попробую. Спасибо за совет.
  12. Перепробовал вчера такие варианты: 1) Запись в LR или PC значения EXC_RETURN уводит в HardFault исключение, то есть он воспринимает это как просто переход в неадреуемую область. 2) Проверил, что пишется в стэк при простом выходе из прерывания (то есть в шедулере оставил просто команду BX LR), и скопировал записанные значения в стэк задачи. Результат тот же, значения он не подцепил. Хотя в стэк были записаны и PC регистры и LR и значение FFFFFFF9(EXC_RETURN).
  13. Оно и происходит внутри прерывания, ведь scheduler() выполняется внутри SysTick_Handler. Сейчас обратил внимание на другую особенность при обработке задачи. В Cortex-M# есть регистр xPSR, которые содержит в себе под-регистр ISR в момент до прерывания значение этого регистра равно 0, при входе в прерывание оно изменяется на 15 (что как я понимаю соответствует прерыванию от системного таймера), однако при выходе на task1 ISR не обнуляется, а так и остается равным 15. Есть ли возможность ручной корректировке этого бита, и можно ли с помощью этого решить проблему?
  14. Таймер точно работает и генерирует прерывания, для примера убрал вызов шедулера и поставил простейшую команду i++, он корректно увеличивает ее через равные промежутки времени. В инструкции меня смущает строка "The processor saves an EXC_RETURN value to the LR on exception entry." Получается когда я заменяю LR внутри прерывания на LR задачи, я затираю тот самый EXC_RETURN value?
×
×
  • Создать...