Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Cortex-A9 вложенные прерыания
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Genadi Zawidowski
Появился вопрос в процессе одевания на голое железо обычной системы с super loop. Железо - Renesas RZ/A1L.

Что есть:
Вот такой код обработчика в ассемблере:

Код
IRQHandler:

/* Save interrupt context on the stack to allow nesting */
    sub        lr, lr, #4
    stmfd   sp!, {lr}
    mrs     lr, SPSR
    stmfd   sp!, {r0, lr}

    // save VFP/Neon data registers
    VPUSH {d0-d15}    // same as s0-s31
    // save VFP/Neon FPSCR register
    FMRX        r0, fpscr
    stmfd   sp!, {r0-r3, r4, r12, lr}


    ldr        r2, =IRQHandlerSafe
    mov        lr, pc
    bx        r2     /* And jump... */

    ldmia   sp!, {r0-r3, r4, r12, lr}
    // restore VFP/Neon FPSCR register
    FMXR        fpscr, r0
    // restore VFP/Neon data registers
    VPOP   {d0-d15}    // same as s0-s31

    ldmia   sp!, {r0, lr}
    msr     SPSR_cxsf, lr
    ldmia   sp!, {pc}^


И его продолжение в C:

Код
void IRQHandlerSafe(void)
{
    /* const uint32_t icchpir = */ (void) INTC.ICCHPIR;
    const uint32_t icciar = INTC.ICCIAR;
    (* intc_func_table [icciar & 0x03FF]) ();         /* Call interrupt handler */
    INTC.ICCEOIR = icciar & 0x1FFF;
}


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

Установка при инициализации процессора значения в регистре priority mask на менее приоритетное прерывание - оно естественно запрещается...


Вопрос - как это должно тут выглядеть? (на STM32 с архитектурой Cortex-M4 и Cortex-M7 это всё работает, с использованием тамошних механизмов BASEPRI и остального).


зы: картинки просто как иллюстрация.
Genadi Zawidowski
Почитал... понял что тут (в armv7-a) всё совсем не так просто...


Если процессор стартует в supervisor mode и далее в нём работает, прерывания используют свой стек. А если я запущу в IRQ mode? при входе в прерывание не будет происходить перезагрузка SP и прерывания будут вложенными?
AndrejM
загляните в примеры для freertos , там есть для cortex-a9 реализация FreeRTOS_IRQ_Handler в файле portASM.s .
стартуете в supervisor , в обработчике снова в него переключаетесь
FreeRTOS_IRQ_Handler

; Return to the interrupted instruction.
SUB lr, lr, #4

; Push the return address and SPSR
PUSH {lr}
MRS lr, SPSR
PUSH {lr}

; Change to supervisor mode to allow reentry.
CPS #SVC_MODE

; Push used registers.
PUSH {r0-r4, r12}
............................
zltigo
QUOTE (Genadi Zawidowski @ Mar 7 2016, 01:32) *
Почитал... понял что тут (в armv7-a) всё совсем не так просто...

Наоборот - все просто, если о том, что в ядре - есть два прерывания IRQ и FIQ. FIQ, естественно, прерывает IRQ.
То есть такого типа вложенность есть. Любые другие форусы с вложеностью - ручками.
Собственно контролеры прерываний это не как у мелких кортексов - не пренадлежность ядра и могут быть разнообразными в зависимости от производителя. Что прикручивает STM не смотрел.
QUOTE
А если я запущу в IRQ mode? при входе в прерывание не будет происходить перезагрузка SP и прерывания будут вложенными?

ВСЕГДА устанавливаться начало собственного стека и соответственно никакой автоматической вложенности не может быть в принципе.

Genadi Zawidowski
Не прервёт ли исполнявшееся IRQ другое IRQ с большим приоритетом? Я про ситуацию "рукопашного" выхода из прерывания - не вернут ли меня назад, к началу обработчика? ARM-овский документ есть, но как-то в явном виде эту ситуацию я пока не нашел... чугунный слог, которым там всё описано, просто тяжело читать "насковзь".
Genadi Zawidowski
Разобрался... Самое необычное, что в старом проекте для AT91SAM7S64 было именно так сделано...
Разобрался снова в коде более чем пять лет назад писанном... Я не мог догадаться, что в результате начинает использоваться два стека. А я всё искал способ "выгрести" всё из стека IRQ и перенести в главный (SVC).

Обработчик теперь выглядит так:
Код
IRQHandler:

        /* Save interrupt context on the stack to allow nesting */
        sub        lr, lr, #4
        stmfd   sp!, {lr}
        mrs     lr, SPSR
        stmfd   sp!, {r0, lr}

        msr     CPSR_c, #ARM_MODE_SVC | I_BIT    // added *****
        stmfd   sp!, {r1-r3, r4, r12, lr}

        // save VFP/Neon data registers
        VPUSH    {d0-d15}    // same as s0-s31
        // save VFP/Neon FPSCR register
        FMRX    r2, fpscr
        PUSH    {r2}

        ldr        r2, =IRQHandlerSafe
        mov        lr, pc
        bx        r2     /* And jump... */

        // restore VFP/Neon FPSCR register
        POP        {r2}
        FMXR    fpscr, r2
        // restore VFP/Neon data registers
        VPOP   {d0-d15}    // same as s0-s31

        ldmia   sp!, {r1-r3, r4, r12, lr}
        msr     CPSR_c, #ARM_MODE_IRQ | I_BIT    // added *****

        ldmia   sp!, {r0, lr}
        msr     SPSR_cxsf, lr


Остались ещё проблемы с маской приоритетов, но это уже не страшно...
Genadi Zawidowski
Как выяснилось при тестировании на минимальной программе:
прерывания действительно "вложенны", обрабатываются так как надо (в нужном порядке соответственно назначенным приоритетам). Но!
После возникновения первого же прерывания основная программа перестает выполняться.
Вот RPR (running priority) и CPSR в разных точках:

Основная программа до возникновения первого из прерываний
FF 800001d3

Прерывание с меньшим приоритетом
10 60000193

Прерывание с большим приоритетом
08 80000193

Состояние RPR=FF больше не появляется ни разу.

UPD:
Код
После возникновения первого же прерывания основная программа перестает выполняться

Всё нормально, просто тест был написан таким образом, что аппаратные прерывания возникали так часто (и с такими задержками внутри обработчиков), что в основной цикл никогда не возвращались...
Genadi Zawidowski
Странно...
Установка правильны образом сформированного значения в GICC_PMR должна запрещать прерывания с указанным и меньшим приоритетом. Однако, в моем случае почему-то иногда не срабатывает... __ISB() и __DSB() пробовал.
Присвоением значения в этот регистр ограждается критическая секция (работа со связанным списком из основного цикла и из прерывания не с самым высоким приоритетом. В системе существует ещё одно прерывание с более высоким приоритетом - и не имеет отношения к этому списку. Так замена избирательного запрещения прерываний в этом месте на __disable_irq() (модификация I в CPSR) и соответственно разрешение - даёт нормально работающую программу.
jcxz
Цитата(zltigo @ Mar 7 2016, 22:58) *
Наоборот - все просто, если о том, что в ядре - есть два прерывания IRQ и FIQ. FIQ, естественно, прерывает IRQ.

Не естестественно wink.gif
Насколько я помню ARM7: при входе в режим IRQ, процессор автоматически устанавливает запрет прерываний IRQ; при входе в режим FIQ автоматически устанавливает запрет FIQ & IRQ.
Но ничто не запрещает программисту хоть в начале ISR любой из этих запретов снять или установить дополнительно и тогда и IRQ сможет прервать FIQ-обработчик если очень хочется.
Как впрочем и вложенное прерывание (IRQ в IRQ или FIQ в FIQ) может возбудиться, но только надо быть аккуратным тут, так как будут перезаписаны теневые регистры регистрового файла для данного режима
(SP, LR, SPSR для IRQ-режима и ещё больше регистров для FIQ-режима).
zltigo
QUOTE (jcxz @ Mar 10 2016, 06:51) *
Не естестественно wink.gif

"Естественно" писалось о аппаратном поведении встроенного в ядро механизма IRQ/FIQ, а не о том, как его можно расширять контроллерами прерываний и корректировать программно.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.