Sener
Sener

Reputation: 335

How to use UART receive data for further processing rather than just echoing in embedded C?

Here is the code from my test environment. it simply replies back (echo) the entered data to the terminal application where it is connected through a Serial Port. So far so good.

Now, I need to use that data and process as per the requirements/protocol. But, I am struggling to consume the data UART0Buffer as I expected. (The variable UART0Buffer is populated in the UART Interrupt)

I send e.g. "7E0007AA010203040506CC" from the terminal and the code replies back this to the terminal application in an order in four steps for some reason;

1 by Process #1

37

2 by Process #2

00

3 by Process #1

30 30 30 37 41 41 30 31 30 32 30 33 30 34 30

4 by Process #2

A1

As you can also notice that the data replied (echoed) is not identical with what I send from the terminal.

And furthermore, if I remove line "Process #2" completely, I can get a proper echo;

37 45 30 30 30 37 41 41 30 31 30 32 30 33 30 34 30 35 30 36 43 43

What am I really missing here?

int main()
{
    SystemInit();       /* Clock and PLL configuration */   
    UARTInit(0, 57600); /* baud rate setting */

    while(1)
    {
        if ( UART0Count != 0 )
        {
            LPC_UART0->IER = IER_THRE | IER_RLS;            /* Disable RBR */

            UARTSend( 0, (uint8_t *)UART0Buffer, UART0Count ); // Process #1

            UART0Count = 0;

// I need to call a function here in order to process data in UART0Buffer
// like checking/using STX, CHKSUM and DATA.

            // A test, if I can manage to use the data in pieces
            UARTSend( 0, (uint8_t *)UART0Buffer[0], 1); // Process #2

            LPC_UART0->IER = IER_THRE | IER_RLS | IER_RBR;  /* Re-enable RBR */
        }
    }
}

void UARTSend( uint32_t portNum, uint8_t *BufferPtr, uint32_t Length )
{
  if ( portNum == 0 )
  {
    while ( Length != 0 )
    {
      /* THRE status, contain valid data */
      while ( !(UART0TxEmpty & 0x01) ); 
      LPC_UART0->THR = *BufferPtr;
      UART0TxEmpty = 0; /* not empty in the THR until it shifts out */
      BufferPtr++;
      Length--;
    }
  }
}

EDIT: As dude has already explained the wrong use of "Process #2", please ignore it. It somehow breaks things. However, my issue persists. Although I can get an echo by "Process #1", I couldn't manage to read and use the data!?! Any pointers would be greatly appreciated.

EDIT:

Receiving:

void UART0_IRQHandler (void) 
{
  uint8_t IIRValue, LSRValue;
  uint8_t Dummy = Dummy;

  IIRValue = LPC_UART0->IIR;

  IIRValue >>= 1;           /* skip pending bit in IIR */
  IIRValue &= 0x07;         /* check bit 1~3, interrupt identification */
  if ( IIRValue == IIR_RLS )        /* Receive Line Status */
  {
    LSRValue = LPC_UART0->LSR;
    /* 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 */
      UART0Status = LSRValue;
      Dummy = LPC_UART0->RBR;       /* Dummy read on RX to clear 
                            interrupt, then bail out */
      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 */
      UART0Buffer[UART0Count] = LPC_UART0->RBR;
      UART0Count++;
      if ( UART0Count == BUFSIZE )
      {
        UART0Count = 0;     /* buffer overflow */
      } 
    }
  }
  else if ( IIRValue == IIR_RDA )   /* Receive Data Available */
  {
    /* Receive Data Available */
    UART0Buffer[UART0Count] = LPC_UART0->RBR;
    UART0Count++;
    if ( UART0Count == BUFSIZE )
    {
      UART0Count = 0;       /* buffer overflow */
    }
  }
  else if ( IIRValue == IIR_CTI )   /* Character timeout indicator */
  {
    /* Character Time-out indicator */
    UART0Status |= 0x100;       /* Bit 9 as the CTI error */
  }
  else if ( IIRValue == IIR_THRE )  /* THRE, transmit holding register empty */
  {
    /* THRE interrupt */
    LSRValue = LPC_UART0->LSR;      /* Check status in the LSR to see if
                                    valid data in U0THR or not */
    if ( LSRValue & LSR_THRE )
    {
      UART0TxEmpty = 1;
    }
    else
    {
      UART0TxEmpty = 0;
    }
  }

}

Upvotes: 0

Views: 1948

Answers (1)

kkrambo
kkrambo

Reputation: 7057

You're basically designing a serial message driver. Divide the design into layers.

The lowest layer is the UART driver that moves characters to and from the hardware UART. The UART driver encapsulates all the knowledge about how to interface to the UART hardware. This layer knows nothing of frames or messages, only characters. It copies a transmit character to the TX register when a transmit character is available and the UART is ready to transmit. It copies a received character from the UART RX register when one is available. These actions are typically implemented in the UART interrupt service routine. And typically, RAM circular buffers are used to store the TX and RX characters.

The next layer is for framing characters. This layer is responsible for identifying the characters that delimit a frame. This layer encapsulates all the knowledge about characters are delimited into frames. This is typically implemented as a state machine that gets repeatedly called when characters are available in the RX buffer. The state machine gets the next character from the RX buffer and processes it according to the current state. States might include, for example, waiting_for_start_of_frame, copying_body_of_frame, and waiting_for_end_of_frame. If the frame protocol includes a frame check sequence then this layer performs the check. This layer doesn't attempt to interpret the meaning of frames, rather it just forms complete frames to be used by the next layer.

If your serial messages are large enough to span multiple frames then you might have a layer here that stitches frames together into messages. Or if each message is a contained within a single frame then you probably don't need this layer.

At the top is the layer that actually interprets the message and performs the appropriate actions. This layer doesn't know anything about the UART or the frame delimiters because all of that knowledge is encapsulated by the lower layers.

This answer has more tips, Embedded C UART conventions

Upvotes: 1

Related Questions