Help with lpc2378 and uart0 interrupts

I’m trying to design a application for my arm7 that’ll wait for data to start coming in from UART0 and then start processing it.

I’m able to determin the exact number of bytes I’m expecting to receive by reading the first 3 bytes that I receive as the 3rd byte dictates the whole number of bytes expected.

What I want to achieve here is basically have call a routine after the first 3 bytes have been received and then read the 3rd byte and store it in a value then call another routine to grab the rest of the bytes expected and then depending on what was received respond back with a proper formated response.

Any clues or example code I can look at.

I’ve already gotten uart0 working to send data from my arm7 to my pc with some sample code I downloaded but haven’t been able to get more then one char at a time.

Thanks.

I use interrupts and a circular buffer. Here is the ISR code:

//------------------------ UART0 ISR ------------------------//
static void
uart0ISR(void)
{
  /* Read IIR to clear interrupt and find out the cause */
  unsigned iir = U0IIR;

  /* Handle UART0 interrupt */
  switch ((iir >> 1) & 0x7)
    {
      case 1:
        /* THRE interrupt */
        break;
      case 2:
        /* RDA interrupt */
        do
          {
          uint16_t temp;

          // calc next insert index & store character
          temp = (uart0_rx_insert_idx + 1) % UART0_RX_BUFFER_SIZE;
          uart0_rx_buffer[uart0_rx_insert_idx] = U0RBR;

          // check for more room in queue
          if (temp != uart0_rx_extract_idx)
            uart0_rx_insert_idx = temp; // update insert index
          }
        while (U0LSR & 0x01);

        break;
      case 3:
        /* RLS interrupt */
        break;
      case 6:
        /* CTI interrupt */
        break;
   }
}

I’ve forgotten where it came from.

Leon

Ok I have that code already in this demo that I’m trying to use to make my app from.

What I don’t understand is how to use it to get the 3rd byte and then from that 3rd byte determin number of bytes left to read from buffer then once all bytes read clear rx buffer and wait again…

Just put everything into into the circular buffer. If it’s ASCII you can use control codes to identify the start and finish of the block of data. I send fixed length records with CRC, which makes things easy. I also use a simple ACK/NAK protocol between the two systems.

Leon

Ok let me clarify things a bit better.

I’ve done vb.net and asp.net and php code but never have I done c/c++ code nor have I ever worked with micro devices.

This is 100% new to me so I haven’t a clue on what a circular buffer is.

All I know is the sample demo code I grabbed works perfectly for sending data strings to the pc but I’ve yet to figure a way to get strings of data sent from the pc to the uart to then be re-echoed back to the pc to show that it was infact received.

Sorry if me being a totall newbie at this hinders your ability to help me.

Try Google. Most comms systems use circular buffers.

You don’t need to echo the data back if you use CRC and a simple protocol like the one I mentioned. I’m actually using it for sending commands from a PC to an LPC2148 system, and sending data back from the LPC2148 to the PC. This is how I implemented it on the LPC2148:

unsigned int get_command()
{
  u_long crc, received_crc; // crc is the calculated CRC
  unsigned char temp1[20], temp2[20];
  unsigned char temp[10];

  if (serial_buffer_ptr == 12) // if all 12 characters have been received
  {
    (void) strncpy(temp1, serial_buffer, 4); // get command in temp1
    temp1[4] = 0; // terminating null for string
  
    (void) strncpy(temp2, serial_buffer+4, 8); // get CRC in temp2
    temp2[8] = 0; // terminating null for string
  
    sscanf(temp2, "%8lx", &received_crc); // convert received CRC string to a long
    crc = crc32(temp1, 4); // calculate CRC for command string    
    {
      if (crc == received_crc) // compare received and calculated CRCs
      {
        serout0(ACK); // send ACK if they match
        serout0(CR);
        serout0(LF);
        #ifndef NDEBUG
        debug_puts("ACK");
        #endif
        serial_buffer_ptr = 0; // reset pointer
        if (temp1[0] == '3') //test for Ekta Asssembly
        {
          if (temp1[1] == '5')  
          {                     
            temp[0] = temp1[2];//extract 2 hex digits into temp (string)
            temp[1] = temp1[3];
            temp[2] = '\0';
            sscanf(temp, "%X", &speed);//convert string to decimal in speed
            return(35);
          }

        }
        else
          return(atoi(temp1)); // return command as numeric value
      }
      else
      {
        serout0(NAK); // send NAK if they don't match
        serout0(CR);
        serout0(LF);
        #ifndef NDEBUG
        debug_puts("NAK");
        #endif
        serial_buffer_ptr = 0; // reset pointer
        return(0);
      }
    }
  }
  else
    return(0);
}

I get the data from the circular buffer, check the CRC and send an ACK if it is correct, or a NAK if there is an error. The PC does the same thing with the received data. We never get any errors, but we need to check as it’s a medical system and the consequences of the wrong data being received could be disastrous for the patient.

Leon

Ok here’s what I’ve got so far but can’t seem to get it working.

Routine to extract a certain number of bytes and return them in a string.

int uart0Gets(int bytes)
{
  uint8_t data;
  int count = 1;

  if (uart0_rx_insert_idx == uart0_rx_extract_idx) // check if character is available
    return -1;

  while (count <= bytes)
  {
  data += uart0_rx_buffer[uart0_rx_extract_idx++]; // get character, bump pointer
  uart0_rx_extract_idx %= UART0_RX_BUFFER_SIZE; // limit the pointer
  count +=1;
  }

  return data;
}

Routine called by some code

for (;;) {
		if ((ch = uart0Gets(1)) >= 1)
		{
			uart0Puts("Bytes Received\r\n");
		}
}

return 0;

I use this code to get data from the UART1 input queue into an array:

unsigned int get_motor_speed()
{
  int c, i;
  unsigned char temp3[30];

  i = 0;
  _puts1("GN");
  while ((c = uart1Getch()) != -1)
    temp3[i++] = c;
  temp3[i] = '\0';
  return (atoi(temp3)); 
}

Leon

Ok here’s my new function for grabbing a specified number of bytes from uart0

char rx_data[30];

char uart0GetBytes(int bytes)
{
	int rx_size = 0;

	do {
	} while (uart0_rx_insert_idx == uart0_rx_extract_idx);

	uart0Puts("1\r\n");

	while (rx_size != bytes - 1) {
			rx_data[rx_size++] = uart0_rx_buffer[uart0_rx_extract_idx++];
	}

	uart0Puts("2\r\n");

	uart0_rx_extract_idx %= UART0_RX_BUFFER_SIZE;
	rx_size = 0;

	uart0Puts("3\r\n");

	return *rx_data;
}

It doesn’t seem to work, I type in 3 bytes via hyperterminal and it never displays them. Actually for that matter it never even prints number 1.

echel0n:
Ok here’s my new function for grabbing a specified number of bytes from uart0

char rx_data[30];

char uart0GetBytes(int bytes)
{
int rx_size = 0;

do {
} while (uart0_rx_insert_idx == uart0_rx_extract_idx);

uart0Puts("1\r\n");

while (rx_size != bytes - 1) {
		rx_data[rx_size++] = uart0_rx_buffer[uart0_rx_extract_idx++];
}

uart0Puts("2\r\n");

uart0_rx_extract_idx %= UART0_RX_BUFFER_SIZE;
rx_size = 0;

uart0Puts("3\r\n");

return *rx_data;

}




It doesn't seem to work, I type in 3 bytes via hyperterminal and it never displays them. Actually for that matter it never even prints number 1.
My quick read:

Logic design error?

the first while loop waits for one or more bytes to be in the buffer.

the second while loop takes one byte but does not preclude a buffer-is-empty situation in the loop. if the passed variable “bytes” is > 1. This can work if enough bytes have already arrived before the function is called.

Also: incrementing the buffer pointers (all cases, including the interrupt routine), need to do the end of buffer wrap after every increment and that code as is doesn’t. It’s a good idea to make the buffer size a power of 2 and use a bitwise AND rather than a modulo operator, though some compilers will in effect do so anyway.

new code is left as an exercise for the student, as they say.

Echelon,

How are you debugging your software? You should be able to check if the interrupt is being called and trace through the program to see where it is going wrong.

Leon

Ok it’s this line that seems to be were i’m getting hung up on in the code.

   do { 
   } while (uart0_rx_insert_idx == uart0_rx_extract_idx);

The way you call this routine is by doing this:

nRet = GetBytes(3);

When you start up the devel board with this code and go into a terminal window it just looks like it’s stuck but if you hit reset well holding down a key on the keyboard it’ll display that key and go through.

Any reason ?

Ok i’ve made some more changes to the routine but still it doesn’t seem to be working, seems to me it’s stuck in the loop and never has a chance to get the bytes I’m wanting.

char uart0GetBytes(int bytes)
{
	int rx_size = 0;
	int ch;

	while (rx_size != bytes - 1) {
		if ((ch = uart0Getch()) >= 0) {
			rx_data[rx_size++] = ch;
		}
	}

	uart0Puts("2\r\n");

	rx_size = 0;

	return *rx_data;
}

whats wrong with this code ?

Ok I’ve solved one problem and this new code seems to work as long as I have interrupts disabled. Would it be better to use interrupts ?

Getbytes function

char* uart0GetBytes(void)
{
	static char rx_data[256];
	int rx_size = 0;
	int bytes = 3;
	int ch;

	do {
		if ((ch = uart0Getch()) >= 0) {
			rx_data[rx_size++] = ch;
		}
	} while (rx_size != (bytes * 2));

	return rx_data;
}

RX ISR Interrupt function

void uart0ISR(void)
{
  uint8_t iid;

  // perform proper ISR entry so thumb-interwork works properly
  ISR_ENTRY();

  // loop until not more interrupt sources
  while (((iid = U0IIR) & UIIR_NO_INT) == 0)
    {
    // identify & process the highest priority interrupt
    switch (iid & UIIR_ID_MASK)
      {
      case UIIR_RLS_INT:                // Receive Line Status
        U0LSR;                          // read LSR to clear
        break;

#ifdef UART0_RX_INT_MODE
      case UIIR_CTI_INT:                // Character Timeout Indicator
      case UIIR_RDA_INT:                // Receive Data Available
        do
          {
          uint16_t temp;

          // calc next insert index & store character
          temp = (uart0_rx_insert_idx + 1) % UART0_RX_BUFFER_SIZE;
          uart0_rx_buffer[uart0_rx_insert_idx] = U0RBR;

          // check for more room in queue
          if (temp != uart0_rx_extract_idx)
            uart0_rx_insert_idx = temp; // update insert index
          }
        while (U0LSR & ULSR_RDR);

        LED1_PIN ^= LED1_BIT;

        break;
#endif

#ifdef UART0_TX_INT_MODE
      case UIIR_THRE_INT:               // Transmit Holding Register Empty
        while (U0LSR & ULSR_THRE)
          {
          // check if more data to send
          if (uart0_tx_insert_idx != uart0_tx_extract_idx)
            {
            U0THR = uart0_tx_buffer[uart0_tx_extract_idx++];
            uart0_tx_extract_idx %= UART0_TX_BUFFER_SIZE;
            }
          else
            {
            // no
            uart0_tx_running = 0;       // clear running flag
            break;
            }
          }

        break;
#endif // UART0_TX_INT_MODE

      default:                          // Unknown
        U0LSR;
        U0RBR;
        break;
      }
    }

  VICVectAddr = 0x00000000;             // clear this interrupt from the VIC
  ISR_EXIT();                           // recover registers and return
}