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

A problem with serial IO in the 'Traffic' example:

I would like to point out a problem in the Traffic example program for the C166 toolset. The program contains SERIAL.C file which implements interrupt-driven serial IO for the on-chip UART of the C16x microcontroller family. The implementation is very good and I used it with minor modifications in some projects. It is likely that others used it too. That's why I want to point out a problem with this implementation.
I'll try to describe the problem in detail, so please excuse me for the long posting.
Occasionally the SERIAL.C module sends characters to the serial line in wrong order, i.e. it swaps two adjacent characters. The problem showed in a program that used serial IO heavily. To see where the problem comes from, let's look at the source code:

/******************************************************************************/
/*       putbuf:  write a character to SBUF or transmission buffer            */
/******************************************************************************/
void putbuf (char c)  {
  if (!sendfull)  {                   /* transmit only if buffer not full     */
!!! if (!sendactive && !sendstop)  {  /* if transmitter not active:           */
      sendactive = 1;                 /* transfer the first character direct  */
      S0TBUF = c;                     /* to S0TBUF to start transmission      */
    }
    else  {                           /* otherwise:                           */
!!!   S0TIE = 0;                      /* disable transmit interrupt           */
      _nop_ ();                       /* avoid pipeline effects               */
      _nop_ ();
      outbuf[oend++ & (OLEN-1)] = c;  /* transfer char to transmission buffer */
      if (((oend ^ ostart) & (OLEN-1)) == 0)  sendfull = 1;
      S0TIE = 1;                      /* enable transmit interrupt            */
    }                                 /* set flag if buffer is full           */
  }
}

/* ... */

/******************************************************************************/
/*       serial_transmit:  serial transmitter interrupt                       */
/******************************************************************************/
void serial_transmit (void) interrupt SERIAL_TRANSMIT0 = 0x2A using S_RBANK  {
  if (ostart != oend)  {           /* if characters in buffer and           */
    if (!sendstop)  {              /* if not Control+S received             */
      S0TBUF = outbuf[ostart++ & (OLEN-1)];    /* transmit character        */
      sendfull = 0;                /* clear 'sendfull' flag                 */
                                   /* if task waiting: signal ready         */
      if (otask != -1) isr_send_signal (otask);
    }
  }
  else sendactive = 0;             /* if all transmitted clear 'sendactive' */
}
Consider the unlikely case of serial transmit interrupt occuring between the two lines marked with 3 exclamation marks !!!. In this case the ISR clears the sendactive flag. The byte to be sent (argument to the putbuf function) is put in the output buffer (outbuf) intead of being sent straight away. The serial transmitter will be idle until the next call to putbuf. Next time putbuf is called the next byte to be sent will be transmitted first, followed by the first byte out of the buffer. The two bytes will have been sent in reversed order.
It is easy to prevent the problem: disabling the serial transmit interrupt will be enough.
Once again, I consider the Traffic program to be a very good example of interrupt-driven serial IO implementation. Since a lot of people might be using it in real programs, it would be nice if Keil corrected SERIAL.C in a future release of its toolset.

- mike