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

 
 
> Вложенные прерывания, GCC и ARM7
Novichok1
сообщение Mar 1 2010, 05:08
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 73
Регистрация: 8-07-09
Пользователь №: 51 032



Доброго времени суток!
Работаю с платой LPC2478, требуется реализовать вложенные (nested) прерывания.
Нарыл несколько статей на эту тему, но пока ни один метод не запахал.
Тестирую прерывания таким образом:

Код
void TestInterrupts::TestTimers()
{
    myPrintf("\nSTART TestTimers()\n");

    Timer0VICInit(Timer0ISR);
    Timer1VICInit(Timer1ISR);
    Timer1StartWithInt(1000);

    myPrintf("\nEND TestTimers()\n");
}

void TestInterrupts::Timer0ISR()
{
    T0IR  = TIR_MR0_INT; // reset interrrupt flags
    myPrintf("\nTimer0ISR()\n");
    // Dummy write to VIC to signal end of interrupt
    VICVectAddr = 0x00000000;
}

void TestInterrupts::Timer1ISR()
{
    IENABLE;

    T1IR  = TIR_MR0_INT; // reset interrrupt flags
    myPrintf("\nSTART Timer1ISR()\n");
        Timer0StartWithInt(5000);
    volatile tU8 dummy = 0;
    while(1)
    {
        dummy = 0;
    }
    myPrintf("\nEND Timer1ISR()\n");
    IDISABLE;
    // Dummy write to VIC to signal end of interrupt
    VICVectAddr = 0x00000000;
}


Где в качестве IENABLE пробовал разные последовательности ассемблерных команд, вычитанных с разных статей:
Код
// FROM Nesting of interrupts in the LPC2000 (AN10381)
#define IENABLE /* Nested Interrupts Entry */ \
        __asm__ ("MRS LR, SPSR"); /* Copy SPSR_irq to LR */ \
        __asm__ ("STMFD SP!, {LR}"); /* Save SPSR_irq */ \
        __asm__ ("MSR CPSR_c, #0x1F"); /* Enable IRQ (Sys Mode) */ \
        __asm__ ("STMFD SP!, {LR}"); /* Save LR */ \

Код
// FROM Real-time processing with the Philips LPC ARM microcontroller; using GCC and the MicroC/OS-II RTOS.
#define IENABLE /* Nested Interrupts Entry */ \
        __asm__ ("sub lr, lr, #4"); /* (1) Save IRQ context, including the APCS registers, and r4-6 */ \
        __asm__ ("stmfd sp!, {r0-r6, ip, lr}"); \
        __asm__ ("mrs r4, spsr"); /* (2) Save the SPSR_irq register */ \
        __asm__ ("ldr r5, =0xFFFFFF00"); /* (3) Read the VICVectAddr */ \
        __asm__ ("ldr r6, [r5]"); \
        __asm__ ("msr cpsr_c, 0x1F"); /* (4) Change to SYS mode and enable IRQ */ \
        __asm__ ("stmfd sp!, {lr}"); /* (5) Save the banked SYS mode link register */ \


То есть, на консоли должно появиться
Цитата
START TestTimers()
END TestTimers()
START Timer1ISR()
START Timer0ISR()


А на самом деле последняя строка не выводиться, что говорит о невхождении в обработчик вложенного прерывания Timer0.
Так вот, первый мой вопрос, какая же все таки последовательной команд должна быть в прологе и эпилоге обработчика для LPC2478?

И еще, во втором случае IENABLE полное описание вхождения и вывода их вложенных прерываний выглядит так:
Цитата
nested_irq_isr:
/* (1) Save IRQ context, including the APCS registers, and r4-6 */
sub lr, lr, #4
stmfd sp!, {r0-r6, ip, lr}
/* (2) Save the SPSR_irq register */
mrs r4, spsr
/* (3) Read the VICVectAddr */
ldr r5, VICVECTADDR
ldr r6, [r5]
/* (4) Change to SYS mode and enable IRQ */
msr cpsr_c, #SYS_MODE
/* (5) Save the banked SYS mode link register */
stmfd sp!, {lr}
/* (6) Call the C-coded handler */
mov lr, pc
ldr pc, r6
/* (7) Restore SYS mode link register */
ldmfd sp!, {lr}
36
AR1803 May 10, 2006
/* (8) Change to IRQ mode and disable IRQ */
msr cpsr_c, #IRQ_MODE|IRQ_DISABLE
/* (9) Restore the SPSR */
msr spsr, r4
/* (10) Acknowledge the VIC */
mov r0, #0
str r0, [r5]
/* (11) Restore IRQ context and return from interrupt */
ldmfd sp!, {r0-r6, ip, pc}^


И это описание натолкнуло меня на дополнительный вопрос, а можно ли в GCC переопределять последовательность операций для вызова функций, например путем создания собственных атрибутов для функций. И дальнейшим их использованием в примерно таком виде:
Код
static void Timer0ISR()  __attribute__ ((my_nested_interrupt))


Сообщение отредактировал Novichok1 - Mar 1 2010, 05:14
Go to the top of the page
 
+Quote Post
3 страниц V   1 2 3 >  
Start new topic
Ответов (1 - 14)
sergeeff
сообщение Mar 1 2010, 06:57
Сообщение #2


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Про прерывания а форуме для ARM столько уже понаписано!
1. Заставить VIC вызывать по прерыванию С++ функцию класса можно, но тогда ее надо делать статической со всеми вытекающими.
2. Вы приводите только функции класса, да и те не полностью. Остается гадать, что написано в остальных и как выглядит таблица перываний.
Go to the top of the page
 
+Quote Post
Novichok1
сообщение Mar 1 2010, 08:07
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 73
Регистрация: 8-07-09
Пользователь №: 51 032



Цитата
1. Заставить VIC вызывать по прерыванию С++ функцию класса можно, но тогда ее надо делать статической со всеми вытекающими.


С этим все в порядке. Каждое из прерываний по отдельности работает нормально, и вызываются соответствующие обработчики. Дело в другом, мне нужны именно вложенные прерывания. то есть во время обработки одного прерывания(Timer1ISR) может произойти второе прерывание (Timer0), и это прерывание должно корректно обработаться.

Цитата
2. Вы приводите только функции класса, да и те не полностью. Остается гадать, что написано в остальных и как выглядит таблица перываний.

Виноват, но не хотелось перегружать топик.
Код
static void Timer::Timer0VICInit(_void_pointer handler)
{
    VICIntSelect &= ~VIC_TIMER0;      // Timer1 selected as IRQ
    VICVectCntl4 = VIC_TIMER0;
    VICVectAddr4 = (tU32)handler;  // Address of the ISR
    VICIntEnable |= VIC_TIMER0;      // Timer interrupt enabled
}

static void Delay::Timer0StartWithInt(tU32 ms)
{
    T0TCR = TCR_RESET; // stop and reset timer
    T0PR  = 0x00; // set prescaler to zero
    T0IR  = TIR_RESET_INTERRUPTS; // reset all interrrupt flags
    T0MR0 = TIMER_CONVERT_FROM_MS(ms);
    T0MCR = MCR_MR0_INT; // Interrupt on MR0: an interrupt is generated when MR0 matches the value in the TC.
    T0TCR = TCR_ENABLE; // start timer
}


Аналогично для Timer1.


Не знаю, почему может не работать, вроде все делаю, как описано здесь, в случае дополнения тела обработчиками макросами IENABLE и IDISABLE.
Go to the top of the page
 
+Quote Post
Novichok1
сообщение Mar 1 2010, 09:12
Сообщение #4


Участник
*

Группа: Участник
Сообщений: 73
Регистрация: 8-07-09
Пользователь №: 51 032



Может и правда, дело в стартапе, выложу его на всякий случай, может кто и увидит несостыковку.
CODE
#
# *** Startup Code (executed after Reset) ***
#

#include "config.h"

# Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs

.equ Mode_USR, 0x10
.equ Mode_FIQ, 0x11
.equ Mode_IRQ, 0x12
.equ Mode_SVC, 0x13
.equ Mode_ABT, 0x17
.equ Mode_UND, 0x1B
.equ Mode_SYS, 0x1F

.equ I_Bit, 0x80 /* when I bit is set, IRQ is disabled */
.equ F_Bit, 0x40 /* when F bit is set, FIQ is disabled */

.equ sram_bottom, SRAM_SADDR
.equ sram_top, SRAM_TOP
.equ stackTop, SRAM_TOP

#define VAL_PLLCFG_MSEL ((PLL_MUL - 1) << 0)
#if (PLL_DIV == 1)
#define PLL_DIV_VALUE 0x00
#elif (PLL_DIV == 2)
#define PLL_DIV_VALUE 0x01
#elif (PLL_DIV == 4)
#define PLL_DIV_VALUE 0x10
#elif (PLL_DIV == 8)
#define PLL_DIV_VALUE 0x11
#endif
#define VAL_PLLCFG_PSEL (PLL_DIV_VALUE << 5)
#define VAL_PLLCFG (VAL_PLLCFG_MSEL | VAL_PLLCFG_PSEL)

# Phase Locked Loop (PLL) definitions
.equ PLL_BASE, 0xE01FC080 /* PLL Base Address */
.equ PLLCON_OFS, 0x00 /* PLL Control Offset*/
.equ PLLCFG_OFS, 0x04 /* PLL Configuration Offset */
.equ PLLSTAT_OFS, 0x08 /* PLL Status Offset */
.equ PLLFEED_OFS, 0x0C /* PLL Feed Offset */
.equ PLLCON_PLLE, (1<<0) /* PLL Enable */
.equ PLLCON_PLLC, (1<<1) /* PLL Connect */
.equ PLLSTAT_PLOCK, (1<<10) /* PLL Lock Status */

#define HANDLER(HandlerLabel,HandleLabel) \
HandlerLabel: ;\
sub sp, sp, #4 ;\
stmfd sp!, {r0};\
ldr r0, =HandleLabel;\
ldr r0, [r0] ;\
str r0, [sp,#4] ;\
ldmfd sp!, {r0,pc}

# Starupt Code must be linked first at Address at which it expects to run.

.text
.arm
# ******************************************************************************
# Declare external function
# ******************************************************************************
.extern lowLevelInit
.extern exceptionHandlerInit

.global _startup
.func _startup
_startup:

# Exception Vectors
# Mapped to Address 0.

Vectors:
_vectors:
# If vectors are in FLASH, starting at 0x00000000
#if (MAM_MAP == 1)
B handleReset /* jump to reset code */
B HandlerUndef /* handlerUndef */
B HandlerSWI /* SWI interrupt handler */
B HandlerPabort /* handlerPAbort */
B HandlerDabort /* handlerDAbort */
NOP /* Reserved Vector */
#if (IRQ_HANDLER == 0)
B HandlerIRQ /* handlerIRQ */
#else
LDR PC,[PC,#-0x120] /* jump to address supplied by VIC */
#endif
B HandlerFIQ /* handlerFIQ */

# Create handlers
HANDLER(HandlerUndef, HandleUndef)
HANDLER(HandlerSWI, HandleSWI)
HANDLER(HandlerPabort, HandlePabort)
HANDLER(HandlerDabort, HandleDabort)
#if (IRQ_HANDLER == 0)
HANDLER(HandlerIRQ, HandleIRQ)
#endif
HANDLER(HandlerFIQ, HandleFIQ)

# If vectors are in RAM, starting at 0x40000000
#else
LDR PC,[PC,#resetHandlerAddress - . - 8] /* handle reset */
LDR PC,[PC,#undefHandlerAddress - . - 8] /* handlerUndef */
LDR PC,[PC,#swiHandlerAddress - . - 8] /* SWI interrupt handler */
LDR PC,[PC,#pabortHandlerAddress - . - 8] /* handlerPAbort */
LDR PC,[PC,#dabortHandlerAddress - . - 8] /* handlerDAbort */
NOP /* Reserved Vector */
#if (IRQ_HANDLER == 0)
LDR PC,[PC,#irqHandlerAddress - . - 8] /* jump to common irq handler */
#else
LDR PC,[PC,#-0x120] /* jump to address supplied from VIC */
#endif
LDR PC,[PC,#fiqHandlerAddress - . - 8] /* handlerFIQ */

resetHandlerAddress:
.word handleReset

undefHandlerAddress:
.word 0

swiHandlerAddress:
.word 0

pabortHandlerAddress:
.word 0

dabortHandlerAddress:
.word 0

irqHandlerAddress:
.word 0

fiqHandlerAddress:
.word 0

#endif

# Reset Handler
handleReset:

# Call pll initialization
# BL pllInit

# Setup Stack for each mode
LDR R0, =stackTop

# Enter Undefined Instruction Mode and set its Stack Pointer
MSR CPSR_c, #Mode_UND|I_Bit|F_Bit
MOV SP, R0
SUB R0, R0, #stackSize_UND

# Enter Abort Mode and set its Stack Pointer
MSR CPSR_c, #Mode_ABT|I_Bit|F_Bit
MOV SP, R0
SUB R0, R0, #stackSize_ABT

# Enter FIQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_FIQ|I_Bit|F_Bit
MOV SP, R0
SUB R0, R0, #stackSize_FIQ

# Enter IRQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_IRQ|I_Bit|F_Bit
MOV SP, R0
SUB R0, R0, #stackSize_IRQ

# Enter Supervisor Mode and set its Stack Pointer
MSR CPSR_c, #Mode_SVC|I_Bit|F_Bit
MOV SP, R0
SUB R0, R0, #stackSize_SVC

# Enter System Mode and set its Stack Pointer
MSR CPSR_c, #Mode_SYS|I_Bit|F_Bit
MOV SP, R0

# Setup a default Stack Limit (when compiled with "-mapcs-stack-check")
SUB SL, SP, #stackSize_SYS

#if (MAM_MAP == 2)
# Copy exception vectors into SRAM
MOV R8, #SRAM_SADDR
LDR R9, =Vectors
# Move exception vectors (7 vectors + 1 reserved)
LDMIA R9!, {R0-R7}
STMIA R8!, {R0-R7}
# Move addresses belonging to exception vectors (7 addresses)
LDMIA R9!, {R0-R6}
STMIA R8!, {R0-R6}
#endif

# Call low-level initialization
# BL lowLevelInit

# Relocate .data section (Copy from ROM to RAM)
LDR R1, =_etext
LDR R2, =_data
LDR R3, =_edata
LoopRel: CMP R2, R3
LDRLO R0, [R1], #4
STRLO R0, [R2], #4
BLO LoopRel

# Clear .bss section (Zero init)
MOV R0, #0
LDR R1, =__bss_start__
LDR R2, =__bss_end__
LoopZI: CMP R1, R2
STRLO R0, [R1], #4
BLO LoopZI

# Initialize exception vectors
# BL exceptionHandlerInit

# Enter the C code
Jump_To_Main:
ADR LR, __Return_from_Main
MOV R0, #0
MOV R1, #0
LDR R2, =main
BX R2

__Return_from_Main:
B __Return_from_Main

.size _startup, . - _startup
.endfunc


#
# Reserve memory for exception handlers
#
.struct SRAM_SADDR + 0x20
HandleReset:

.struct SRAM_SADDR + 0x24
HandleUndef:

.struct SRAM_SADDR + 0x28
HandleSWI:

.struct SRAM_SADDR + 0x2c
HandlePabort:

.struct SRAM_SADDR + 0x30
HandleDabort:

.struct SRAM_SADDR + 0x34
HandleIRQ:

.struct SRAM_SADDR + 0x38
HandleFIQ:

#
# Reserve memory for stack areas
#
.struct STK_SADDR
UserStack: /* User stack not used (size = 0) */

.struct UserStack + stackSize_SYS
SYSStack:

.struct SYSStack + stackSize_SVC
SVCStack:

.struct SVCStack + stackSize_UND
UndefStack:

.struct UndefStack + stackSize_ABT
AbortStack:

.struct AbortStack + stackSize_IRQ
IRQStack:

.struct IRQStack + stackSize_FIQ
FIQStack: /* this position equals top of SRAM */

.end



Кстати, если следовать советам "Real-time processing with the Philips LPC ARM microcontroller; using GCC and the MicroC/OS-II RTOS." то я подозреваю этот код загрузки обработчика
Код
nested_irq_isr:
/* (1) Save IRQ context, including the APCS registers, and r4-6 */
sub lr, lr, #4
stmfd sp!, {r0-r6, ip, lr}
/* (2) Save the SPSR_irq register */
mrs r4, spsr
/* (3) Read the VICVectAddr */
ldr r5, VICVECTADDR
ldr r6, [r5]
/* (4) Change to SYS mode and enable IRQ */
msr cpsr_c, #SYS_MODE
/* (5) Save the banked SYS mode link register */
stmfd sp!, {lr}
/* (6) Call the C-coded handler */
mov lr, pc
ldr pc, r6
/* (7) Restore SYS mode link register */
ldmfd sp!, {lr}
/* (8) Change to IRQ mode and disable IRQ */
msr cpsr_c, #IRQ_MODE|IRQ_DISABLE
/* (9) Restore the SPSR */
msr spsr, r4
/* (10) Acknowledge the VIC */
mov r0, #0
str r0, [r5]
/* (11) Restore IRQ context and return from interrupt */
ldmfd sp!, {r0-r6, ip, pc}^
нужно поместить в макрос HANDLER(HandlerLabel,HandleLabel)? Но тогда возникает вопрос, что такое VICVECTADDR, просто адрес 0xFFFFFF00, или нечто иное?

Сообщение отредактировал rezident - Mar 4 2010, 13:33
Причина редактирования: Редактирование оформления цитаты исходника.
Go to the top of the page
 
+Quote Post
Novichok1
сообщение Mar 4 2010, 05:44
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 73
Регистрация: 8-07-09
Пользователь №: 51 032



Хорошо, частично разобрался, для вызовов всех прерываний использую

Код
HandlerIRQ_ISR_NESTED:
    /* (1) Save IRQ context, including the APCS registers, and r4-6 */
    sub lr, lr, #4
    stmfd sp!, {r0-r6, ip, lr}
    /* (2) Save the SPSR_irq register */
    mrs r4, spsr
    /* (3) Read the VICVectAddr */
    ldr r5, =0xFFFFFF00
    ldr r6, [r5]
    /* (4) Change to SYS mode and enable IRQ */
    msr cpsr_c, #0x1F
    /* (5) Save the banked SYS mode link register */
    stmfd sp!, {lr}
    /* (6) Call the C-coded handler */
    mov lr, pc
    ldr pc, [r5]
    /* (7) Restore SYS mode link register */
    ldmfd sp!, {lr}
    /* (8) Change to IRQ mode and disable IRQ */
    msr cpsr_c, #Mode_IRQ|I_Bit
    /* (9) Restore the SPSR */
    msr spsr, r4
    /* (10) Acknowledge the VIC */
    mov r0, #0
    str r0, [r5]
    /* (11) Restore IRQ context and return from interrupt */
    ldmfd sp!, {r0-r6, ip, pc}^


И что происходит, в обработчике внешнего прерывания в цикле просматриваю флаги прерываний, и вижу, что да, второе прерывание срабатывает, но его обработчик не запуститься до тех пор, пока мы не запишем что-либо в VicVectAddr, что сделает возможными и прерывания меньшего приоритета
Цитата
Writing to the VICVECTADDR Register indicates to the interrupt priority hardware that the current interrupt is serviced, enabling lower priority or the same priority interrupts to be removed, and for the interrupts to become active to go active

И тем более запись в VicVectAddr советуют делать в самом конце обработчика прерывания, а без этой записи ядру не идет сообщение о прерывании. Может есть другой способ разрешить VIC инициализировать прерывания, без записи в VicVectAddr?


И еще, если использовать директивы компилятора, указывающими на то что данная функция является обработчиком прерывания, то компилятор сам сохраняет изменяемые регистры, а тут мы это делаем ручками и для всех обработчиков, поэтому возникает вопрос, а достаточно ли сохранение первых семи регистров(stmfd sp!, {r0-r6, ip, lr})?

И еще, небольшое наблюдение- приведенный выше подход проявляет более лучшую устойчивость, чем этот:
Цитата
#define IENABLE /* Nested Interrupts Entry */ \
__asm__ ("MRS LR, SPSR"); /* Copy SPSR_irq to LR */ \
__asm__ ("STMFD SP!, {LR}"); /* Save SPSR_irq */ \
__asm__ ("MSR CPSR_c, #0x1F"); /* Enable IRQ (Sys Mode) */ \
__asm__ ("STMFD SP!, {LR}"); /* Save LR */ \

// Macro for disabling interrupts, switching back to IRQ and relevant stack operations
#define IDISABLE /* Nested Interrupts Exit */ \
__asm__ ("LDMFD SP!, {LR}"); /* Restore LR */ \
__asm__ ("MSR CPSR_c, #0x92"); /* Disable IRQ (IRQ Mode) */ \
__asm__ ("LDMFD SP!, {LR}"); /* Restore SPSR_irq to LR */ \
__asm__ ("MSR SPSR_cxsf, LR"); /* Copy LR to SPSR_irq */ \


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

Сообщение отредактировал Novichok1 - Mar 4 2010, 06:25
Go to the top of the page
 
+Quote Post
Novichok1
сообщение Mar 4 2010, 07:06
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 73
Регистрация: 8-07-09
Пользователь №: 51 032



И благодаря такому подходу исчезли глюки, которые были связаны с прерываниями, и проявлялись в виде лишних вызовов функций с параметрами, которые, походу, оставались в регистрах во время исполнения обработчика прерывания. От этих причуд складывалось такое впечатление, что компилятор при входе или выходе сохранял(восстанавливал) не все требуемые регистры.

Сообщение отредактировал Novichok1 - Mar 4 2010, 07:06
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Mar 4 2010, 23:26
Сообщение #7


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



театр одного актёра smile.gif


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 4 2010, 23:57
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(GetSmart @ Mar 5 2010, 02:26) *
театр одного актёра smile.gif

Надо помочь, наверное, да пугают длинные копипасты мутного кода.

Цитата(Novichok1 @ Mar 4 2010, 08:44) *
И еще, если использовать директивы компилятора, указывающими на то что данная функция является обработчиком прерывания, то компилятор сам сохраняет изменяемые регистры, а тут мы это делаем ручками и для всех обработчиков, поэтому возникает вопрос, а достаточно ли сохранение первых семи регистров(stmfd sp!, {r0-r6, ip, lr})?

Перед вызовом достаточно сохранить R0-R3, R12, R14, остальное вызываемая подпрограмма трогать не имеет права. R4-R6 портит сама обертка.
Кроме того, следует обратить внимание на некорректное выравнивание стека - должно быть четное число слов.
Использование одного обработчика для прерываний всех приоритетов - тоже, мягко говоря, не самая светлая идея.

Цитата(Novichok1 @ Mar 4 2010, 08:44) *
Так, если в обработчике первого прерывания происходит второе прерывания, а в вызванном обработчике второго прерывания происходит первое, то после выхода из обработчика программа глючит.

Не происходит такого в нормальных условиях. Пока выполняется один обработчик прерывания с определенным приоритетом, другие прерывания с тем же или меньшим приоритетом маскируются. Иначе какой вообще смысл во вложенности?
Go to the top of the page
 
+Quote Post
Novichok1
сообщение Mar 5 2010, 04:59
Сообщение #9


Участник
*

Группа: Участник
Сообщений: 73
Регистрация: 8-07-09
Пользователь №: 51 032



Цитата(aaarrr @ Mar 5 2010, 02:57) *
Перед вызовом достаточно сохранить R0-R3, R12, R14, остальное вызываемая подпрограмма трогать не имеет права. R4-R6 портит сама обертка.
Кроме того, следует обратить внимание на некорректное выравнивание стека - должно быть четное число слов.

Большое спасибо за разъяснение! А насчет некорректного выравнивания стека - после stmfd sp!, {r0-r6, ip, lr} через некоторое число команд вызывается еще и stmfd sp!, {lr} (на шаге 5), так что в сумме получается четное число сохраненных регистров, так можно рассуждать, или при выполнении ОДНОЙ команды записи в стек должно сохраняться четное число слов?

Цитата(aaarrr @ Mar 5 2010, 02:57) *
Использование одного обработчика для прерываний всех приоритетов - тоже, мягко говоря, не самая светлая идея.

Я наверно не совсем точно выразился, под " ...для вызовов всех прерываний использую..." не имелось ввиду использование одного сишного обработчика для всех прерываний, а подразумевалась последовательность ассемблерных команд для подготовки ко входу в обработчик прерывания, вызова сишной функции обработчика, адрес которой лежит в регистре ViсVectAddr, и восстановления регистров и состояния проца после завершения обработчика. Так что для каждого прерывания у меня свой обработчик, как и положено.

Цитата(aaarrr @ Mar 5 2010, 02:57) *
Не происходит такого в нормальных условиях. Пока выполняется один обработчик прерывания с определенным приоритетом, другие прерывания с тем же или меньшим приоритетом маскируются. Иначе какой вообще смысл во вложенности?

Вот в этом-то и дело! К примеру, если в процессе работы обработчика прерывания с приоритетом 5 (Timer1), происходит прерывание с приоритетом 4 (Timer0), то выставляются флаги прерывания в T0IR, VICIRQStatus, записывается нужный адрес в VicVecAddress, НО перехода в обработчик прерывания Timer0 не происходит до тех пор, пока мы не запишем что-либо в регистр VicVecAddress, что само собой разрешит прерывания всех приоритетов. Хотя ни в "AN10381(Nesting of interrupts in the LPC2000)", ни в "Real-time processing with the Philips LPC ARM microcontroller; using GCC and the MicroC/OS-II RTOS." про необходимость записи в регистр VicVecAddress для разрешения вложенных прерываний ничего не сказано. Там говорится о достаточности применения вышеописанных макросов IENABLE, IDISABLE, либо ассемблерной процедурине для входа и выхода из обработчика. Вот и интересно, что же я упустил?

А вообще, рассмотрение сего вопроса началось из-за следующего глюка: вызывается функция, которая допускает появления прерываний, далее походу при появлении этих прерываний, ИНОГДА появляются лишние вызовы функций со странными параметрами. При рассмотрении это было похоже на следующее:
1. Вызвали функцию Func1(param1),
2. В этой функции произошло прерывание, в котором использовалось значение по адресу param_ISR
3. Вышли из прерывания
4. ЛИШНИЙ повторный вызов функции Func1(param_ISR) (прошу обратить внимание на изменившийся параметр!)
5. Дальнейший ход выполнения программы.
Обработчик прерывания был отмечен атрибутом __attribute__ ((interrupt)), никаких макросов типа IENABLE не было, вход в обработчик был стандартным.
Вот и складывается впечатление, что при входе-выходе из прерывания сохраняются-ресторятся не все регистры.

Цитата
театр одного актёра

Благодарю за участие)

Сообщение отредактировал Novichok1 - Mar 5 2010, 05:17
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Mar 5 2010, 06:44
Сообщение #10


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Цитата(Novichok1)
Вот и складывается впечатление, что при входе-выходе из прерывания сохраняются-ресторятся не все регистры.

Дайте ка посмотреть на пролог и эпилог обработчика, генерируемого GCC.


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
Novichok1
сообщение Mar 5 2010, 07:22
Сообщение #11


Участник
*

Группа: Участник
Сообщений: 73
Регистрация: 8-07-09
Пользователь №: 51 032



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

пролог:
Код
sub    lr, lr, #4
stmfd    sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, lr}


эпилог:
Код
ldr    r3, [r4, #8]
and    r3, r3, #255
strb    r3, [sp, #11]
ldrb    r3, [sp, #11]    @ zero_extendqisi2
tst    r3, #1
beq    .L92
mov    r2, #0
mvn    r3, #0
str    r2, [r3, #-255]
add    sp, sp, #12
ldmfd    sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, lr}
subs    pc, lr, #4


и ко второму:
пролог:
Код
stmfd    sp!, {r4, r5, r6, r7, r8, lr}
ldr    r4, .L23
mov    r3, #1
sub    sp, sp, #8


эпилог:
Код
add    sp, sp, #8
ldmfd    sp!, {r4, r5, r6, r7, r8, lr}


Я не силен в ассемблерных кодах, поэтому могу напутать с границами эпилога-пролога.
Что странно, во втором случае регистр r3 не сохраняется в стек, хотя в теле функции он проскакивает.
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Mar 5 2010, 07:43
Сообщение #12


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Если после команды ldmfd в эпилоге второго ничего не стоит, то неудивительно, что есть глюки. Это может быть известная бага GCC с атрибутом interrupt.

В эпилоге первого прерывания стоит subs pc, lr, #4, что является нормальным выходом из прерывания. В эпилоге второго нет этой команды. Есть ещё второй вариант правильного ухода из прерывания, но и его там тоже не видно.

Почитайте
http://electronix.ru/forum/index.php?showt...mp;#entry650548

Вот ещё.
http://electronix.ru/forum/index.php?showt...=69514&st=0

Там есть мои короткие обёртки для вложенных прерываний. Они под ФриРТОС. В них можно чуть переделать режимы проца, чтобы nested IRQ/FIQ работало в System Mode без какой-либо оси.


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
Novichok1
сообщение Mar 5 2010, 07:47
Сообщение #13


Участник
*

Группа: Участник
Сообщений: 73
Регистрация: 8-07-09
Пользователь №: 51 032



Цитата(GetSmart @ Mar 5 2010, 10:43) *
Если после команды ldmfd в эпилоге второго ничего не стоит, то неудивительно, что есть глюки. Это может быть известная бага GCC с атрибутом interrupt.


Да, во втором случае еще стоит команда:
bx lr
Извините, ее пропустил. А что на счет r3, это нормально, что она не сохраняется в стек?

За ссылки спасибо, буду изучать.

Сообщение отредактировал Novichok1 - Mar 5 2010, 08:05
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 5 2010, 10:04
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Novichok1 @ Mar 5 2010, 07:59) *
Большое спасибо за разъяснение! А насчет некорректного выравнивания стека - после stmfd sp!, {r0-r6, ip, lr} через некоторое число команд вызывается еще и stmfd sp!, {lr} (на шаге 5), так что в сумме получается четное число сохраненных регистров, так можно рассуждать, или при выполнении ОДНОЙ команды записи в стек должно сохраняться четное число слов?

На шаге 5 пишется уже другой стек (SYS), суммировать эти записи нельзя.

Цитата(Novichok1 @ Mar 5 2010, 07:59) *
Я наверно не совсем точно выразился, под " ...для вызовов всех прерываний использую..." не имелось ввиду использование одного сишного обработчика для всех прерываний, а подразумевалась последовательность ассемблерных команд для подготовки ко входу в обработчик прерывания

Я ее и имел в виду. Для прерывания с высшим приоритетом эта ассемблерная последовательность - пустая трата времени.

Цитата(Novichok1 @ Mar 5 2010, 07:59) *
Вот и интересно, что же я упустил?

Вложенные прерывания предполагают, что выполнение процедуры обработки прерывания с приоритетом 5 может быть прервано прерыванием с приоритетом 6 или выше. Прерывание с меньшим приоритетом (4) может отработать только после записи VicVectAddr.
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Mar 5 2010, 12:14
Сообщение #15


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Цитата(aaarrr @ Mar 5 2010, 15:04) *
Вложенные прерывания предполагают, что выполнение процедуры обработки прерывания с приоритетом 5 может быть прервано прерыванием с приоритетом 6 или выше. Прерывание с меньшим приоритетом (4) может отработать только после записи VicVectAddr.

Приоритеты нумеруются в обратном порядке. №0 самое важное/приоритетное. №15 самое низкоприоритетное.

Цитата(Novichok1 @ Mar 5 2010, 12:47) *
Да, во втором случае еще стоит команда:
bx lr

Это точно пролог/эпилог функции с атрибутом interrupt ?


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 20th July 2025 - 17:42
Рейтинг@Mail.ru


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