This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Serial interrupt behaviour?

Hi everyone!

I'm a n00b to microcontroller programming so have patience with me :)

The mission is to handle some uart (rs232) communication, both rx and tx. My part is a small module going into a rest of the software already developed.

The issue is the following: When I use serial ISR it seems to not go into the "main while loop" (which is required).

(I've also tried to poll my self but reliability seems somewhat unstable, loosing a byte here and there)

I've tried the simplest demo/test programs and if I for instance use a printf in the while loop, it will not reach it as soon as ES = 1.

Is it just that any printf will not issue an interrupt and hence no output to my terminal? At the moment I can not test my module with the rest of the software so I'm a bit in the blind here, well could of course try to blink a led or something... but I reacon a answer from here is faster and more reliable :)

Thanks in advance

/Mike

  • The issue is the following: When I use serial ISR it seems to not go into the "main while loop" (which is required).

    It would be helpful if you posted your ISR. Or even your complete test case (if it is small enough - it should be the smallest program that will reliably reproduce the problem you are encountering).

    Also, when posting source code, follow the instructions that you find above the text window, in order to keep the source code legible.

  • Is it just that any printf will not issue an interrupt and hence no output to my terminal?

    If you look at the putchar() function (which is used by the printf() function), you should find that it actually uses polling. It's usually a bad idea to mix interrupt-driven and polling operation for a peripheral. You may need to adapt the putchar() function to operate the UART with interrupts.

  • Of course here it is:

    #include "at89c5131.h"
    #include "stdio.h"

    char uart_data

    void main (void)
    {
        int i=0;
    
        uartInit();
    
        // Global interrupt
        EA = 1;
    
        // Serial interrupt
        // Comment out below and printf in while will work
        ES = 1;
    
        while(1)
        {
            printf("...");
        }
    }
    
    // The ISR function echos the received character
    void serial_IT(void) interrupt 4
    {
        if(RI==1)
        {
            RI=0;
            uart_data = SBUF; //Read received data
            SBUF = uart_data; //Send back same data on uart
        }
        else TI=0;
    }
    

  • Of course here it is:

    uart_init() would also be of interest.

    Also, as I mentioned below, using printf() and using interrupt-driven operation on the UART at the same time is most likely a bad idea. You may need to find a different method to indicate that the program has entered the main loop (e.g. toggle a port pin or blink a LED - or use a breakpoint if your emulator/debugger supports it).

  • "using printf() and using interrupt-driven operation on the UART at the same time is most likely a bad idea."

    Not at all!

    There is absolutely no reason whatsoever why you should not use printf with interrupt-driven serial IO provided you make the necessary changes to putchar() - See:
    http://www.keil.com/support/man/docs/c51/c51_printf.htm

    See also:
    http://www.keil.com/support/man/docs/c51/c51_putchar.htm
    http://www.keil.com/support/man/docs/c51/c51_lib_source.htm

    It's all clearly illustrated in the following Keil examples:
    http://www.keil.com/download/docs/200.asp
    http://www.keil.com/download/docs/71.asp
    You can use this code directly in your application - no need to re-invent the wheel!

  • "Is it just that any printf will not issue an interrupt"

    Maybe that's just a poor choice of words, but you need to understand that the interrupt is never issued by printf - nor even putchar, nor any other such software.

    The interrupt is "issued" by the hardware when it has completed sending a byte.

    Sorry if you did realise that, and it was just words - but, for full details, see Chapter 3 of the so-called "bible" for the 8051:

    Chapter 1 - 80C51 Family Architecture:
    www.nxp.com/.../80C51_FAM_ARCH_1.pdf

    Chapter 2 - 80C51 Family Programmer's Guide and Instruction Set:
    www.nxp.com/.../80C51_FAM_PROG_GUIDE_1.pdf

    Chapter 3 - 80C51 Family Hardware Description:
    www.nxp.com/.../80C51_FAM_HARDWARE_1.pdf

  • Well actually the interrupts for the serial port can be set by software (RI and TI set to 1 will give a interrupt).

    Excerpt from the bible:

    All of the bits that generate interrupts can be set or cleared by
    software, with the same result as though it had been set or cleared
    by hardware. That is, interrupts can be generated or pending
    interrupts can be canceled in software.

    But my main problem is the understanding of why the program will not proceed to the while loop and just print the ... indefinately. If I choose to not activate serial interrupt (ES !=1) it does proceed and prints the ... Interrupts usually does not block but interrupt when something exiting happens :).

  • But my main problem is the understanding of why the program will not proceed to the while loop and just print the ... indefinately.

    Can you post your UART init routine ?

    Also, you may want to look at 1) the power-on default value of SCON and 2) the putchar() routine (which you can find in \C51\LIB).

    The power-on default value for TI in SCON is 0, while putchar will wait in an endless loop while TI is 0 (since it assumes that TI==0 means that a character is currently being transmitted - which is not the case after power-on). Therefore, using putchar() without either 1) sending one character "by hand" or 2) setting TI to 1 manually will result in being stuck in and endless loop.

  • void uartInit(void);
    {
       SCON  = 0x50;
       TMOD |= 0x20;
       TH1   = 0xF7;
       TR1   = 1;
       PCON |= 0x80;
       TI    = 1;
    }
    

    By the way, thanks for your interest in my problem :)

  • Okay, I think we're getting somewhere. Your problem is a good example why interrupt-driven and polling operation on a peripheral should not be mixed.

    I've added some comments to your code that should show what is happening.

    void uartInit(void);
    {
       SCON  = 0x50;
       TMOD |= 0x20;
       TH1   = 0xF7;
       TR1   = 1;
       PCON |= 0x80;
       TI    = 1;
    }
    
    
    void main (void)
    {
        int i=0;
    
        uartInit(); // This sets TI to 1
    
        // Global interrupt
        EA = 1;
    
        // Serial interrupt
        // Comment out below and printf in while will work
        ES = 1; // Since TI is 1, MCU will jump to UART ISR immediately
    
        while(1)
        {
            printf("..."); // printf will call putchar(), and putchar will enter an endless loop since TI is 0
        }
    }
    
    // The ISR function echos the received character
    void serial_IT(void) interrupt 4
    {
        if(RI==1)
        {
            RI=0;
            uart_data = SBUF; //Read received data
            SBUF = uart_data; //Send back same data on uart
        }
        else TI=0; // If TI was 1, then TI is set to 0
    }
    

  • "Well actually the interrupts for the serial port can be set by software (RI and TI set to 1 will give a interrupt)."

    It's true that they can - but printf does not, and neither does putchar, nor any other such software (unless you make it so).

    Note that "such" was key there!

  • Just to clearify, if you add a printf above the ES = 1; row it will be executed.

    Any printf below ES = 1; will not be executed. Although any printf done from the interrupt function will work fine.

    I need my interrupt to not block the rest of the "show".

  • I think Christoph has explained that?

    You are still using a polled putchar, but your ISR clears TI, so putchar never transmits a character, so no further TIs are generated!

    "If I choose to not activate serial interrupt (ES !=1) it does proceed"

    If the interrupt is disabled, the ISR never fiddles with TI, and the polled putchar proceeds as normal!

    "Interrupts usually does not block"

    It's not the interrupt that's blocking - it's you polling putchar!
    Your ISR is interfering with the condition that your putchar is polling for!

    Again, as Christoph said, "Your problem is a good example why interrupt-driven and polling operation on a peripheral should not be mixed"

  • Although any printf done from the interrupt function will work fine.

    Calling a non-reentrant, heavyweight function like printf() inside an interrupt service routine is another bad idea.

  • Ahhh ok, tnx guys. Well my hunch was not too far from the target at least :).

    In the "real world" no printf (even or stdio.h) will be allowed.

    The only thing to put my head around is how all the previous debug code will be possible to execute... I just have to develop code that does not need debugging ;)

    Thanks again.

    /Mike