0
\$\begingroup\$

I wrote a code

int main(void) {
    uart2();
    NVIC_EnableIRQ(UART2_IRQn);
    while(1);   
} 

void receive(void) {
    SMR_485RECEIVE;
    receive_byte = LPC_UART2->RBR;
    }

void send(void) {
    SMR_485TRANSMIT;
    LPC_UART2->THR = receive_byte;
    }

void UART2_IRQHandler(void) {   

    BYTE maska = LPC_UART2->LSR & 0x01;
    if(maska == 0x01){
        delay_1_ms();
        receive();
        delay_1_ms();
        send();
        }
    }

It works first time I send a character via terminal to CPU, it sends me back the same, but then it starts to send me back \0, does anyone have idea what causes infinite loop, i think while(1), but I'm not sure how and why, and how to solve this?

Here is how it looks in terminal

http://i60.tinypic.com/2qjvi1g.png

\$\endgroup\$
3
  • \$\begingroup\$ I'm not familiar with the LPC micros, but shouldn't you be clearing an interrupt flag somewhere in your ISR to tell it that the interrupt has been handled? \$\endgroup\$
    – brhans
    Commented Apr 21, 2015 at 12:22
  • \$\begingroup\$ All the flag bits (RDA in IIR, RDR in LSR) in registers that I'm using are read-only, so Im not really sure what to do. \$\endgroup\$
    – Laki
    Commented Apr 21, 2015 at 12:24
  • \$\begingroup\$ There is stuff going on in those macros that makes this impossible to answer without it. \$\endgroup\$
    – Daniel
    Commented Apr 21, 2015 at 15:55

2 Answers 2

1
\$\begingroup\$

Are you sure there isn't a global interrupt that requires clearing? I would say that most systems have a clearable flag somewhere.

Also, is your interrupt handler routine only triggered by the UART or is that where all interrupts will land?

On PIC micro and Atmel architectures (thus I assume ARM too, otherwise my answer holds no water) there is only one function that is ever called when an interrupt occurs. It is up to the programmer to determine which specific interrupt has occurred from code. If you have, say, ten possible interrupt sources then you need to poll those ten flags individually to find the source of the IRQ. From there you call an individual routine for that interrupt.

In your case, the constant sending of the NULL character is because the program is continuously running the handler routine, but is that because the UART interrupt is being caught or because a global interrupt is set. Your code doesn't allow you to find out at the moment. The easy solution is to add a single "if" statement as the first line of the interrupt routine that returns from the routine immediately if the UART flag is not set. Do this, then run the code.

What happens?

If nothing changes, you know you MUST be able to clear that UART interrupt flag. If it truly is read only, try disabling then re-enabling the UART interrupt. There has to be a way of clearing the flag! Run the code again.

If the continuous NULL has gone, you aren't necessarily finished! Remember that the global interrupt flag may still be set so, for debugging purposes, add some more code to the interrupt handler routine to do something (maybe send a particular character) if the routine is called but the UART flag is NOT set. That's the only way you'll know you are dealing with interrupts correctly.

EDIT:

After trawling through the ARM178x User Manual I have found the key line (page 510, "18.6.5 - UARTn Interrupt Identification Register") as follows:

The UnIIR must be read in order to clear the interrupt prior to exiting the Interrupt Service Routine.

Your code just assumes that the interrupt has been called because of one single request and, although you may have only enabled one single interrupt source, the ARM expects otherwise. In a full blown program there will be more than one reason for the UARTn IRQ to occur, which means you would have to make a read to LPC_UART2->IIR to find out what has caused the interrupt. In your case it should be sufficient just to read the address and discard the information, but it might be good practise to at least check the IIR to make sure that you're handling the correct interrupt.

In my opinion a 'correct' interrupt routine shouldn't really contain much code itself. It should just check whichever interrupt register it needs to and then call subroutines to do carry out the necessary code. For example:

void InterruptServiceRoutine(void) {

    BYTE InterruptRegisterState = Requesting_Interrupt_Register;
        // This 'read' instruction should clear your read-only flags

    if (InterruptRegisterState && InterruptFlag_A)
        Interrupt_A_Handler(void);

    if (InterruptRegisterState && InterruptFlag_B)
        Interrupt_B_Handler(void);

    if (InterruptRegisterState && InterruptFlag_C)
        Interrupt_C_Handler(void);

    // ... add one for each interrupt source
}

void Interrupt_A_Handler(void) {
    // Put actual your code here...
}
    . . . etc.

As you can see this makes your initial ISR much clearer as there's nothing in it. You're then free to write as much code in your individual "Interrupt_X_Handler()" subroutine as you like.

\$\endgroup\$
5
  • \$\begingroup\$ I found this in one document, and I think thats the reason why it is in infinite loop: 'The next step is very important: clearing the interrupt flag. If your ISR returns without clearing the interrupt flag, the interrupt will endlessly occur (infinite loop).' \$\endgroup\$
    – Laki
    Commented Apr 22, 2015 at 6:27
  • \$\begingroup\$ As I can see, my program constantly enters ISR routine for UART and never exits of that infinite loop, and I think the reason is uncleared interrupt flag. Is interrupt flag for UART on LPC1788 cleared automatically or? I spent many hours trying to find out what register and bit to clear, but without success. \$\endgroup\$
    – Laki
    Commented Apr 22, 2015 at 8:18
  • \$\begingroup\$ I am just digging through the 1109-page manual for the answer to that! \$\endgroup\$ Commented Apr 22, 2015 at 8:19
  • \$\begingroup\$ Thanks for your help, I'm searching in manual and trying to find that flag bits. \$\endgroup\$
    – Laki
    Commented Apr 22, 2015 at 8:23
  • \$\begingroup\$ I found that when byte is read out from RBR register, it automatically clear RDA receive interrupt flag, but why then it constantly entering ISR routine? \$\endgroup\$
    – Laki
    Commented Apr 22, 2015 at 8:32
0
\$\begingroup\$

Finally it works, here is code, thank you all for helping me.

int main(void) {

    uart2();
    NVIC_EnableIRQ(UART2_IRQn);
    while(1);
} 

void receive(void) {

    SMR_485RECEIVE;
    receive_byte = LPC_UART2->RBR;
    }

void send(void) {

    if(receive_byte != '\0'){ //ADDED THIS IF
        SMR_485TRANSMIT;
        LPC_UART2->THR = receive_byte;
        }
}

void UART2_IRQHandler(void) {   

    BYTE maska = LPC_UART2->IIR & 0x06;

    if(maska == 0x04) {
        receive();
        delay_1_ms();
        send();
        delay_1_ms();
        }   
}
\$\endgroup\$
1
  • \$\begingroup\$ Might worth mentioning what changes you made to get it to work.. \$\endgroup\$
    – m.Alin
    Commented Apr 22, 2015 at 10:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.