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

MCB2300 only receiving last byte in UART1 FIFO

Hi, I'm having some issues with reading in a serial stream on UART1. For some reason, I'm only able to receive the last byte of my message.

Some code snippets:

/*----------------------------------------------------------------------------
  Defines for ring buffers
 *---------------------------------------------------------------------------*/
#define SER_BUF_SIZE               (128)               // serial buffer in bytes (power 2)
#define SER_BUF_MASK               (SER_BUF_SIZE-1ul)  // buffer size mask

/* Buffer read / write macros */
#define SER_BUF_RESET(serBuf)      (serBuf.rdIdx = serBuf.wrIdx = 0)
#define SER_BUF_WR(serBuf, dataIn) (serBuf.data[SER_BUF_MASK & serBuf.wrIdx++] = (dataIn))
#define SER_BUF_RD(serBuf)         (serBuf.data[SER_BUF_MASK & serBuf.rdIdx++])
#define SER_BUF_EMPTY(serBuf)      (serBuf.rdIdx == serBuf.wrIdx)
#define SER_BUF_FULL(serBuf)       (serBuf.rdIdx == serBuf.wrIdx+1)
#define SER_BUF_COUNT(serBuf)      (SER_BUF_MASK & (serBuf.wrIdx - serBuf.rdIdx))

// buffer type
typedef struct __SER_BUF_T {
  unsigned char data[SER_BUF_SIZE];
  unsigned int wrIdx;
  unsigned int rdIdx;
} SER_BUF_T;

void ser_InitPort (unsigned long baudrate, unsigned int  databits,
                  unsigned int  parity,   unsigned int  stopbits) {

  unsigned char lcr_p, lcr_s, lcr_d;
  unsigned long dll;

  switch (databits) {
    case 5:                                            // 5 Data bits
      lcr_d = 0x00;
    break;
    case 6:                                            // 6 Data bits
      lcr_d = 0x01;
    break;
    case 7:                                            // 7 Data bits
      lcr_d = 0x02;
    break;
    case 8:                                            // 8 Data bits
    default:
      lcr_d = 0x03;
    break;
  }

  switch (stopbits) {
    case 1:                                            // 1,5 Stop bits
    case 2:                                            // 2   Stop bits
      lcr_s = 0x04;
    break;
    case 0:                                            // 1   Stop bit
    default:
      lcr_s = 0x00;
    break;
  }

  switch (parity) {
    case 1:                                            // Parity Odd
      lcr_p = 0x08;
    break;
    case 2:                                            // Parity Even
      lcr_p = 0x18;
    break;
    case 3:                                            // Parity Mark
      lcr_p = 0x28;
    break;
    case 4:                                            // Parity Space
      lcr_p = 0x38;
    break;
    case 0:                                            // Parity None
    default:
      lcr_p = 0x00;
    break;
  }

  SER_BUF_RESET(ser_out);                              // reset out buffer
  SER_BUF_RESET(ser_in);                               // reset in buffer

  /* Note that the pclk is 12.0 MHz.      */
  dll = ((UART_CLK / baudrate) / 16UL);

  U1FDR = 0;                                           // Fractional divider not used
  U1LCR = 0x80 | lcr_d | lcr_p | lcr_s;                // Data bits, Parity,   Stop bit
  U1DLL = dll;                                         // Baud Rate @ 12 MHZ PCLK
  U1DLM = 0;                                           // High divisor latch
  U1LCR = 0x00 | lcr_d | lcr_p | lcr_s;                // DLAB = 0
  U1IER = 0x03;                                        // Enable TX/RX interrupts
  U1FCR = 0x07;                                        // FIFO enabled, reset Tx and Rx


  ser_txRestart = 1;                                   // TX fifo is empty

  /* Set up and enable the UART interrupt in the VIC */
  VICVectAddr7 = (unsigned long)ser_irq;             // Set interrupt function
  VICVectCntl7 = 0x0F;                                 // Set interrupt priority
  VICIntEnable = (1 << 7);                             // Enable interrupt

}

/*----------------------------------------------------------------------------
  serial port 1 interrupt
 *---------------------------------------------------------------------------*/
static __irq void ser_irq (void) {
  volatile unsigned long iir;

  iir = U1IIR;

  if ((iir & 0x4) || (iir & 0xC)) {                    // RDA or CTI pending
    while (U1LSR & 0x01) {                             // Rx FIFO is not empty
      SER_BUF_WR(ser_in, U1RBR);                       // Read Rx FIFO to buffer
    }
  }

  ser_lineState = ((U1MSR << 8) | U1LSR) & 0xE01E;     // update linestate

  VICVectAddr = 0;                                     // acknowledge interrupt
}

I can receive a single byte fine but when I send multiple bytes, the FIFO only contains the last byte of the message. The LSR RDR bit is only valid for one iteration and the RBR is only read once no matter how many bytes I send.

Thanks in advance.

  • I am not so sure about the 'static' before '__irq'.

    static __irq void ser_irq (void) {
    

    The below code looks strange to me (not only the 'while'), and the hardware FIFO is not controlled by programmer.

      if ((iir & 0x4) || (iir & 0xC)) {                    // RDA or CTI pending
        while (U1LSR & 0x01) {                             // Rx FIFO is not empty
          SER_BUF_WR(ser_in, U1RBR);                       // Read Rx FIFO to buffer
        }
      }
    

    I have not seen how do you use the below code.

    #define SER_BUF_RD(serBuf)         (serBuf.data[SER_BUF_MASK & serBuf.rdIdx++])
    #define SER_BUF_EMPTY(serBuf)      (serBuf.rdIdx == serBuf.wrIdx)
    #define SER_BUF_FULL(serBuf)       (serBuf.rdIdx == serBuf.wrIdx+1)
    

  • Copy from NXP code bundle

    #define IER_RBR         0x01
    #define IER_THRE        0x02
    #define IER_RLS         0x04
    
    #define IIR_PEND        0x01
    #define IIR_RLS         0x03
    #define IIR_RDA         0x02
    #define IIR_CTI         0x06
    #define IIR_THRE        0x01
    
    #define LSR_RDR         0x01
    #define LSR_OE          0x02
    #define LSR_PE          0x04
    #define LSR_FE          0x08
    #define LSR_BI          0x10
    #define LSR_THRE        0x20
    #define LSR_TEMT        0x40
    #define LSR_RXFE        0x80
    
    void UART1Handler (void) __irq
    {
      BYTE IIRValue, LSRValue;
      BYTE Dummy = Dummy;
    
      IENABLE;                              /* handles nested interrupt */
      IIRValue = U1IIR;
    
      IIRValue >>= 1;                 /* skip pending bit in IIR */
      IIRValue &= 0x07;                 /* check bit 1~3, interrupt identification */
      if ( IIRValue == IIR_RLS )            /* Receive Line Status */
      {
            LSRValue = U1LSR;
            /* Receive Line Status */
            if ( LSRValue & (LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI) )
            {
              /* There are errors or break interrupt */
              /* Read LSR will clear the interrupt */
              UART1Status = LSRValue;
              Dummy = U1RBR;                /* Dummy read on RX to clear
                                                            interrupt, then bail out */
              IDISABLE;
              VICVectAddr = 0;              /* Acknowledge Interrupt */
              return;
            }
            if ( LSRValue & LSR_RDR )   /* Receive Data Ready */
            {
              /* If no error on RLS, normal ready, save into the data buffer. */
              /* Note: read RBR will clear the interrupt */
              UART1Buffer[UART1Count] = U1RBR;
              UART1Count++;
              if ( UART1Count == BUFSIZE )
              {
                    UART1Count = 0;         /* buffer overflow */
              }
            }
      }
      else if ( IIRValue == IIR_RDA )       /* Receive Data Available */
      {
            /* Receive Data Available */
            UART1Buffer[UART1Count] = U1RBR;
            UART1Count++;
            if ( UART1Count == BUFSIZE )
            {
              UART1Count = 0;               /* buffer overflow */
            }
      }
      else if ( IIRValue == IIR_CTI )       /* Character timeout indicator */
      {
            /* Character Time-out indicator */
            UART1Status |= 0x100;           /* Bit 9 as the CTI error */
      }
      else if ( IIRValue == IIR_THRE )      /* THRE, transmit holding register empty */
      {
            /* THRE interrupt */
            LSRValue = U1LSR;               /* Check status in the LSR to see if
                                                                    valid data in U0THR or not */
            if ( LSRValue & LSR_THRE )
            {
              UART1TxEmpty = 1;
            }
            else
            {
              UART1TxEmpty = 0;
            }
      }
    
      IDISABLE;
      VICVectAddr = 0;              /* Acknowledge Interrupt */
    }
    

  • My understanding was that all the data is in the FIFO. The while loop checks if the FIFO still contains data, when I read the U1RBR register I place the byte into my buffer and repeat until the FIFO is empty.

    int ser_Read (char *buffer, const int *length) {
      int bytesToRead, bytesRead;
    
      /* Read *length bytes, block if *bytes are not avaialable     */
      bytesToRead = *length;
      bytesToRead = (bytesToRead < (*length)) ? bytesToRead : (*length);
      bytesRead = bytesToRead;
    
      while (bytesToRead--) {
        while (SER_BUF_EMPTY(ser_in));                     // Block until data is available if none
        *buffer++ = SER_BUF_RD(ser_in);
      }
      return (bytesRead);
    }
    

  • The below code is very strange, maybe you can explain it for me?

      bytesToRead = *length;
      bytesToRead = (bytesToRead < (*length)) ? bytesToRead : (*length);
      bytesRead = bytesToRead;
    

    And how do you get the conclusion that
    "when I send multiple bytes, the FIFO only contains the last byte of the message."

  • /*----------------------------------------------------------------------------
      serial port 1 interrupt
     *---------------------------------------------------------------------------*/
    __irq void ser_irq (void) {
      volatile unsigned long iir;
    
      iir = U1IIR;
    
      if (iir & 0x4) {                    // RDA
        if (U1LSR & 0x01) {
          SER_BUF_WR(ser_in, U1RBR);
        }
      }
    
      VICVectAddr = 0;                                     // acknowledge interrupt
    }
    

    I would suggest that,
    1. Use the above code as your serial port 1 ISR.
    2. Send 8 bytes to you MCB2300 device serial port 1.
    3. Check the content of your "ser_in" ring buffer.
    4. Tell me what is the content of your "ser_in" ring buffer, and how do you check/know that.