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

Problem with interrup on P89C557E4

Hi, i'm having a problem with the interrupt routine for timer 0 on the P89C557E4 Philips chip.
The interrupt routine doesn't work when running the program. when i simulate it, it works fine.
below is the code:

#include <reg557.h>
#define TIMER0_COUNT 0xDC11 /* 10000h - ((11,059,200 Hz / (12 * FREQ)) - 17) */
static unsigned timer0_tick; /* timer tick variable */
/*------------------------------------------------------------------------------
static void timer0_isr (void);
This function is an interrupt service routine for TIMER 0. It should never
be called by a C or assembly function. It will be executed automatically
when TIMER 0 overflows.
------------------------------------------------------------------------------*/
static void timer0_isr (void) interrupt 1 using 1
{
/*------------------------------------------------
Stop Timer 0, adjust the timer 0 counter so that
we get another interrupt in 10ms, and restart the
timer.
------------------------------------------------*/
TR0 = 0; /* stop timer 0 */
TL0 = TL0 + (TIMER0_COUNT & 0x00FF);
TH0 = TH0 + (TIMER0_COUNT >> 8);
TR0 = 1; /* start timer 0 */
/*------------------------------------------------
Increment the timer tick. This interrupt should
occur approximately every 10ms. So, the resolution
of the timer will be 100Hz not including interrupt
latency.
------------------------------------------------*/
//timer0_tick++;
CMSR4 = 0;
}
/*------------------------------------------------------------------------------
void timer0_initialize (void);
This function enables TIMER 0. TIMER 0 generates a synchronous interrupt
once every 100Hz.
------------------------------------------------------------------------------*/
void timer0_initialize (void)
{
EA = 0; /* disable interrupts */
timer0_tick = 0;
TR0 = 0; /* stop timer 0 */
TMOD &= ~0x0F; /* clear timer 0 mode bits */
TMOD |= 0x01; /* put timer 0 into 16-bit no prescale */
TL0 = (TIMER0_COUNT & 0x00FF);
TH0 = (TIMER0_COUNT >> 8);
PT0 = 0; /* set low priority for timer 0 */
ET0 = 1; /* enable timer 0 interrupt */
TR0 = 1; /* start timer 0 */
EA = 1; /* enable interrupts */
}
/*------------------------------------------------------------------------------
unsigned timer0_count (void);
This function returns the current timer0 tick count.
------------------------------------------------------------------------------*/
unsigned timer0_count (void)
{
unsigned t;
EA = 0;
t = timer0_tick;
EA = 1;
return (t);
}
/*------------------------------------------------------------------------------
void timer0_delay (
unsigned count);
This function waits for 'count' timer ticks to pass.
------------------------------------------------------------------------------*/
void timer0_delay (
unsigned count)
{
unsigned start_count;
start_count = timer0_count (); /* get the starting count */
while ((timer0_count () - start_count) <= count) /* wait for count "ticks" */
{
}
}
void main (void)
{
timer0_initialize();
while (1)
  {
CMSR4 = !CMSR4;
//timer0_delay( 1 );
  }
}

thank you for any help you can provide me.

Parents Reply Children
  • ok, sorry.
    here is clearer example:

    #include <reg557.h>
    
    #define TIMER0_COUNT 0xDC11 /* 10000h - ((11,059,200 Hz / (12 * FREQ)) - 17) */
    static unsigned timer0_tick; /* timer tick variable */
    /*------------------------------------------------------------------------------
    static void timer0_isr (void);
    This function is an interrupt service routine for TIMER 0. It should never
    be called by a C or assembly function. It will be executed automatically
    when TIMER 0 overflows.
    ------------------------------------------------------------------------------*/
    static void timer0_isr (void) interrupt 1 using 1
    {
    /*------------------------------------------------
    Stop Timer 0, adjust the timer 0 counter so that
    we get another interrupt in 10ms, and restart the
    timer.
    ------------------------------------------------*/
    TR0 = 0; /* stop timer 0 */
    TL0 = TL0 + (TIMER0_COUNT & 0x00FF);
    TH0 = TH0 + (TIMER0_COUNT >> 8);
    TR0 = 1; /* start timer 0 */
    /*------------------------------------------------
    Increment the timer tick. This interrupt should
    occur approximately every 10ms. So, the resolution
    of the timer will be 100Hz not including interrupt
    latency.
    ------------------------------------------------*/
    timer0_tick++;
    }
    /*------------------------------------------------------------------------------
    void timer0_initialize (void);
    This function enables TIMER 0. TIMER 0 generates a synchronous interrupt
    once every 100Hz.
    ------------------------------------------------------------------------------*/
    void timer0_initialize (void)
    {
    EA = 0; /* disable interrupts */
    timer0_tick = 0;
    TR0 = 0; /* stop timer 0 */
    TMOD &= ~0x0F; /* clear timer 0 mode bits */
    TMOD |= 0x01; /* put timer 0 into 16-bit no prescale */
    TL0 = (TIMER0_COUNT & 0x00FF);
    TH0 = (TIMER0_COUNT >> 8);
    PT0 = 0; /* set low priority for timer 0 */
    ET0 = 1; /* enable timer 0 interrupt */
    TR0 = 1; /* start timer 0 */
    EA = 1; /* enable interrupts */
    }
    /*------------------------------------------------------------------------------
    unsigned timer0_count (void);
    This function returns the current timer0 tick count.
    ------------------------------------------------------------------------------*/
    unsigned timer0_count (void)
    {
    unsigned t;
    EA = 0;
    t = timer0_tick;
    EA = 1;
    return (t);
    }
    /*------------------------------------------------------------------------------
    void timer0_delay (
    unsigned count);
    This function waits for 'count' timer ticks to pass.
    ------------------------------------------------------------------------------*/
    void timer0_delay (
    unsigned count)
    {
    unsigned start_count;
    start_count = timer0_count (); /* get the starting count */
    while ((timer0_count () - start_count) <= count) /* wait for count "ticks" */
    {
    }
    }
    
    void delay()
    {
     int i;
      for (i=0;i<2000;i++);
    }
    
    void SendSerial(char cLetra)
    {
      S0BUF = cLetra;
      while(!TI);
      TI = 0;
      delay();
    }
    
    void InitSerial ()
    {
       S0CON  = 0x40;              // SCON: mode 1, 8-bit UART, enable rcvr
       TMOD  = 0x20;               // TMOD: timer 1, mode 2, 8-bit reload
       TH1   = 0xFD;               // TH1:  reload value for 1200 baud @ 16MHz  253
       TR1   = 1;                  // TR1:  timer 1 run
       TI    = 0;                  // TI:   set TI to send first char of UART
       PCON   = 0x00;              // Setar SMOD = 0
    
    }
    
    void main (void)
    {
    InitSerial();
    timer0_initialize();
    while (1)
      {
    	SendSerial( 0x30 + timer0_count() );
      }
    }
    

    It should send characters from 0 up to 9 to the screen, ascending. Then it would send weird characters. Instead, what it does is send only '0's. So I think it is because the interrupt is not working or there is something I'm doing wrong. When I debug, the timer0_tick increments as expected, then I think the code is fine.
    Thanks.

  • Looking at the variable in the debugger doesn't necessarily mean a thing. You'll have to look at what actually happens in function timer0_counter(). Step into it in the debugger and watch the register values. Look at the generated assembly code.

    Odds are your problem is caused by the lack of a "volatile" qualifier in the definition of the global variable timer0_tick. Also watch out for linker warnings as you compile the project.

  • Hi,first, thank you for your attention
    I've changed the main function to see what was happening with TF0:

    void main (void)
    {
    InitSerial();
    timer0_initialize();
    while (1)
      {
    	SendSerial( 0x30 | TF0 );
    	SendSerial( 0x30 + timer0_count() );
    	SendSerial( ' ' );
    	SendSerial( ' ' );
      }
    }
    the first two chars sent are "00", then it is only "10"s. So I figure it is not being cleared by the HW (it should when it got into the interrupt routine). I took a look at the .m51 file, and I think it shows the problem, but I don't know how to solve it. Here is the beginning of the file:
    BL51 BANKED LINKER/LOCATER V5.03                                                        12/03/2003  12:29:48  PAGE 1
    
    
    BL51 BANKED LINKER/LOCATER V5.03, INVOKED BY:
    C:\KEIL\C51\BIN\BL51.EXE Timer_main.obj TO Timer RAMSIZE (256)
    
    
    MEMORY MODEL: SMALL
    
    
    INPUT MODULES INCLUDED:
      Timer_main.obj (TIMER_MAIN)
      C:\KEIL\C51\LIB\C51S.LIB (?C_STARTUP)
    
    
    LINK MAP OF MODULE:  Timer (TIMER_MAIN)
    
    
                TYPE    BASE      LENGTH    RELOCATION   SEGMENT NAME
                -----------------------------------------------------
    
                * * * * * * *   D A T A   M E M O R Y   * * * * * * *
                REG     0000H     0008H     ABSOLUTE     "REG BANK 0"
                DATA    0008H     0002H     UNIT         ?DT?TIMER_MAIN
                IDATA   000AH     0001H     UNIT         ?STACK
    
                * * * * * * *   C O D E   M E M O R Y   * * * * * * *
                CODE    0000H     0003H     ABSOLUTE
                        0003H     0008H                  *** GAP ***
                CODE    000BH     0003H     ABSOLUTE
                        000EH     07F2H                  *** GAP ***
                CODE    0800H     0026H     UNIT         ?PR?MAIN?TIMER_MAIN
                CODE    0826H     0021H     UNIT         ?PR?TIMER0_ISR?TIMER_MAIN
                CODE    0847H     001EH     UNIT         ?PR?TIMER0_INITIALIZE?TIMER_MAIN
                CODE    0865H     001DH     UNIT         ?PR?_TIMER0_DELAY?TIMER_MAIN
                CODE    0882H     0011H     UNIT         ?PR?INITSERIAL?TIMER_MAIN
                CODE    0893H     000FH     UNIT         ?PR?DELAY?TIMER_MAIN
                CODE    08A2H     000CH     UNIT         ?C_C51STARTUP
                CODE    08AEH     000AH     UNIT         ?PR?_SENDSERIAL?TIMER_MAIN
                CODE    08B8H     0009H     UNIT         ?PR?TIMER0_COUNT?TIMER_MAIN
    
    
    
    OVERLAY MAP OF MODULE:   Timer (TIMER_MAIN)
    
    
    Looking at the CODE MEMORY part, I saw that ?PR?TIMER0_ISR?TIMER_MAIN is at 0826H. Shouldn't it be at 0003H? Do you know how to solve it?
    Thank you.

  • The position of the timer handler routine is not your problem --- the actual handler is not supposed to be positioned at 0x000b (not 0x0003) in code memory. Only a jmp to the handler has to be there, and apparently it is:

                * * * * * * *   C O D E   M E M O R Y   * * * * * * *
                CODE    0000H     0003H     ABSOLUTE
                        0003H     0008H                  *** GAP ***
                CODE    000BH     0003H     ABSOLUTE
    

    Anyway: the problem doesn't appear to be in the interrupt handler, since you said that the timer0_counter variable is being incremented as designed.

    The problem is somewhere between the global counter variable and the function supposed to get it, timer0_count(). Did you try my suggestion about making that volatile?

  • The position of the timer handler routine is not your problem --- the actual handler is not supposed to be positioned at 0x000b (not 0x0003) in code memory. Only a jmp to the handler has to be there, and apparently it is
    That is right!
    since you said that the timer0_counter variable is being incremented as designed
    Hans, it is NOT being incremented, it is only when in debug mode.
    Did you try my suggestion about making that volatile?
    How do I do that? I took the static keyword off. Still doesn't work. But notice that TF0 is not being cleared, what means that the ISR is not being called.
    I looked at the hex file, and it seemed alright, so I asked people from Philips.
    Here is the first lines of the hex:

    :03000B00020826C2
    :10082600C0E0C0D0C28C7411258AF58A74DC258C90
    :10083600F58CD28C0509E50970020508D0D0D0E008
    :01084600327F
    
    the 1st places a LJMP to 0826 at 000B
    the 2nd and 3rd put the routine starting at 0826
    the 4th is a RETI
    That is, I think, exactly what it should be, so I can't figure out where the problem is.
    Thank you.

  • "Did you try my suggestion about making that volatile?
    How do I do that?"

    Use the volatile keyword. Look it up in your C book.

    Stefan

  • Hans, it is NOT being incremented, it is only when in debug mode.

    But in that same message, you said that in debug, you saw the variable move, but not the result returned by timer0_count(). That's the disparity I'm trying to resolve by that "volatile".

    And instead of looking at HEX output, you really should look at the assembly in your listing file (if you had uVision make one), or in the debugger.