We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
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.
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 */ }