/* File name: UART2support.c

   Buffered interrupt support for DSP Global UART board 
   on the TI C5510 DSK.
   
   UART channel 2 only.

    28Mar2004 .. initial version .. KM
    29Mar2004 .. UART 2 int sup evolved from test code .. KM
    
*/

#define FOREVER 1

#define UART 0x500200
#define RBR (UART+0x00)
#define THR (UART+0x00)
#define DLL (UART+0x00)
#define DLM (UART+0x02)
#define IER (UART+0x02)
#define ISR (UART+0x04)
#define FCR (UART+0x04)
#define LCR (UART+0x06)
#define MCR (UART+0x08)
#define LSR (UART+0x0A)
#define MSR (UART+0x0C)
#define SPR (UART+0x0E)


#define IER0 ((unsigned long)0x00)
#define IFR0 ((unsigned long)0x01)
#define IVPD ((unsigned long)0x49)
#define IVPH ((unsigned long)0x4A)

#define INT0 0x0008
#define INT0_BIT 0x0004

interrupt void UART2int(void);
void resetv();

volatile int *U2RxAdr, U2RxSize, U2RxAOff, U2RxIOff, U2RxCount;
volatile int *U2TxAdr, U2TxSize, U2TxAOff, U2TxIOff, U2TxCount, U2TxStopped;

//----------------------------------------------------------------


/* Function to set up the UART channel buffered Rx and Tx support.

   Call prior to globally enabling the interrupt system.
   
   The arguments are:
   
   *intbuf    A pointer to the receive (Rx) buffer.
   nin        The number of ints in the Rx buffer.
   *outbuf    A pointer to the transmit (Tx) buffer.
   nout       The number of ints in the Tx buffer.
   RateDiv    The rate divisor value baud rate is
              230,400/RateDiv.  For 38400 baud use a
              value of 6.
*/

void UART2setup(int *inbuf, int nin, int *outbuf, int nout, int RateDiv)
{
    unsigned long resetloc;
    
    // set up buffering support
    
    U2RxAdr = inbuf;    // address of Rx buffer
    U2RxSize = nin;     // size of Rx buffer
    U2RxAOff = 0;       // application level Rx address offset
    U2RxIOff = 0;       // interrupt level Rx address offset
    U2RxCount = 0;      // count of characters in Rx buffer
    U2TxAdr = outbuf;   // address of Tx buffer
    U2TxSize = nout;    // size of Tx buffer
    U2TxAOff = 0;       // application level TX address offset
    U2TxIOff = 0;       // interrupt level Tx address offset
    U2TxCount = 0;      // count of characters in Tx buffer
    U2TxStopped = 1;    // Tx waiting for a character to be sent
    
    // set up interrupt vector and interrupt registers
    
    resetloc = (long)resetv;
    far_poke(IVPD, (unsigned)(resetloc>>8));
    far_poke(IVPH, (unsigned)(resetloc>>8));
    far_poke((resetloc>>1)+INT0, (unsigned)((unsigned long)UART2int>>16));
    far_poke((resetloc>>1)+INT0+1, (unsigned)((unsigned long)UART2int));
    far_poke(IER0, far_peek(IER0)|INT0_BIT);
    far_poke(IFR0, INT0_BIT);
    
    // configure the UART channel 2
    
    far_poke(LCR, 0x80); // access baud rate registers
    far_poke(DLM, RateDiv>>8); // set baud rate divisor high byte
    far_poke(DLL, RateDiv);    // set baud rate divison low byte
    far_poke(LCR, 0x07); // use 8 data and 2 stop bits
    
    far_poke(FCR, 0x00); // insure FIFOs are off
    far_poke(LSR, 0x60); // initialize line status register
    far_poke(IER, 0x03); // have UART generate Rx and Tx interrupts
    far_poke(MCR, 0x08); // make UART int req outputs active
    far_peek(RBR);       // clear receiver buffer
    
    return;
}

// Function to fetch characters from the Rx buffer

int U2RxGet(void)
{
    int itemp;
    
    while (U2RxCount == 0);    // wait if no characters present
   
    itemp = *(U2RxAdr+U2RxAOff);              // fetch character
    if (++U2RxAOff >= U2RxSize) U2RxAOff = 0; // adv pointer cyclicly
    
    _disable_interrupts();     // enter a critical section
    U2RxCount--;               // reduce the number present
    _enable_interrupts();      // exit the critical section

    return (itemp);            // return the fetched character
}

// Function to put characters into the Tx buffer

void U2TxPut(int value)
{
    while (U2TxCount == U2TxSize);  // wait if no room in the buffer
    
    _disable_interrupts();          // enter a critical section
    
    if (U2TxStopped != 0) {                  // if Tx not running
        far_poke(THR, value);                // load character directly
        far_poke(IER, far_peek(IER)|0x0002); // reenable interrupt
        U2TxStopped = 0;                     // and note that is expected
    }
    else {                                   // if Tx is running
        *(U2TxAdr+U2TxAOff) = value;         // put character into buffer
        if (++U2TxAOff >= U2TxSize) U2TxAOff = 0; // adv pointer cyclicly
        U2TxCount++;                              // and increase the count
    }
    
    _enable_interrupts();          // exit the critical section
    
    return;
}
    
//-----------------------------------------------------------------

// Interrupt handler for UART channel 2

int volatile U2Flag;

interrupt void UART2int(void)
{
	U2Flag = far_peek(ISR);          // get the interrupt status value
	if ((U2Flag&0x0C) != 0) {        // true if Rx interrupt
       if (U2RxCount < U2RxSize) {   // ignore if no room
           *(U2RxAdr+U2RxIOff) = far_peek(RBR); // put character in Rx buffer
           if (++U2RxIOff >= U2RxSize) U2RxIOff = 0; // adv pointer cyclicly
           U2RxCount++;                              // count the character
       }
       else {                        // if no room in the Rx buffer we
           far_peek(RBR);            // fetch the character and discard it
       }
   } 
   else if ((U2Flag&0x02)!=0) {     // true if Tx interrupt
       if (U2TxCount == 0) {        // true if no characters in Tx buffer
           U2TxStopped = 1;         // so note that no future interrupt
           far_poke(IER, far_peek(IER)&0xFFFD); // and disable Tx interrupt requests
       }
       else {                       // otherwise have a character to send
           far_poke(THR, *(U2TxAdr+U2TxIOff));       // so put into the Tx buffer
           if (++U2TxIOff >= U2TxSize) U2TxIOff = 0; // adv pointer cyclicly
           U2TxCount--;                              // reduce count present
       }
   }
   else { 
        while(1);  // should never get here..but if we do, wait for help
   }   
   return;
}
