SparkFun Electronics Forum Index SparkFun Electronics
MicroController Ideas and Support
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

LPC2294 Uart interrupt problem

 
Post new topic   Reply to topic    SparkFun Electronics Forum Index -> Everything ARM and LPC
View previous topic :: View next topic  
Author Message
daa



Joined: 29 Jan 2008
Posts: 8

PostPosted: Mon Jul 07, 2008 1:42 pm    Post subject: LPC2294 Uart interrupt problem Reply with quote

Hello there,

I am having this strange problem where once an Interrrupt happens, interrupts are disabled forever. After the first occurance of the interrupt, even though interrupts are happening and the processor knows about it, because interrupts stays disabled in CPSR, it never goes back to the ISR. I DO NOT need to nest the interrupts. I actually prefer not to do that. I have found some example interrupt nesting code in assembly. I updated my crt.s file with those updates and that didn't help either.

Ok.. the basic thing I am trying to achieve is the following. I have a main loop that's being triggered by a timer interrupt. I have configured Timer1 to interrupt at every 10msec for this purpose. Then I am receiving data in Uart0. Uart0 raises an interrupt after it receives one byte of data. My plan was to send this byte out through Uart1. But for now I am just doing some dummy reads to clear the interrupt.

I have a very simple main loop where it toggles a bit to let me know if it's running. Now if I am not sending any data to the uart, the main loop is running smoothly which tells me that timer1 interrupt is happening periodically. But the moment I start sending data, I see that the timer1 interrupt has stopped working. After stepping through the code what I have noticed is that when it comes out of the Uart interrupt, for some reason it leaves the IRQ bit in the CPSR register disabled. How do I stop this from happening? I don't think I am doing anything special with Uart interrupt. It's working fine with the timer interrupt, then why does it mess up in case of timer interrupt.


Code:

     
void Uart0_ISR(void)
{
   if(toggle) // toggle a bit
      IOSET0 = 0x00000008;
   else
      IOCLR0 = 0x00000008;
   toggle = ~toggle;
   while(!(U0LSR & 0x01));
       data = U0RBR; // dummy read
       data = U0IIR;   // dummy read
}   

void Uart0_Driver_init(Uart0_Driver *this)//, FrequencyFormatter *FF_handle)
{
    //this->rx_buffer = rx_buffer;
    //this->rx_buffer_size = rx_buffer_size;
    Uint8 q;
    // set the pin
//    PINSEL0 = PINSEL0 | PINSEL0_08_UART1_TX |
//              PINSEL0_09_UART1_RX;

    PINSEL0 = PINSEL0 | PINSEL0_00_UART0_TX |
              PINSEL0_01_UART0_RX ;
   
    // Set the line control registers
    U0LCR = U0LCR_WORD_LENGTH_SELECT_8  |
            U0LCR_1_STOP_BIT            |
            U0LCR_PARITY_DISABLE        | // Parity = None.
            U0LCR_BREAK_CONTROL_DISABLE |
            U0LCR_DIVISOR_LATCH_ACCESS_ENABLE;

    // Now set the baud rate.
    U0DLL = (60000000/9600/16) & 0xFF;             // should be 0x86 for 9600
    U0DLM = ((60000000/9600/16)>>8) & 0xFF;        // should be 0x01 for 9600
   
    //Configure the FIFO first
    U0FCR = U0FCR_FIFO_ENABLE       |
            U0FCR_RX_FIFO_RESET     |
            U0FCR_RX_TRIGGER_LEVEL_01;


    //Disable the divisor latch access
    U0LCR = U0LCR_WORD_LENGTH_SELECT_8  |
            U0LCR_1_STOP_BIT            |
            U0LCR_PARITY_DISABLE        | // Parity = None.
            U0LCR_BREAK_CONTROL_DISABLE |
            U0LCR_DIVISOR_LATCH_ACCESS_DISABLE;

    q = U0RBR;
   
    VICIntEnable = ENABLE_UART0_INTERRUPT;
    VICVectCntl1 = THIS_VIRQ_IS_ENABLED |
                   UART0_INTERRUPT;
    VICVectAddr1 = (unsigned long)Uart0_ISR;

   
    // UART1 interrupt handling
    U0IER = ENABLE_U0IER_RDA_INTERRUPT;
 
    return;
}


Code for another ISR is as follows:

Code:


void mainLoopTimerInit(void)
{
    // Configure for Timer 0 Match 0
    PINSEL0 = PINSEL0 | PINSEL0_12_MAT_1_0;

    // Timer Control Register
    T1TCR = TCR_COUNTER_RESET;

    // Match register values
    T1MR0 = 600000;
    //    T0MR1 = 0;
    //    T0MR2 = 0;
    //    T0MR3 = 0;

    // Match control register
    T1MCR = MCR_INTERRUPT_MR0 |
            MCR_RESET_MR0;

    // Capture control register
    //T1CCR = CCR_CAPTURE_ON_CAP0_FALLING_EDGE |
    //        CCR_CAPTURE_ON_CAP0_INTERRRUPT;

    VICVectAddr2 = (unsigned long)timer_1_match_0_ISR;
    VICVectCntl2 = THIS_VIRQ_IS_ENABLED |
                   TIMER1_INTERRUPT;
    VICIntEnable = ENABLE_TIMER1_INTERRUPT;

    T1TCR = TCR_COUNTER_ENABLE;
}


void __attribute__((interrupt("IRQ"))) timer_1_match_0_ISR(void)
{
   main_loop_enable = 1;
       T1IR        = IR_RESET_MR0_INTERRUPT  ;     // Clear interrupt flag
       VICVectAddr = 0;                            // Acknowledge Interrupt
}
Back to top
View user's profile Send private message
jonloveslou



Joined: 20 Jul 2007
Posts: 13

PostPosted: Wed Jul 09, 2008 8:51 am    Post subject: Reply with quote

Don't you need
Code:
__attribute__((interrupt("IRQ")))
and
Code:
VICVectAddr = 0;

in your Uart0_ISR as well?
Back to top
View user's profile Send private message
daa



Joined: 29 Jan 2008
Posts: 8

PostPosted: Tue Jul 15, 2008 4:06 pm    Post subject: Fix Reply with quote

A past post from somebody named Magnus helped me resolve this issue.

When compiler sees __attribute__ ((interrupt("IRQ"))) specifier, it adds appropriate to handle the entering and exiting the interrupt. It seemed like in my case, for some reason, the compiler wasn't generating the proper code. I removed this specifier and replaced it with __attribute__ ((naked)). If used this attribute, the compiler doesn't add code to handle entering the exiting the interrupt. I used the following code in my crt.s file for interrupt handing.

Code:

IRQHandler:
/* Adjust link register and save r0 and lr on IRQ stack */
                sub      lr, lr, #4
                stmfd    sp!, {r0, lr}
/*− SPSR needs to be saved on IRQ stack for nested interrupt */
                mrs      r14, SPSR
                stmfd    sp!, {r14}
/* Read the AIC Interrupt Vector register to clear the interrupt and fetch IRQ handler address */
                ldr      r14, =VICVECTADDR
                ldr      r0 , [r14]
/* Enable IRQ interrupts and switch to Supervisor mode */
                msr      CPSR_c, #ARM_MODE_SVC
/* Save scratch/used registers and LR in Supervisor Stack */
                stmfd    sp!, {r0-r12, r14}
/* Branch to the C language routine pointed by the AIC_IVR */
                mov      r14, pc
                bx       r0
/* Restore scratch/used registers and LR from Supervisor Stack */
                ldmia    sp!, {r0-r12,r14}
/* Disable IRQ interrupts and switch back to IRQ mode */
                msr      CPSR_c, #ARM_MODE_IRQ | I_BIT
/* Mark the End of Interrupt on the AIC */
                ldr      r14, =VICVECTADDR
                str      r14, [r14, #0]
/* Restore SPSR_irq and r0 from IRQ stack */
                ldmia    sp!, {r14}
                msr      SPSR_cxsf, r14
/* pop r0 and lr from IRQ stack and restore the SPSR_irq; this returns from IRQ interrupt */
                ldmia    sp!, {r0, pc}^


This took care of my problem.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    SparkFun Electronics Forum Index -> Everything ARM and LPC All times are GMT - 7 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group