Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: FIQ+FreeRTOS на LPC2146
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
meister
Здравствуйте,

не могу заставить работать эту операционку с FIQ. С IRQ у меня все работает, но мне покоя не дает этот простаивающий ресурс, тем более, что большого запаса по производительности у меня нет.

Линковщик:
Код
-D_CSTACK_SIZE=4
-D_IRQ_STACK_SIZE=100
-D_FIR_STACK_SIZE=100
-D_SVC_STACK_SIZE=100
-D_ABT_STACK_SIZE=4
-D_UND_STACK_SIZE=4
-D_HEAP_SIZE=0

-Z(DATA)CSTACK+_CSTACK_SIZE=RAMSTART-RAMEND
-Z(DATA)IRQ_STACK+_IRQ_STACK_SIZE=RAMSTART-RAMEND
-Z(DATA)FIR_STACK+_FIR_STACK_SIZE=RAMSTART-RAMEND
-Z(DATA)SVC_STACK+_SVC_STACK_SIZE=RAMSTART-RAMEND
-Z(DATA)ABT_STACK+_ABT_STACK_SIZE=RAMSTART-RAMEND
-Z(DATA)UND_STACK+_UND_STACK_SIZE=RAMSTART-RAMEND
-Z(DATA)HEAP+_HEAP_SIZE=RAMSTART-RAMEND


Настройка стека:
Код
    mrs     r0,cpsr                            ; Original PSR value
    bic     r0,r0,#MODE_BITS                   ; Clear the mode bits
    orr     r0,r0,#IRQ_MODE                    ; Set IRQ mode bits
    msr     cpsr_c,r0                          ; Change the mode
    ldr     sp,=SFE(IRQ_STACK) & 0xFFFFFFF8    ; End of IRQ_STACK
    
    mrs     r0,cpsr                            ; Original PSR value
    bic     r0,r0,#MODE_BITS                   ; Clear the mode bits
    orr     r0,r0,#FIQ_MODE                    ; Set FIQ mode bits
    msr     cpsr_c,r0                          ; Change the mode
    ldr     sp,=SFE(FIR_STACK) & 0xFFFFFFF8    ; End of FIR_STACK                

    bic     r0,r0,#MODE_BITS                   ; Clear the mode bits
    orr     r0,r0,#SYS_MODE                    ; Set System mode bits
    msr     cpsr_c,r0                          ; Change the mode
    ldr     sp,=SFE(CSTACK) & 0xFFFFFFF8       ; End of CSTACK

    bic     r0,r0,#MODE_BITS                   ; Clear the mode bits
    orr     r0,r0,#SVC_MODE                    ; Set System mode bits
    msr     cpsr_c,r0                          ; Change the mode
    ldr     sp,=SFE(SVC_STACK) & 0xFFFFFFF8    ; End of SVCSTACK


Вот так настраивается с IRQ (так работает):
Код
    void init_interrupts()
    {
        MEMMAP = 1;

        VICSoftIntClear = ~0;
        VICIntEnClear = ~0;
        VICIntSelect = 0;

        set_VICVectCntls(1, hw::VIC_CHANNEL_TIMER1, &irq_timer1_handler_asm);
        set_VICVectCntls(2, hw::VIC_CHANNEL_UART0, &irq_uart0_handler_asm);
        set_VICVectCntls(3, hw::VIC_CHANNEL_UART1, &irq_uart1_handler_asm);

        VICDefVectAddr = reinterpret_cast<unsigned long>(&non_vectored_handler_asm);
        
        VICIntEnable =
            BIT_(hw::VIC_CHANNEL_TIMER1) +
            BIT_(hw::VIC_CHANNEL_UART0) +
            BIT_(hw::VIC_CHANNEL_UART1);

        VICProtection = 1;
        VICVectAddr = 0;
    }


Вот так с FIQ (иногда работает, но очень редко, потом зависает в prefetch interrupt):
Код
    void init_interrupts()
    {
        MEMMAP = 1;

        VICSoftIntClear = ~0;
        VICIntEnClear = ~0;
        VICIntSelect = 0;

        set_VICVectCntls(2, hw::VIC_CHANNEL_UART0, &irq_uart0_handler_asm);
        set_VICVectCntls(3, hw::VIC_CHANNEL_UART1, &irq_uart1_handler_asm);

        VICDefVectAddr = reinterpret_cast<unsigned long>(&non_vectored_handler_asm);
        
        VICIntSelect = BIT_(hw::VIC_CHANNEL_TIMER1);
        
        VICIntEnable =
            BIT_(hw::VIC_CHANNEL_TIMER1) +
            BIT_(hw::VIC_CHANNEL_UART0) +
            BIT_(hw::VIC_CHANNEL_UART1);

        VICProtection = 1;
        VICVectAddr = 0;
    }


Таблица прерываний:
Код
    org    0x00
__program_start:        B           ?cstartup
        undefvec:        B           undef_handler_proxy
        swivec:            B           swi_handler_proxy
        pabtvec:        B           prefetch_handler_proxy
        dabtvec:        B           data_handler_proxy

    org 0x18
        irqvec:            LDR            PC, [PC, #-0xFF0]
        fiqvec:         B           fiq_handler_proxy


Прокси:
Код
undef_handler_proxy B undef_handler;
swi_handler_proxy B vPortYieldProcessor;
prefetch_handler_proxy B prefetch_handler;
data_handler_proxy B data_handler;
fiq_handler_proxy B fiq_handler_asm;


Обработчики прерываний (ASM)
Код
fiq_handler_asm:
    portSAVE_CONTEXT
    BL fiq_handler_impl;
    portRESTORE_CONTEXT

irq_timer1_handler_asm:
    portSAVE_CONTEXT
    BL irq_timer1_handler_impl;
    portRESTORE_CONTEXT


Обработчики прерываний (C++)
Код
extern "C" __arm void fiq_handler_impl(void)
{
    timer1_uart_isr_impl();
}

extern "C" __arm void irq_timer1_handler_impl(void)
{
    timer1_uart_isr_impl();
}


Спасибо.
zltigo
Я все это не читал, поскольку сразу понял, что не смогу понять за конечное количество времени, что Вы хотите сделать с бедным FIQ sad.gif. Но с FIQ никаких специальных проблем нет - при работающем от IRQ ядре системы отдельные обработчики прерываний могут висеть на FIQ. Следует иметь ввиду только следующие моменты:
- по умолчанию в критических секциях запрещается и IRQ и FIQ - надо доработать при необходимости;
- из FIQ нельзя осуществлять системные вызовы требующие переключения контекста. В принципе это не смертельно, ибо FIQ оно на то и FIQ дабы чего-то (а не все подряд! где его эффективность к нулю приблизится )быстро обслуживать. Если очень ну очень и в исключительных случаях надо, то вполне правильным рещением следует признать эмуляцию обычного прерывания из FIQ для переключения контекста.
meister
Сорри. Симулятор в IAR меня обманул, на железе - работает.

Ниже уже не актуально.
===

Цитата(zltigo @ Jan 23 2008, 11:38) *
Если очень ну очень и в исключительных случаях надо, то вполне правильным рещением следует признать эмуляцию обычного прерывания из FIQ для переключения контекста.


Я попробую этот вариант потрясти - там контекст нужно переключать далеко не каждый раз. А как генерировать софтварное прерывание? Так не получается sad.gif

Код
namespace
{
    unsigned const my_sw_irq_channel = 31;
}

__arm __irq void irq_sw_test(void)
{
    VICVectAddr = 0;
}

__arm __irq void non_vectored_handler(void)
{
    VICVectAddr = 0;
}

int main()
{
    MEMMAP = 1;
    
    VICSoftIntClear = ~0;
    VICIntEnClear = ~0;
    VICIntSelect = 0;
    
    VICVectAddr0 = reinterpret_cast<unsigned long>(&irq_sw_test);
    VICVectCntl0 = 0x20 | my_sw_irq_channel;

    VICDefVectAddr = reinterpret_cast<unsigned long>(&non_vectored_handler);

    VICIntEnable = BIT_(my_sw_irq_channel);

    VICProtection = 1;
    VICVectAddr = 0;
    
    __enable_interrupt();

    VICSoftInt = BIT_(my_sw_irq_channel);
    
    assert(0 && "here");
}
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.