Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: sam7se512 не входит в прерывания
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
malysh_nrg
Не могу понять почему процессор не может выполнить прерывание по таймеру 0. Хотя в основной программе нормально крутится и выполняет все функции.
Отлаживаю в ИАР 5.4 через SAM-ICE по JTAG. После прокрутки программы в регистрах таймера устанавливается бит CPCS (переполнение таймера по достижению значения в регистре RC). В AIC устанавливаются в регистре AIC_IPR бит 12 (таймер0) и в регистре маски AIC_IMR тоже стоит бит 12. Однако ни светодиод не загорается, ни программа по "пошаговой" отладке не вылетает в прерывания. Почему?

Настройки Т0:

CODE
//1: AIC
AT91C_BASE_AIC->AIC_IDCR=1<<AT91C_ID_TC0; //выключить прерывание по Т0

AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC0] = 0x1; //срабатывать по уровню 1 и приоритет 1
AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0] = (unsigned int) TC0_IrgHandler; //записать обработчик прерывания по Т0
AT91C_BASE_AIC->AIC_ICCR = 1 << AT91C_ID_TC0; //очистить флаг прерывания
AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_TC0); //T0

//3 PMC
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); //T0
//4.T0
AT91C_BASE_TC0->TC_CMR = ( AT91C_TC_CLKS_TIMER_DIV5_CLOCK| //внутр/5
AT91C_TC_WAVESEL_UP_AUTO|
AT91C_TC_WAVE); //авто по RC, режим формирования
AT91C_BASE_TC0->TC_RC = 0x0000FFFF; //RC=max (0x0000FFFF)
AT91C_BASE_TC0->TC_IDR = 0xFFFFFFFF; //запретить все прерывания
temp = AT91C_BASE_TC0->TC_SR; //прочитать состояние таймера чтобы обнулить его
temp=temp;
AT91C_BASE_TCO->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG ; //Разрешение Т0 и сброс в ноль
AT91C_BASE_TC0->TC_IER = AT91C_TC_CPCS; //разрешить прерывания по достижению RC


настроил ножку PCK0 на которой сигнал с частотой PLL и настроил ножку которая управляет светодиодом:

CODE
//сконфигурить PA29 на выход с прямой записью
AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA29; //PIO control
AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA29; // no input, drive by PIO
AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA29; // =1
AT91C_BASE_PIOA->PIO_OWER = AT91C_PIO_PA29; // enable write to PIO_ODSR
AT91C_BASE_PIOA->PIO_MDDR = AT91C_PIO_PA29; //выключить open drain
AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA29; //включить лампочку!
//сконфигурировать ... на чтение (вход)

//сконфиругить PC10 как выходы CLK, периферия B
AT91C_BASE_PIOC->PIO_PDR = AT91C_PIO_PC10; //управляется периф
AT91C_BASE_PIOC->PIO_BSR = AT91C_PIO_PC10; //периф B
//разрешить ножку PCK0 (48 МГц)
AT91C_BASE_PMC->PMC_SCDR = AT91C_PMC_PCK0; //запретить тактировать на выход PCK0
AT91C_BASE_PMC->PMC_PCKR[0] = AT91C_PMC_PRES_CLK_2 | AT91C_PMC_CSS_MAIN_CLK;
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_PCK0RDY));
AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_PCK0; //разрешить выход PCK0

AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_PIOA)| //порт А
(1 << AT91C_ID_PIOC); //порт С


Основную программу загоняю в цикл, выключив светодиод

CODE
int main()
{
InitMCU();
LEDoff(1);
while(1){
Background_Task();
}
}



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

CODE
void TC0_IrgHandler(void)
{
unsigned int i,j;
unsigned int status;

status = AT91C_BASE_TC0->TC_SR; //копировать статус регистр
LEDon(1);
}


СтартАп.s и .с взял как есть из предыдущего рабочего проекта для этой же платы и этого же процессора
CODE

;------------------------------------------------------------------------------
; Include your AT91 Library files
;------------------------------------------------------------------------------
#include "include/AT91SAM7SE512_inc.h"
;------------------------------------------------------------------------------

#define TOP_OF_MEMORY (AT91C_ISRAM + AT91C_ISRAM_SIZE)
#define IRQ_STACK_SIZE (3*8*4)
; 3 words to be saved per interrupt priority level

; Mode, correspords to bits 0-5 in CPSR
MODE_BITS DEFINE 0x1F ; Bit mask for mode bits in CPSR
USR_MODE DEFINE 0x10 ; User mode
FIQ_MODE DEFINE 0x11 ; Fast Interrupt Request mode
IRQ_MODE DEFINE 0x12 ; Interrupt Request mode
SVC_MODE DEFINE 0x13 ; Supervisor mode
ABT_MODE DEFINE 0x17 ; Abort mode
UND_MODE DEFINE 0x1B ; Undefined Instruction mode
SYS_MODE DEFINE 0x1F ; System mode

I_BIT DEFINE 0x80
F_BIT DEFINE 0x40

;------------------------------------------------------------------------------
; ?RESET
; Reset Vector.
; Normally, segment INTVEC is linked at address 0.
; For debugging purposes, INTVEC may be placed at other addresses.
; A debugger that honors the entry point will start the
; program in a normal way even if INTVEC is not at address 0.
;------------------------------------------------------------------------------
SECTION .intvec:CODE:NOROOT(2)
PUBLIC __vector
PUBLIC __iar_program_start

ARM
__vector:
ldr pc,[pc,#+24] ;; Reset
__und_handler:
ldr pc,[pc,#+24] ;; Undefined instructions
__swi_handler:
ldr pc,[pc,#+24] ;; Software interrupt (SWI/SVC)
__prefetch_handler:
ldr pc,[pc,#+24] ;; Prefetch abort
__data_handler:
ldr pc,[pc,#+24] ;; Data abort
DC32 0xFFFFFFFF ;; RESERVED
__irq_handler:
ldr pc,[pc,#+24] ;; IRQ
__fiq_handler:
ldr pc,[pc,#+24] ;; FIQ

DC32 __iar_program_start
DC32 __und_handler
DC32 __swi_handler
DC32 __prefetch_handler
DC32 __data_handler
B .
DC32 IRQ_Handler_Entry
DC32 FIQ_Handler_Entry

;------------------------------------------------------------------------------
;- Manage exception: The exception must be ensure in ARM mode
;------------------------------------------------------------------------------
SECTION text:CODE:NOROOT(2)
ARM
;------------------------------------------------------------------------------
;- Function : FIQ_Handler_Entry
;- Treatments : FIQ Controller Interrupt Handler.
;- R8 is initialize in Cstartup
;- Called Functions : None only by FIQ
;------------------------------------------------------------------------------
FIQ_Handler_Entry:

;- Switch in SVC/User Mode to allow User Stack access for C code
; because the FIQ is not yet acknowledged

;- Save and r0 in FIQ_Register
mov r9,r0
ldr r0 , [r8, #AIC_FVR]
msr CPSR_c,#I_BIT | F_BIT | SVC_MODE
;- Save scratch/used registers and LR in User Stack
stmfd sp!, { r1-r3, r12, lr}

;- Branch to the routine pointed by the AIC_FVR
mov r14, pc
bx r0

;- Restore scratch/used registers and LR from User Stack
ldmia sp!, { r1-r3, r12, lr}

;- Leave Interrupts disabled and switch back in FIQ mode
msr CPSR_c, #I_BIT | F_BIT | FIQ_MODE

;- Restore the R0 ARM_MODE_SVC register
mov r0,r9

;- Restore the Program Counter using the LR_fiq directly in the PC
subs pc,lr,#4
;------------------------------------------------------------------------------
;- Function : IRQ_Handler_Entry
;- Treatments : IRQ Controller Interrupt Handler.
;- Called Functions : AIC_IVR[interrupt]
;------------------------------------------------------------------------------
IRQ_Handler_Entry:
;-------------------------
;- Manage Exception Entry
;-------------------------
;- Adjust and save LR_irq in IRQ stack
sub lr, lr, #4
stmfd sp!, {lr}

;- Save r0 and SPSR (need to be saved for nested interrupt)
mrs r14, SPSR
stmfd sp!, {r0,r14}

;- Write in the IVR to support Protect Mode
;- No effect in Normal Mode
;- De-assert the NIRQ and clear the source in Protect Mode
ldr r14, =AT91C_BASE_AIC
ldr r0 , [r14, #AIC_IVR]
str r14, [r14, #AIC_IVR]

;- Enable Interrupt and Switch in Supervisor Mode
msr CPSR_c, #SVC_MODE

;- Save scratch/used registers and LR in User Stack
stmfd sp!, { r1-r3, r12, r14}

;----------------------------------------------
;- Branch to the routine pointed by the AIC_IVR
;----------------------------------------------
mov r14, pc
bx r0

;----------------------------------------------
;- Manage Exception Exit
;----------------------------------------------
;- Restore scratch/used registers and LR from User Stack
ldmia sp!, { r1-r3, r12, r14}

;- Disable Interrupt and switch back in IRQ mode
msr CPSR_c, #I_BIT | IRQ_MODE

;- Mark the End of Interrupt on the AIC
ldr r14, =AT91C_BASE_AIC
str r14, [r14, #AIC_EOICR]

;- Restore SPSR_irq and r0 from IRQ stack
ldmia sp!, {r0,r14}
msr SPSR_cxsf, r14

;- Restore adjusted LR_irq from IRQ stack directly in the PC
ldmia sp!, {pc}^

;------------------------------------------------------------------------------
;- Exception Vectors
;------------------------------------------------------------------------------
PUBLIC AT91F_Default_FIQ_handler
PUBLIC AT91F_Default_IRQ_handler
PUBLIC AT91F_Spurious_handler

ARM ; Always ARM mode after exeption

AT91F_Default_FIQ_handler
b AT91F_Default_FIQ_handler

AT91F_Default_IRQ_handler
b AT91F_Default_IRQ_handler

AT91F_Spurious_handler
b AT91F_Spurious_handler


;------------------------------------------------------------------------------
; ?INIT
; Program entry.
;------------------------------------------------------------------------------

SECTION FIQ_STACK:DATA:NOROOT(3)
SECTION IRQ_STACK:DATA:NOROOT(3)
SECTION SVC_STACK:DATA:NOROOT(3)
SECTION ABT_STACK:DATA:NOROOT(3)
SECTION UND_STACK:DATA:NOROOT(3)
SECTION CSTACK:DATA:NOROOT(3)
SECTION text:CODE:NOROOT(2)
REQUIRE __vector
EXTERN ?main
PUBLIC __iar_program_start
EXTERN AT91F_LowLevelInit


__iar_program_start:

;------------------------------------------------------------------------------
;- Low level Init is performed in a C function: AT91F_LowLevelInit
;- Init Stack Pointer to a valid memory area before calling AT91F_LowLevelInit
;------------------------------------------------------------------------------

;- Retrieve end of RAM address

ldr r13,=TOP_OF_MEMORY ;- Temporary stack in internal RAM for Low Level Init execution
ldr r0,=AT91F_LowLevelInit
mov lr, pc
bx r0 ;- Branch on C function (with interworking)

; Initialize the stack pointers.
; The pattern below can be used for any of the exception stacks:
; FIQ, IRQ, SVC, ABT, UND, SYS.
; The USR mode uses the same stack as SYS.
; The stack segments must be defined in the linker command file,
; and be declared above.

mrs r0,cpsr ; Original PSR value
bic r0,r0,#MODE_BITS ; Clear the mode bits
orr r0,r0,#SVC_MODE ; Set SVC mode bits
msr cpsr_c,r0 ; Change the mode
ldr sp,=SFE(SVC_STACK) ; End of SVC_STACK

bic r0,r0,#MODE_BITS ; Clear the mode bits
orr r0,r0,#UND_MODE ; Set UND mode bits
msr cpsr_c,r0 ; Change the mode
ldr sp,=SFE(UND_STACK) ; End of UND_STACK

bic r0,r0,#MODE_BITS ; Clear the mode bits
orr r0,r0,#ABT_MODE ; Set ABT mode bits
msr cpsr_c,r0 ; Change the mode
ldr sp,=SFE(ABT_STACK) ; End of ABT_STACK

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(FIQ_STACK) ; End of FIQ_STACK
;- Init the FIQ register
ldr r8, =AT91C_BASE_AIC

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) ; End of IRQ_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) ; End of CSTACK

#ifdef __ARMVFP__
; Enable the VFP coprocessor.
mov r0, #0x40000000 ; Set EN bit in VFP
fmxr fpexc, r0 ; FPEXC, clear others.

; Disable underflow exceptions by setting flush to zero mode.
; For full IEEE 754 underflow compliance this code should be removed
; and the appropriate exception handler installed.
mov r0, #0x01000000 ; Set FZ bit in VFP
fmxr fpscr, r0 ; FPSCR, clear others.
#endif

; Add more initialization here


; Continue to ?main for more IAR specific system startup

ldr r0,=?main
bx r0

END ;- Terminates the assembly of the last module in a file




CODE
#include "project.h"


// The following functions must be write in ARM mode this function called
// directly by exception vector
extern void AT91F_Spurious_handler(void);
extern void AT91F_Default_IRQ_handler(void);
extern void AT91F_Default_FIQ_handler(void);

//*----------------------------------------------------------------------------
//* \fn AT91F_LowLevelInit
//* \brief This function performs very low level HW initialization
//* this function can use a Stack, depending the compilation
//* optimization mode
//*----------------------------------------------------------------------------
void AT91F_LowLevelInit(void)
{
unsigned char i;
///////////////////////////////////////////////////////////////////////////
// EFC Init
///////////////////////////////////////////////////////////////////////////
AT91C_BASE_MC->MC0_FMR = AT91C_MC_FWS_2FWS;// 2 Wait State to work at 48MHz
AT91C_BASE_MC->MC1_FMR = AT91C_MC_FWS_2FWS;// 2 Wait State to work at 48MHz

///////////////////////////////////////////////////////////////////////////
// Init PMC Step 1. Enable Main Oscillator
// Main Oscillator startup time is board specific:
// Main Oscillator Startup Time worst case (3MHz) corresponds to 15ms
// (0x40 for AT91C_CKGR_OSCOUNT field)
///////////////////////////////////////////////////////////////////////////
AT91C_BASE_PMC->PMC_MOR = (( AT91C_CKGR_OSCOUNT & (0x40 <<8) | AT91C_CKGR_MOSCEN ));
// Wait Main Oscillator stabilization
while(!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS));

///////////////////////////////////////////////////////////////////////////
// Init PMC Step 2.
// Set PLL to 96MHz (96,109MHz) and UDP Clock to 48MHz
// PLL Startup time depends on PLL RC filter: worst case is choosen
// UDP Clock (48,058MHz) is compliant with the Universal Serial Bus
// Specification (+/- 0.25% for full speed)
///////////////////////////////////////////////////////////////////////////
AT91C_BASE_PMC->PMC_PLLR = AT91C_CKGR_USBDIV_1 |
AT91C_CKGR_OUT_0 |
(16 << 8) |
(AT91C_CKGR_MUL & (72 << 16)) |
(AT91C_CKGR_DIV & 14);
// Wait for PLL stabilization
while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCK) );
// Wait until the master clock is established for the case we already
// turn on the PLL
while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) );

///////////////////////////////////////////////////////////////////////////
// Init PMC Step 3.
// Selection of Master Clock MCK equal to (Processor Clock PCK) PLL/2=48MHz
// The PMC_MCKR register must not be programmed in a single write operation
// (see. Product Errata Sheet)
///////////////////////////////////////////////////////////////////////////
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
// Wait until the master clock is established
while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) );

AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK;
// Wait until the master clock is established
while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) );

///////////////////////////////////////////////////////////////////////////
// Disable Watchdog (write once register)
///////////////////////////////////////////////////////////////////////////
AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;

///////////////////////////////////////////////////////////////////////////
// Init AIC: assign corresponding handler for each interrupt source
///////////////////////////////////////////////////////////////////////////
AT91C_BASE_AIC->AIC_SVR[0] = (int) AT91F_Default_FIQ_handler ;
for (i = 1; i < 31; i++) {
AT91C_BASE_AIC->AIC_SVR[i] = (int) AT91F_Default_IRQ_handler ;
}
AT91C_BASE_AIC->AIC_SPU = (unsigned int) AT91F_Spurious_handler;
}
aaarrr
Цитата(malysh_nrg @ Apr 7 2010, 23:05) *
В AIC устанавливаются в регистре AIC_IPR бит 12 (таймер0) и в регистре маски AIC_IMR тоже стоит бит 12. Однако ни светодиод не загорается, ни программа по "пошаговой" отладке не вылетает в прерывания. Почему?

Видимо потому что -
Цитата(malysh_nrg @ Apr 7 2010, 23:05) *
Отлаживаю в ИАР 5.4 через SAM-ICE по JTAG.

AIC не в debug mode, и ему все равно кто прочитает IVR - отладчик или ядро.
malysh_nrg
Проверю, но однако если после прошивки перезапустить плату все равно не происходит прерывания (= не загорается светодиод)
malysh_nrg
если в основной цикл вставить код проверки флагов прерывания и разрешения на таймер, а после выполнить код подпрограммы, то светодиод загорается

Код
    if ((AT91C_BASE_AIC->AIC_IMR & (1<<12) ) == ( AT91C_BASE_AIC->AIC_IPR & (1<<12)))            
        {
            TC0_IrgHandler();
        
        }


Пока решил не особо пользоваться DEBUGером, просто как прошивальщик флешки и щелкаю питанием.
aaarrr
В стартапе прерывания не разрешаются.
malysh_nrg
абсолютно точно.

Причина моей проблемы: в СтартАпе.s при инициализации каждого из режимов процессора устанавливался соответствующий указатель на стек и заодно устанавливались биты F и I регистра CPSR, что означает запрет прерываний FIQ и IRQ ядра.

Решение проблемы: сброс для режима SYS (режим, в котором исполняется основная программа) бита I, что разрешит прерывания IRQ (FIQ в данном случае не используется)
Часть стартАп.s c исправленным кодом:
CODE
; Initialize the stack pointers.
; The pattern below can be used for any of the exception stacks:
; FIQ, IRQ, SVC, ABT, UND, SYS.
; The USR mode uses the same stack as SYS.
; The stack segments must be defined in the linker command file,
; and be declared above.

mrs r0,cpsr ; Original PSR value
bic r0,r0,#MODE_BITS ; Clear the mode bits
orr r0,r0,#SVC_MODE ; Set SVC mode bits
msr cpsr_c,r0 ; Change the mode
ldr sp,=SFE(SVC_STACK) ; End of SVC_STACK

bic r0,r0,#MODE_BITS ; Clear the mode bits
orr r0,r0,#UND_MODE ; Set UND mode bits
msr cpsr_c,r0 ; Change the mode
ldr sp,=SFE(UND_STACK) ; End of UND_STACK

bic r0,r0,#MODE_BITS ; Clear the mode bits
orr r0,r0,#ABT_MODE ; Set ABT mode bits
msr cpsr_c,r0 ; Change the mode
ldr sp,=SFE(ABT_STACK) ; End of ABT_STACK

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(FIQ_STACK) ; End of FIQ_STACK
;- Init the FIQ register
ldr r8, =AT91C_BASE_AIC

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) ; End of IRQ_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) ; End of CSTACK

msr cpsr_c, #SYS_MODE | F_BIT ; Change the mode Этот
ldr sp, =SFE(CSTACK)
sergeeff
На будущее совет. Не включайте в startup'e прерывание. Вам может понадобиться в main (а еще лучше до main) вызвать какую-либо функцию типа init(), где вы инициализируете все необходимое вам железо. А уж потом разрешайте прерывание отдельной функцией типа IrqEnable().
GetSmart
Цитата(malysh_nrg @ Apr 10 2010, 00:54) *
Причина моей проблемы: в СтартАпе.s при инициализации каждого из режимов процессора устанавливался соответствующий указатель на стек и заодно устанавливались биты F и I регистра CPSR, что означает запрет прерываний FIQ и IRQ ядра.

Это не проблема. Это правильный стартап. Кроме того, при аппаратном влёте в любой режим исключения, IRQ (флаг в CPSR) всё равно запретятся, даже если они были предворительно разрешены.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.