AnsweredAssumed Answered

Synchronising timer1?

Question asked by ThorMJ on Jul 23, 2013
Latest reply on Aug 22, 2013 by Dirk

I'm using timer1 to interrupt me when a modbus RTU packet is complete (3.5 chars of silence)...

The problem is that it doesn't seem to synchronise with a T1CLRI write; with the code below and an oscope attached to P0.4 and P1.2, I clearly see the characters coming in (edges of P0.4 --yellow trace), but the P1.2 (blue trace) seems to have a "spurious pulses" in the middle of the receive operation (P1.2 goes high despite no silence -- the only thing that sets P1.2 high is the Timer1 ISR).  The P1.2 wave appears to be the right width if you get more than 1 pulse, but I was expecting the line marked //RESET to reset the timer every time I see something in the serial port....


void sportsetup    (int Baud)


    int div;


    IRQEN &= ~BIT(UART_INT);            // Lock out interrupts

    COMIEN0 = 0;                        // during (re)configuration...


    // Initialize the UART for 9600-8-N

    GP1CON |= BIT0 + BIT4;  // Select UART functionality for P1.0/P1.1 (sin/sout)

    COMCON0 = BIT7;            // Enable access to COMDIV registers

/* Hardcoded Examples:

    COMDIV0 = 0x21;        //9600 Baud


    COMDIV0 = 0x02;            // 115,200

    COMDIV1 = 0x00;            // No High Byte.

    COMDIV2 = BIT(15) |        //FracDiv

                1<<11 |



    //Main divider

    div = (CLOCKSPEED / 16 / 2) / Baud;

    COMDIV1 = div >> 8;

    COMDIV0 = div & 0xFF;


    //Fractional divider

    div = ((CLOCKSPEED / 16 / 2) / div * 2048) / Baud - 2048;

    COMDIV2 = BIT(15)                        //Enable Fracdiv

                        | 1 << 11            //M hardcoded to 1

                        | (div & 0xFFFF);    //Fractional divisor


    //ToDo BugzID:203 - This (10*7/2) should work, but doesn't (20*7/2 does though)... don't know if the PC ain't fast enough or what...

    char35 = CLOCKSPEED / Baud * 10 * 7 / 2;


    COMCON0 = BIT0 + BIT1;    //Drop DLAB, go to 8N1 mode

    COMCON1 = 0x03;            // Release the line


    //Init the fifo pointers




    //Start up the ISR:

    IntHndlrTable[UART_INT] = sportirq;    // Put the address in to the VIC table

    IRQEN |= BIT(UART_INT);                // Enable the VIC for the UART

    COMIEN0 = BIT0;                        // IRQ on RXd -- We'll enable the tx interrupt as part of the TX motion



    //Set up TIMER1 to handle the serial state transitions

    IntHndlrTable[T1_INT] = sporttimerirq;

    T1LD  = char35;            // Set the reload value based on baud rate

    T1CON = BIT9             // Core Clock

            | BIT6               //Periodic, not free-running so I can synchronize

            | BIT7            // Enabled





//This ISR is used to detect silence so we can deal with half duplex and can turn the line around properly

void sporttimerirq(void)


    if((comstatus == IDLE || comstatus == RXING)    //We're done

        && rxhead!=rxtail)                            //And we have chars rxfifo!

        comstatus = READY;                            //So, say we're "ready" instead of idle.


    /* The TX ISR routines also call for this to be fired at the end:

    *    1. The TX sets the comstatus so something else and I need to set it back if I had fifo

    *    2. TX gets called while there is still stuff going out; releasing the line then corrupts data.

    * So, we release it here.


    COMCON1 = 3;


    GP1DAT |= BIT2<<16;//DBG     --Debug- Make P1.2 go high indicating idle


    IRQCLR = BIT(T1_INT);                            //Turn ISR off until called for again.




void sportirq(void)


    char status;


    //Read the Interrupt ID register to clear it...

    status = COMIID0;


    // Read the the status register to figure out what to do:

    status = COMSTA0;

    GP0DAT ^= (BIT4<<16);//DBG --Mark chars as they come in or out

    T1CLRI = status;        //Reload the silence timer //RESET


    GP1DAT &= ~(BIT2<<16);//DBG     --Keep P1.2 low indicating activity


    if(status & 0x01)    //We have data incoming!


        comstatus = RXING;   

        if(rxhead == rxtail-1 || (rxhead == 0 && rxtail == RXFIFO)) //We're full!


            comstatus = RXFIFOFULL;





            rfifo[rxhead++] = COMRX;

            if (rxhead == RXFIFO)

                rxhead =0;






    if(status & BIT1)







    //Half duplex -- if someone is talking, don't talk over them.  This is not part of the above

    // -- I have to wait for the 3.5 char silence to expire before I start talking.

    if (comstatus == RXING)


        IRQEN = BIT(T1_INT);    //Turn on the silence timer if it was off before...

        return;                    //Skip the TX portion until the silence timer sez we're ok.




    // Gotta have this or we obliterate the 1st byte.  No idea why (I don't think I should've ISR'd).

    if((COMSTA0 & 0x20) == 0x00)



    //Transmit if we're ready.

    if (txhead != txtail) {

        COMCON1 = 0;            //Turn on RTS to take control of the RS485

        IRQCLR = BIT(T1_INT);    //Turn off the silence timer until end of packet.



        COMTX = wfifo[txtail++];

        if(TXFIFO == txtail)

            txtail = 0;

    } else {                    //We're Done.  I have no more to put into empty TX register


        IRQEN = BIT(T1_INT);    // And turn it on (we're going to keep control of RS485 for 3.5 chars).

        COMIEN0 &= ~BIT1;        //Turn off THRE isr -- otherwise we keep triggering the IRQ cuz I dinna fill it.

                                //DON'T turn of using IRQEN -- we still need our RX irqs!

        GP1DAT &= ~(BIT2<<16);//DBG