UBW USART Tx/Rx Interrupt code for review/inclusion

USB PICs and the UBW

Moderator: phalanx

UBW USART Tx/Rx Interrupt code for review/inclusion

Postby pantoine » Sat Jul 07, 2007 10:09 pm

Brian et al,

I've written some interrupt-driven routines for my UBW-based design. I've not built out the proposed "CX" command for setting it up, but thought the core code would nonetheless be useful for you.

First some buffers:
Code: Select all
#pragma udata access fast_vars
// PIC USART Global Variables
// In and out pointers to PIC USART input buffer
near unsigned char g_USART_RX_buf_in;
near unsigned char g_USART_RX_buf_out;

// In and out pointers to PIC USART output buffer
near unsigned char g_USART_TX_buf_in;
near unsigned char g_USART_TX_buf_out;

#pragma udata usart_buf=0x280
// PIC hardware USART Rx buffer
unsigned char g_USART_RX_buf[kUSART_RX_BUF_SIZE];

// PIC hardware USART Tx buffer
unsigned char g_USART_TX_buf[kUSART_TX_BUF_SIZE];

Now some setup code:
Code: Select all
/*********************************************************************
 * Function:        void init_usart(unsigned char usart_conf
 *                                  unsigned char usart_baud)
 * PreCondition:    I/O pins configured
 * Input:           None
 * Output:          None
 * Side Effects:    Configures Rx & Tx IRQs, zero's buffer pointers
 * Overview:        Initialise the PIC's onboard hw USART
 *********************************************************************/
void init_usart(unsigned int usart_baud)
{
  // configure USART - USART will be stderr!
  TXSTA = 0;           // Reset USART registers to POR state
  RCSTA = 0;
  RCSTAbits.CREN = 1;
  TXSTAbits.BRGH = 1;
  SPBRG = usart_baud;       // Write baudrate to SPBRG1
  SPBRGH = usart_baud >> 8; // For 16-bit baud rate generation
  TXSTAbits.TXEN = 1;  // Enable transmitter
  RCSTAbits.SPEN = 1;  // Enable receiver

  // And the USART TX and RX buffer management
  g_USART_RX_buf_in = 0;
  g_USART_RX_buf_out = 0;
  g_USART_TX_buf_in = 0;
  g_USART_TX_buf_out = 0;

  // USART interrupts
  IPR1bits.RCIP = 0;   // USART Rx on low priority interrupt
  PIE1bits.RCIE = 1;   // Enable Rx interrupts
  IPR1bits.TXIP = 0;   // USART Tx on low priority interrupt
  PIE1bits.TXIE = 0;   // Disable Tx interrupts until we need to send

  return;
} /* init_usart */

The interrupt routines included in the low_ISR routine:
Code: Select all
  // PIC hardware USART Rx interrupt?
  if (PIR1bits.RCIF)
  {
    // Reading Rx register clears interrupt
    usartchar = RCREG;
    // TODO: Do we need to do more for framing errors?
    if (RCSTAbits.FERR)
      printf((rom char *)"USART:Rx Framing Error, ");
    else if (RCSTAbits.OERR)
    {
      printf((rom char *)"USART:Rx Overrun error");
      RCSTAbits.CREN = 0;  // Clearing CREN clears any Overrun (OERR) errors
      RCSTAbits.CREN = 1;  // Re-enable continuous USART receive
    }
    else // We have a valid byte :-)
    {
      g_USART_RX_buf[g_USART_RX_buf_in++] = usartchar;
      // Check for wrap around
      g_USART_RX_buf_in &= (kUSART_RX_BUF_SIZE - 1);
      //if (g_USART_RX_buf_in == kUSART_RX_BUF_SIZE)
      //   g_USART_RX_buf_in = 0;
      // Check for buffer overrun
      if (g_USART_RX_buf_in == g_USART_RX_buf_out)
         printf((rom char *)"USART:RX buffer overrun!\n");
    }
  }

  // PIC hardware USART Tx interrupt?
  // NB: TXIF is almost always true... so need to look at TXIE
  //       to see if the Tx interrupt should be taken and then
  //       only take it if the Tx buffer is empty
  if ((PIE1bits.TXIE) && (TXSTAbits.TRMT))
  {
    // Do we have something to transmit?
    if (g_USART_TX_buf_in != g_USART_TX_buf_out)
    {
      TXREG = g_USART_TX_buf[g_USART_TX_buf_out++];
      // Do we need to wrap around to the start of the buffer?
      g_USART_TX_buf_out &= (kUSART_TX_BUF_SIZE - 1);
      //if (g_USART_TX_buf_out == kUSART_TX_BUF_SIZE)
      //   g_USART_TX_buf_out = 0;
    }
    else
    {
      // Disable Tx interrupts until we have something to send
      // NB: re-enable interrupts in buffer-fill routine to
      // restart Tx!
      PIE1bits.TXIE = 0;
    }
  }

And finally a replacement for the standard _usart_putc routine:
Code: Select all
/*********************************************************************
 * Function:        void _usart_putc(char c)
 * PreCondition:    USART buffers initialised
 * Input:           Char to write
 * Output:          None
 * Side Effects:    Adds char to Tx buffer for USART
 * Overview:        Writes a char to the USART circular Tx buffer
 * Note:            Replacement for the standard stderr putc routine,
 *                  Enables fprintf() and all related functions to
 *                  print to *our* buffered, interrupt-driven USART
 
*********************************************************************/
int _usart_putc(char c)
{
  // Start of critical region - disable Tx interrupts
  PIE1bits.TXIE = 0;

  // Copy the character into the output buffer
  g_USART_TX_buf[g_USART_TX_buf_in++] = c;

  // Check for buffer wrap around
  g_USART_TX_buf_in &= (kUSART_TX_BUF_SIZE - 1);
  //  if (g_USART_TX_buf_in == kUSART_TX_BUF_SIZE)
  //    g_USART_TX_buf_in = 0;

  // End of critical region - re-enable Tx interrupts 
  PIE1bits.TXIE = 1;

  //  if (g_USART_TX_buf_in == g_USART_TX_buf_out)
  //    printf((rom char *)"USART: TX buffer overrun\n");

  return (c);
} /* _usart_putc */


Let me know if this is of any use, or if you need any clarification.

Regards,
P.
pantoine
 
Posts: 122
Joined: Fri Dec 29, 2006 9:23 pm
Location: Perth, Western Australia

Postby pantoine » Tue Jul 10, 2007 4:59 pm

Folks: note that the code above includes some "printf"s triggered by errors in reception... these really should be removed and replaced with flag-setting which can be examined/dealt with in the mainline code.

Regards,
P.
(Thanks to user "polly" for pointing this out!)
pantoine
 
Posts: 122
Joined: Fri Dec 29, 2006 9:23 pm
Location: Perth, Western Australia

Re: UBW USART Tx/Rx Interrupt code for review/inclusion

Postby icserny » Sat Oct 09, 2010 12:44 pm

Thank you for providing the code. I have only one comment:
Code: Select all
void init_usart(unsigned int usart_baud)
{
  // configure USART - USART will be stderr!
  TXSTA = 0;           // Reset USART registers to POR state
  RCSTA = 0;
  RCSTAbits.CREN = 1;
  TXSTAbits.BRGH = 1;
  SPBRG = usart_baud;       // Write baudrate to SPBRG1
  SPBRGH = usart_baud >> 8; // For 16-bit baud rate generation
  SPBRG = usart_baud;       // Write baudrate to SPBRG1
  SPBRGH = usart_baud >> 8; // For 16-bit baud rate generation
~~~~~~~~~~~~~~~~~~

What is this for if you don't set the BRG16 bit in the BAUDCON register? I would like to add these lines:
Code: Select all
  BAUDCON = 0;
  BAUDCONbits.BRG16 = 1;
icserny
 
Posts: 2
Joined: Sat Oct 09, 2010 12:21 pm


Return to USB Development

Who is online

Users browsing this forum: No registered users and 2 guests