logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[LPC2124] LPC2124 - przerwania IRQ timera nie działają poprawnie, co sprawdzić?

hpLukasz 20 Maj 2008 21:45 4124 23
  • #1 5162288
    hpLukasz
    Poziom 10  
    Posty: 11
    Witam

    Mam problem z przerwaniami na LPC-2124.
    Staram sie zrobic przerwania na timerze (przerwania IRQ wektoryzowane)
    Mimo odpowiednich ustawien VICIntEnable, VICVectAddr0, VICVectCntl0 przerwanie zostaje zgloszone ale procesor nie wchodzi w obsluge przerwania tylko skacze gdzies pod jakis adres (nie wiem jaki bo nie debugowalem) i procek zawiesza sie.

    Sprawdzalem flage zglaszanych przerwan i ma tam kilka bitow ustawianych (PLL, Tx- od RS232 przy programowaniu flash), ale chyba to nie ma wplywu. Acha w cpsr zeruje odpowiedni bit.

    Moze ktos sie orientuje czy nie ma tutaj dodatkowej ERRATy rozwiazujacej ten problem
  • #3 5162504
    hpLukasz
    Poziom 10  
    Posty: 11
    void IRQ_Handler( void ) __attribute__ ((interrupt("IRQ")));
    
    
    
    #define IRQ_MASK 0x00000080
    
    
    
    inline unsigned asm_get_cpsr(void)
    {
      volatile unsigned long retval;
      asm volatile (" mrs  %0, cpsr" : "=r" (retval) : /* no inputs */  );
      return retval;
    }
    
    inline void asm_set_cpsr(unsigned val)
    {
      asm volatile (" msr  cpsr, %0" : /* no outputs */ : "r" (val)  );
    }
    
    unsigned enableIRQ(void)
    {
      volatile unsigned _cpsr;
    
      _cpsr = asm_get_cpsr();
      asm_set_cpsr(_cpsr & ~IRQ_MASK);
      return _cpsr;
    }
    
    
    
    void timer( void )
    {
    	
    	T0MR0 = COMPARE_VALUE;					
    	T0MCR = 0x7;
    
    }
    
    
    void interruptConfiguration( void )
    {
    
    	enableIRQ( );
    	VICIntEnable = TIMER0_VIC;										/* enable interrupt from chanel 4 */
    
    	VICVectAddr0 = ( unsigned long )IRQ_Handler;
    	VICVectCntl0 = ( 4 | 0x20 );		
    
    	T0TCR = START_TIMER;
    
    }
    
    void IRQ_Handler( void )
    {
    
    	displayString( "interrupt" );
    	timeDelay( 10000 );
    	T0IR = 0x01;					/* clear phlag interrupt */
    	VICVectAddr = 0;
    
    }
    
    const unsigned int bufferSize = 10;
    
    
    int main( void )
    {
    	double value;
    	char buffer[ bufferSize ];
    	
    	initLCD();
    
    	timer();
    	interruptConfiguration();
    
    	while( 1 ) {}
    
    	
    	return 0;
    	
    } 


    Dodano po 2 [minuty]:

    ta wstawka asmeblerow enableIRQ() zeruje odpowiedni bit w CPSR

    Poprawiłem tytuł - https://www.elektroda.pl/rtvforum/topic1015368.html . Proszę umieszczać listingi programów w znacznikach "Code" [c_p]
  • #4 5162562
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    sprobuj przerobic sobie ten kod:

    
    	VICIntEnClr=0xffffffff;
    	VICVectAddr=0;
    	VICIntSelect=0;
    	VICVectAddr0=(unsigned long)&inc_position;
    	VICVectCntl0=IRQslot_en|IRQ_Timer0;
    	VICVectAddr1=(unsigned long)&do_pwm;
    	VICVectCntl1=IRQslot_en|IRQ_Timer1;
    	VICIntEnable=IRQ_Timer0_bit|IRQ_Timer1_bit;
    	T0TCR=CounterEnable;
    


    tutaj masz ustawienie i aktywacje przerwan od timerow. i w takiej kolejnosci nalezy to robic, bo zauwaz, ze NAJPIERW aktywujesz przerwanie, ktore jest nieustawione, a potem dopiero konfigurujesz adres i jego zrodlo i costam. to moze powodowac dziwne rzeczy, np skok pod nieistniejacy adres, jesli przypadkiem jakies przerwanie bylo 'niby-oczekujace'. jak sam zauwazyles - troche tych przerwan tam czeka i to normalne.

    sama obsluga przerwania u ciebie jest juz ok - czyszczenie flagi i adresu VICa jest.

    walcz [;

    0x41 0x56 0x45!!
  • #5 5162575
    hpLukasz
    Poziom 10  
    Posty: 11
    ok dzieki zaraz sprawdze :]
  • #6 5178905
    hpLukasz
    Poziom 10  
    Posty: 11
    Troche mi zeszlo z tym sprawdzaniem :P

    
    
    
    
    void timer( void )
    {
    	
    	T0MR0 = COMPARE_VALUE;					/* value use to compare with Timer Counter */
    	T0PR = 0;								/* Timer Counter is incremented on every pclk */
    	T0PC = 0;								/* Prescale Counter */
    	T0MCR = RESET_INTERRUPT_TC;				/* the Timer Counter will be reset, interrupt is generated when MR0 matches the value in the TC*/
    	
    //	T0TCR = START_TIMER;					/* Timer and Prescale Counter are enabled for counting */
    //	while( (T0TCR & 1) != 0 );				/* wait until start increment */
    
    }
    
    
    void interruptConfiguration( void )
    {
    	
    	enableIRQ( );
    	
    	VICIntEnClr=0xFFFFFFFF;
    	VICVectAddr=0; 
    	VICIntSelect=0; 
    	
    	VICVectAddr0 = ( unsigned long )&IRQ_Handler;
    	VICVectCntl0 = ( TIMER0_VIC_CHANNEL | VIC_IRQ_SLOT_EN );		/* interrupt channel 4, enable slot nr 0 */
    
    	VICIntEnable = TIMER0_VIC;										/* enable interrupt from chanel 4 */
    	
    	
    	
    	T0TCR = START_TIMER;					/* Timer and Prescale Counter are enabled for counting */
    	
    	/* disable other interrupts */
    	//VICIntSelect &= ! ( 1 << 4 );
    	
    }
    
    
    void IRQ_Handler( void )
    {	
    	
    	displayString( "interrupt" );
    	
    	T0IR = 0x01;					/* clear phlag interrupt */
    	VICVectAddr = 0;
    
    }
    
    
    enableIRQ()
    


    a tak juz na powaznie, mimo sugerowanej kolejnosci jest jak bylo
    procek nie wchodzi pod dany adres procedury a skacze gdzies w czeluscia swojej pamieci.

    Dodano po 2 [minuty]:

    acha to enableIRQ() jak wyzej.

    Moze ktos wie czy trzeba tez zmieniac jakis dodatkowy rejstr, ktory by globalnie zalaczal przerwania w procku
    ( tak przynajmniej bylo w AVR-ach)

    Dodano po 11 [minuty]:

    ????
  • #8 5179156
    hpLukasz
    Poziom 10  
    Posty: 11
    no tak ale zastanawiam sie czy jest cos jeszcze

    Dodano po 1 [minuty]:

    wlasciwie to juz probowalem wszystkiego i jest to samo

    Dodano po 2 [minuty]:

    wczesniej tez myslalem ze to moze byc wina priorytetu i to enableIRQ() nic nie robi ale pozniej pozmienialem priorytet na supervisor ale bylo to samo. po sprawdzeniu zawartosci cpsr wyszlo ze bit jest wyzerowany, wiec powinno byc ok...
  • #9 5179192
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    SOA #1: u mnie działa [;

    może masz jakies złe pliki nagłowkowe, złego startup'a, zły skrypt linkera, źle skonfigurowane środowisko, etc?

    spróbuj skompilować i uruchomić jakiś działający przykład.

    0x41 0x56 0x45!!
  • #10 5179265
    hpLukasz
    Poziom 10  
    Posty: 11
    nie no wszystko dziala procz przerwan (i to zarowno wewnetrznych jak i zewnetrznych)

    Dodano po 14 [minuty]:

    te przerwania u ciebie na LPC2124 dzialaly ?
  • #12 5179418
    hpLukasz
    Poziom 10  
    Posty: 11
    no wlasciwie tak, roznia sie chyba tylko flash-em.
    Wiec moze cos z prockiem.

    Wszytko pieknie sie programuje procz tych przerwan
  • #14 5181411
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    no wlasnie. to przeciez kluczowa sprawa. w pliku startup musi byc zadeklarowany wektor dla IRQ w tej oto postaci:

    
    
    	ldr		PC,reset_vector					// reset exception
    	ldr		PC,undef_vector					// undefined instruction exception
    	ldr		PC,swi_vector					// software interrupt exception
    	ldr		PC,prefetch_abt_vector			// prefetch abort exception
    	ldr		PC,data_abt_vector				// data abort exception
    	nop										// reserved for code signature
    	ldr		PC,[PC,#-0xFF0]					// interrupt exception -> VIC
    	ldr		PC,fiq_vector					// fast interrupt exception
    
    reset_vector:			.word	reset_xcpt
    undef_vector:			.word	default_xcpt
    swi_vector:				.word	default_xcpt
    prefetch_abt_vector:	.word	default_xcpt
    data_abt_vector:		.word	default_xcpt
    fiq_vector:				.word	default_xcpt
    


    oczywiscie kluczowy jest tylko ten:

    
    	ldr		PC,[PC,#-0xFF0]					// interrupt exception -> VIC
    


    0x41 0x56 0x45!!
  • #15 5182226
    Krotki
    Poziom 14  
    Posty: 93
    Pomógł: 6
    Ocena: 1
    Może jeszcze inicjalizacja stosu ? Może stos jest za mały ?
  • #16 5182952
    hpLukasz
    Poziom 10  
    Posty: 11
    Oto moj plik boot.S
    Wydaje mi sie ze wszystko jest ok, ustawiony jest teraz tryb Supervisor
    rozmiary stosu tez sie wydaja ok


    
    
    
    
    # *** Startup Code (executed after Reset) ***
    
    
    # Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
    
            .equ    Mode_USR,       0x1F
            .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,  is disabled */
            .equ    F_Bit,          0x40    /* when F bit is set, FIQ is disabled */
    		
    
    
    /*
    // <h> Stack Configuration
    //   <o>  Top of Stack Address  <0x0-0xFFFFFFFF>
    //   <h>  Stack Sizes (in Bytes)
    //     <o1> Undefined Mode      <0x0-0xFFFFFFFF>
    //     <o2> Supervisor Mode     <0x0-0xFFFFFFFF>
    //     <o3> Abort Mode          <0x0-0xFFFFFFFF>
    //     <o4> Fast Interrupt Mode <0x0-0xFFFFFFFF>
    //     <o5> Interrupt Mode      <0x0-0xFFFFFFFF>
    //     <o6> User/System Mode    <0x0-0xFFFFFFFF>
    //   </h>
    // </h>
    */
            .equ    Top_Stack,      0x40004000
            .equ    UND_Stack_Size, 0x00000004
            .equ    SVC_Stack_Size, 0x00000400
            .equ    ABT_Stack_Size, 0x00000004
            .equ    FIQ_Stack_Size, 0x00000004
            .equ    IRQ_Stack_Size, 0x00000080
            .equ    USR_Stack_Size, 0x00000400
    		.equ	SYS_Stack_Size, 0x00000020
    
    
    # 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    PLLCFG_MSEL,    (0x1F<<0)   /* PLL Multiplier */
            .equ    PLLCFG_PSEL,    (0x03<<5)   /* PLL Divider */
            .equ    PLLSTAT_PLOCK,  (1<<10)     /* PLL Lock Status */
    
    /*
    // <e> PLL Setup
    //   <o1.0..4>   MSEL: PLL Multiplier Selection
    //               <1-32><#-1>
    //               <i> M Value
    //   <o1.5..6>   PSEL: PLL Divider Selection
    //               <0=> 1   <1=> 2   <2=> 4   <3=> 8
    //               <i> P Value
    // </e>
    */
            .equ    PLL_SETUP,      1
            .equ    PLLCFG_Val,     0x00000024
    
    
    # Memory Accelerator Module (MAM) definitions
            .equ    MAM_BASE,       0xE01FC000  /* MAM Base Address */
            .equ    MAMCR_OFS,      0x00        /* MAM Control Offset*/
            .equ    MAMTIM_OFS,     0x04        /* MAM Timing Offset */
    
    /*
    // <e> MAM Setup
    //   <o1.0..1>   MAM Control
    //               <0=> Disabled
    //               <1=> Partially Enabled
    //               <2=> Fully Enabled
    //               <i> Mode
    //   <o2.0..2>   MAM Timing
    //               <0=> Reserved  <1=> 1   <2=> 2   <3=> 3
    //               <4=> 4         <5=> 5   <6=> 6   <7=> 7
    //               <i> Fetch Cycles
    // </e>
    */
            .equ    MAM_SETUP,      1
            .equ    MAMCR_Val,      0x00000002
            .equ    MAMTIM_Val,     0x00000004
    
    
    # Starupt Code must be linked first at Address at which it expects to run.
    
            .text
            .arm
    
            .global _startup
            .func   _startup
    _startup:
    
    
    # Exception Vectors
    #  Mapped to Address 0.
    #  Absolute addressing mode must be used.
    #  Dummy Handlers are implemented as infinite loops which can be modified.
    
    Vectors:        LDR     PC, Reset_Addr         
                    LDR     PC, Undef_Addr
                    LDR     PC, SWI_Addr
                    LDR     PC, PAbt_Addr
                    LDR     PC, DAbt_Addr
                    NOP                            /* Reserved Vector */
                    LDR     PC, IRQ_Addr
                    LDR     PC, FIQ_Addr
    
    Reset_Addr:     .word   Reset_Handler
    Undef_Addr:     .word   Undef_Handler
    SWI_Addr:       .word   SWI_Handler
    PAbt_Addr:      .word   PAbt_Handler
    DAbt_Addr:      .word   DAbt_Handler
                    .word   0                      /* Reserved Address */
    IRQ_Addr:       .word   IRQ_Handler
    FIQ_Addr:       .word   FIQ_Handler
    
    Undef_Handler:  B       Undef_Handler
    SWI_Handler:    B       SWI_Handler
    PAbt_Handler:   B       PAbt_Handler
    DAbt_Handler:   B       DAbt_Handler
    IRQ_Handler:    B       IRQ_Handler
    FIQ_Handler:    B       FIQ_Handler
    
    
    # Reset Handler
    
    Reset_Handler:  
    
    
    .if PLL_SETUP
                    LDR     R0, =PLL_BASE
                    MOV     R1, #0xAA
                    MOV     R2, #0x55
    
    # Configure and Enable PLL
                    MOV     R3, #PLLCFG_Val
                    STR     R3, [R0, #PLLCFG_OFS] 
                    MOV     R3, #PLLCON_PLLE
                    STR     R3, [R0, #PLLCON_OFS]
                    STR     R1, [R0, #PLLFEED_OFS]
                    STR     R2, [R0, #PLLFEED_OFS]
    
    # Wait until PLL Locked
    PLL_Loop:       LDR     R3, [R0, #PLLSTAT_OFS]
                    ANDS    R3, R3, #PLLSTAT_PLOCK
                    BEQ     PLL_Loop
    
    # Switch to PLL Clock
                    MOV     R3, #(PLLCON_PLLE | PLLCON_PLLC)
                    STR     R3, [R0, #PLLCON_OFS]
                    STR     R1, [R0, #PLLFEED_OFS]
                    STR     R2, [R0, #PLLFEED_OFS]
    .endif
    
    
    .if MAM_SETUP
                    LDR     R0, =MAM_BASE
                    MOV     R1, #MAMTIM_Val
                    STR     R1, [R0, #MAMTIM_OFS] 
                    MOV     R1, #MAMCR_Val
                    STR     R1, [R0, #MAMCR_OFS] 
    .endif
    
    
    # Initialise Interrupt System
    #..
    
    
    # Setup Stack for each mode
    
                    LDR     R0, =Top_Stack
    
    #  Enter Undefined Instruction Mode and set its Stack Pointer
                    MSR     CPSR_c, #Mode_UND|I_Bit|F_Bit
                    MOV     SP, R0
                    SUB     R0, R0, #UND_Stack_Size
    
    #  Enter Abort Mode and set its Stack Pointer
                    MSR     CPSR_c, #Mode_ABT|I_Bit|F_Bit
                    MOV     SP, R0
                    SUB     R0, R0, #ABT_Stack_Size
    
    #  Enter FIQ Mode and set its Stack Pointer
                    MSR     CPSR_c, #Mode_FIQ|I_Bit|F_Bit
                    MOV     SP, R0
                    SUB     R0, R0, #FIQ_Stack_Size
    
    #  Enter IRQ Mode and set its Stack Pointer
                    MSR     CPSR_c, #Mode_IRQ|I_Bit|F_Bit
                    MOV     SP, R0
                    SUB     R0, R0, #IRQ_Stack_Size
    
    #  Enter Supervisor Mode and set its Stack Pointer
                    MSR     CPSR_c, #Mode_SVC|I_Bit|F_Bit
                    MOV     SP, R0
                    SUB     R0, R0, #SVC_Stack_Size
    
    #  Enter User Mode and set its Stack Pointer
                    MSR     CPSR_c, #Mode_USR|I_Bit|F_Bit
                    MOV     SP, R0
    
    #  Setup a default Stack Limit (when compiled with "-mapcs-stack-check")
                    SUB     SL, SP, #USR_Stack_Size
    
    
    # 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
    
    
    # Enter the C code
                    ADR     LR, __main_exit
                    LDR     R0, =main
                    BX      R0
    
    __main_exit:    B       __main_exit
    
    
            .size   _startup, . - _startup
            .endfunc
    
    
            .end
    
    
  • #17 5182969
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    no przeciez nie jest ok... poczytaj mojego posta i popatrz na swojego

    czy to (u ciebie):

    LDR PC, IRQ_Addr

    jest podobne do (u mnie):

    ldr PC,[PC,#-0xFF0]

    chyba nie bardzo...

    0x41 0x56 0x45!!
  • #18 5183024
    hpLukasz
    Poziom 10  
    Posty: 11
    ok zaraz sprawdze.

    a ta wartosc -0xFF0 dotyczy kazdej procedury przerwan ?

    Dodano po 21 [sekundy]:

    ok zaraz sprawdze.

    a ta wartosc -0xFF0 dotyczy kazdej procedury przerwan ?
  • #20 5183068
    Krotki
    Poziom 14  
    Posty: 93
    Pomógł: 6
    Ocena: 1
    To jest standardowa instrukcja w ARMach ... po prostu jadro ma tylko 2 wektory przerwania IRQ i FIQ i żeby wykonać odpowiednie przerwanie dokonuje sie tak zwanej wektoryzacji która polega jak zaznaczył Freddie na załadowaniu do PC adresu z rejestru (nie pamiętam nazwy) który jest pod adresem względnym PC-0xFF0. I tyle :)
  • #21 5183094
    hpLukasz
    Poziom 10  
    Posty: 11
    do konca nie czaje jak ale zadzialalo, dzieki brahu

    Dodano po 1 [minuty]:

    ok juz teraz czaje

    wielkie dzieki !!!!!!!!!!

    Dodano po 38 [minuty]:

    a jezcze jedno pytanko, jesli ma wychodzic z przerwania nic juz nie musze zmieniac w boot.s, wystarczy ze odpowiednio skonfiguruje obsluge przerwania ?
  • #22 5384840
    zorg666
    Poziom 22  
    Posty: 556
    Pomógł: 30
    Ocena: 28
    Chciałbym na timerze0 zrealizować ciągły odczyt czterech niezależnych liczników w trybie obsługi przerwań za pomoca kanałow porównująch, MR0, MR1, MR2, MR3.
    Timer1 jest zajęty.
    Czasy to 100 msec, 60 sekund , 100 sekund oraz dowolny inny.
    tick dla timera0 wybrałem na 1 msec.
    Licznik działa poprawnie bez włączenia przerwań od timera0, liczy te 1000 Hz.
    W momencie włączenia przerwań od timera0 , licznik zaczyna liczyć wolno.
    Zmienne przekazywane od przerwań ( typu volatile ) są skorelowane ze sobą, takie same.
    np. licz: 50
    injec KM Ftime WakeUp 5 4 4 4

    Przerwania od timera0 działają tylko wtedy jeśli są właczone flagi R.
    Przerwania powinny działać także przy włączeniu flag I, flaga R resetu zeruje licznik i nie ma mozliwości wykorzystania innych kanałów porównujących.
    kompilator to GCC wersja 3.4.3, 4.1.1 oraz 4.2.2 zachowuje się tak samo.
    Na forum była podana informacja że to problem "rozbiegówki " i GCC żle wstawia kody dla
    __attribute__ ((interrupt));

    - ponizej załączam także plik assemblera, znalazłem "rozbiegówkę kolegi
    _Matik_ ale nie wiem jak to wkomponować w te moją.


    
    
    static void initTimer0(void (*pISR)(), void (*pCallback)())
    {
    	
    	pTimerCallback = pCallback;				//store timer callback function pointer
    											//initialize VIC for Timer0 interrupts
    	VICIntSelect &= ~0x10;       				//Timer0 interrupt is assigned to IRQ
    	VICVectAddr4  = (tU32)pISR;  				//register ISR address
    	VICVectCntl4  = 0x24;        				//enable vector interrupt for timer0
    	VICIntEnable |= 0x00000010;				//enable timer0 interrupt
    
    	T0TCR = 0x00;
    	T0TCR = 0x02;
    	T0TCR = 0x00;							// stop, reset, release timer0
    	T0IR  = 0x000000ff;						//reset all flags before enable IRQs
    	
    	T0PR = 14999;							// 1kHz , prescaler (12 MHz x 5) / 4 == 15.000.000 Hz
    	//	T0CTCR = 0x00;							// enable timer mode
    	T0CCR = 0;
    	T0EMR = 0;
    	T0MCR = 0;
    	T0PC  = 0x00000000;						//no prescale of clock T0PC = 0x3FFFFFFF
    
    //	T0MR0 = SYSTEM_TIME_100;				// calculate for 100 msec
        T0MR0 = 10;			    
    //	T0MR1 = SYSTEM_TIME_60000;		    	// calculate for 60.000 msec
    	T0MR1 = 100;		
    //	T0MR2 = SYSTEM_TIME_100000;				// calculate for 100.000 msec
        T0MR2 = 500;				
    //	T0MR3 = SYSTEM_TIME_TICK;				// calculate no of timer ticks
        T0MR3 = 1000;		
    
    	T0MCR |= TMCR_MR3_I |TMCR_MR3_R |TMCR_MR2_I  |TMCR_MR1_I |TMCR_MR0_I ;	
    	//	T0MCR = TMCR_MR3_I |TMCR_MR3_R |TMCR_MR2_I |TMCR_MR1_I |TMCR_MR0_I ;	
    											// # 649 generate IRQ on MR0, MR1, MR2, MR3 match
    	T0TCR = 0x00000001;                     //start Timer0
    	
    	systemTimeMs = 0;						//reset system time
      
    }
    
    




    
    
    void timer0ISR(void)
    {
    	volatile tU32 cpsrReg;
    	volatile tU32 timer_ptr;
    	volatile tU32 saved_match_value;
    	volatile tU8  statusReg;
    	
    	LCD_CLR = P012_SEL;						// timer0 interrupt indicator, active low
    	
    	//----------------------------------  start interrupt --------------------------
    	switch ((statusReg = T0IR) & 0x0F)
    	{
    	
    	case 1:
    	
    //		cpsrReg = disIrq();					//disable IRQ    ### ?
    		timer_ptr = T0TC;					// save timer count
    		T0MCR &= ~(TMCR_MR0_I);							// disable match 0
    		saved_match_value = timer_ptr + 10;		// next match 0 in period 100 msec		
    //		saved_match_value = timer_ptr + SYSTEM_TIME_100;		// next match 0 in period 100 msec
    		T0MCR |= TMCR_MR0_I;								// enable match 0
    		
    		readInjectionTime = readInjectionTime +1; 
    		T0IR = TIR_MR0I;					// irq on MR0
    //		restoreIrq(cpsrReg);				//enable IRQ	### ?
    		
    	break;
    
    	case 2:
    	
    //		cpsrReg = disIrq();					//disable IRQ    ### ?
    		timer_ptr = T0TC;					// save timer count
    		T0MCR &= ~(TMCR_MR1_I);							// disable match 1
    		saved_match_value = timer_ptr + 100;		// next match 1 in period 60 sec, 
    //		saved_match_value = timer_ptr + SYSTEM_TIME_60000;		// next match 1 in period 60 sec, 
    		T0MCR |= TMCR_MR1_I;								// enable match 1
    		
    		readKM = readKM +1;						// read road  
    		T0IR = TIR_MR1I;					// irq on MR0 
    //		restoreIrq(cpsrReg);				//enable IRQ	### ?
    	
    	break;
    	
    	case 4:
    
    //		cpsrReg = disIrq();					//disable IRQ    ### ?
    		timer_ptr = T0TC;					// save timer count
    		T0MCR &= ~(TMCR_MR2_I);							// disable match 2
    		saved_match_value = timer_ptr + 500;		// next match 2 in period 100 sec
    //		saved_match_value = timer_ptr + SYSTEM_TIME_100000;		// next match 2 in period 100 sec
    		T0MCR |= TMCR_MR2_I;								// enable match 2
    		
    		readFTime = readFTime +1;					// calculate FT
    		T0IR = TIR_MR2I;					// irq on MR0 
    //		restoreIrq(cpsrReg);				//enable IRQ	### ?
    			
    	break;
    	
    
    	case 8:
    
    		timer_ptr = T0TC;					// save timer count
    		T0MCR &= ~(TMCR_MR3_I);							// disable match 3
    		saved_match_value = timer_ptr + 1000;	// next match 3 in period 500 msec 
    //		saved_match_value = timer_ptr + SYSTEM_TIME_TICK;	// next match 3 in period 500 msec 
    		T0MCR |= TMCR_MR3_I;								// enable match 3
    
    //		systemTimeMs += (1000 / SYSTEM_TIME_TICK);	//update system time (in ms)
    //		systemTimeMs = systemTimeMs + 1000;	
    //		if (pTimerCallback != NULL)				//call timer callback, if registered
    //		(*pTimerCallback)();
    
    		readWakeUp = readWakeUp + 1;
    		T0IR = TIR_MR3I;					// irq on MR0 
    
    	break;	
    	
    //	    default:
    //		T0IR        = 0xff;					//reset all IRQ flags	
    	
    //	break;	
    	
    
    	}
    
    	
    	LCD_SET = P012_SEL;
    	VICVectAddr = 0x00000000;				//dummy write to VIC to signal end of interrupt
    							// end of interupt timer0
    }
    
    
    
    Załączniki:
    • _Matik_code.rar (958 Bajtów) Musisz być zalogowany, aby pobrać ten załącznik.
    • startup.rar (2.35 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #23 5408939
    99none
    Poziom 19  
    Posty: 339
    Pomógł: 27
    Ocena: 11
    Zastosuj poniższe makra w pliku timer0ISR na poczatku i na koncu funkcji.



    
    /******************************************************************************
     * MACRO Name: ISR_ENTRY()
     * Description:
     *    This MACRO is used upon entry to an ISR.  The current version of
     *    the gcc compiler for ARM does not produce correct code for
     *    interrupt routines to operate properly with THUMB code.  The MACRO
     *    performs the following steps:
     *    1 - Adjust address at which execution should resume after servicing
     *        ISR to compensate for IRQ entry
     *    2 - Save the non-banked registers r0-r12 and lr onto the IRQ stack.
     *    3 - Get the status of the interrupted program is in SPSR.
     *    4 - Push it onto the IRQ stack as well.
      *****************************************************************************/
    #define ISR_ENTRY() asm volatile(" sub   lr, lr,#4\n" \
                                     " stmfd sp!,{r0-r12,lr}\n" \
                                     " mrs   r1, spsr\n" \
                                     " stmfd sp!,{r1}")
    
    /******************************************************************************
     * MACRO Name: ISR_EXIT()
     * Description:
     *    This MACRO is used to exit an ISR.  The current version of the gcc
     *    compiler for ARM does not produce correct code for interrupt
     *    routines to operate properly with THUMB code.  The MACRO performs
     *    the following steps:
     *
     *    1 - Recover SPSR value from stack       
     *    2 - and restore  its value                   
     *    3 - Pop the return address & the saved general registers from
     *        the IRQ stack & return
     *****************************************************************************/
    #define ISR_EXIT()  asm volatile(" ldmfd sp!,{r1}\n" \
                                     " msr   spsr_c,r1\n" \
                                     " ldmfd sp!,{r0-r12,pc}^")
    
    /******************************************************************************
    
    



    
    										// perform proper ISR entry so thumb-interwork works properly
    	ISR_ENTRY();										
    



  • #24 5418858
    zorg666
    Poziom 22  
    Posty: 556
    Pomógł: 30
    Ocena: 28
    nie wiem jaki był to problem ale te makra u mnie nie działały.
    dopiero przeniesienie obsługi timera 0 na konto systemowe i można działać z timerem 1.
    Obecnie testuje prowadzenie 4 niezaleznych liczników na timerze 1 z korelacją czasów.
    wada jest że program działa w trybie ARM.
    rozbiegówka systemu nie musi byc zmieniana.

    
    
       .file        "commonIRQ.S"
    
      .text
      .section .text
      .code 32
    
    @******************************************************************************
    @                            CONSTANT DECLARATIONS
    @******************************************************************************
    
    #define NO_INT   0xC0
    #define MODE_SYS 0x1F
    #define MODE_IRQ 0x12
    
    
    @******************************************************************************
    @                            EXTERNAL DECLARATIONS
    @******************************************************************************
      .extern  handleIRQs
    
    
    @******************************************************************************
    @ Description:
    @   A general interrupt handler.
    @   Save the current context on the stack and switch mode to: SYSTEM.
    @******************************************************************************
            .align 2
            .global _generalIrqHandler
            .type _generalIrqHandler,function
    
    _generalIrqHandler:
            SUB     LR,LR,#4
            STMFD   SP!,{R0-R12,LR}     //store registers
            MRS     R1,SPSR
            STMFD   SP!,{R1}
    
    @        STMFD   SP,{LR}^
    @        SUB     SP,SP,#4
    
            @
            @ Disable interrupts and change to SYSTEM mode (from IRQ mode)
            @
            MSR     CPSR_c,#(NO_INT | MODE_SYS)
            
            @
            @ Handle the IRQ by calling the appropriate ISR
            @ (that will execute in SYSTEM mode)
            @
            BL      handleIRQs
    
            @
            @ Change to IRQ mode (from SYSTEM mode)
            @
            MSR     CPSR_c,#(NO_INT | MODE_IRQ)
    
    @        LDMFD   SP,{LR}^
    @        ADD     SP,SP,#4
    
            @
            @ Restore interrupted context and return
            @
            LDMFD   SP!,{R1}
            MSR     SPSR_cxsf,R1
            LDMFD   SP!,{R0-R12,PC}^   //Restore registers and return
    
    


    
    
    /*****************************************************************************
     *
     * Description:
     *    The routine is called whenever an IRQ occurs, and it should dispatch the 
     *    correct IRQ handler (with information from VIC). 
     *
     ****************************************************************************/
    void handleIRQs(void)
    {
      void (*pfnct)(void);                   /* pfnct is declared to be a function pointer      */
      
      pfnct = (void (*)(void))VICVectAddr;   /* read interrupt vector from the VIC              */
    
    											/* loop through all currently active interrupts */
      while (pfnct != (void (*)(void))0)
      {
        (*pfnct)();                          /* call the registered ISR for interrupting device */
        pfnct = (void (*)(void))VICVectAddr; /* read next interrupt vector from the VIC         */
      }
    }
    
    

Podsumowanie tematu

✨ Dyskusja dotyczy problemów z obsługą przerwań IRQ timera na mikrokontrolerze LPC2124. Użytkownik zgłasza, że pomimo poprawnej konfiguracji rejestrów VIC (VICIntEnable, VICVectAddr0, VICVectCntl0) przerwanie jest zgłaszane, lecz procesor nie wchodzi do procedury obsługi przerwania, tylko skacze pod nieznany adres i zawiesza się. Wskazano, że kluczowa jest poprawna konfiguracja wektora przerwań w pliku startowym boot.S, gdzie standardowo dla ARM stosuje się instrukcję wektoryzacji przerwań: ldr PC, [PC, #-0xFF0], która ładuje adres obsługi przerwania z rejestru VICVectAddr. Niepoprawne ustawienie tego wektora (np. ldr PC, IRQ_Addr) może powodować skoki do nieprawidłowych adresów. Ponadto zwrócono uwagę na kolejność konfiguracji rejestrów VIC (najpierw wyczyszczenie i ustawienie adresów wektorów, a dopiero potem włączenie przerwań), a także na konieczność odpowiedniego ustawienia bitu IRQ w rejestrze CPSR. W dyskusji pojawiły się także uwagi dotyczące stosu i trybu pracy procesora (Supervisor). W dalszej części poruszono kwestie związane z obsługą wielu kanałów porównawczych timera i problemami z kompilatorem GCC w kontekście przerwań, sugerując stosowanie makr do poprawnej obsługi ISR. Ostatecznie rozwiązaniem problemu było poprawne ustawienie wektora przerwań w pliku boot.S oraz właściwa konfiguracja obsługi przerwań w kodzie użytkownika.
Podsumowanie wygenerowane przez AI na podstawie treści dyskusji.
REKLAMA