ccommunicationmicrocontrolleruartdspic

MikroC, UART. Requesting multiple bytes


I'm trying to request multiple bytes from a remote device via UART. To get the needed info, you send a single request byte in order to receive a single data byte. I'm having difficulties identifying data bytes when requesting more then one.

The UART receiving is handled via interrupt:

void UART2RXInterrupt() iv IVT_ADDR_U2RXINTERRUPT 
{
   uart_rd2[LoopVar0] = UART2_Read();       //Read into buffer
   LoopVar0++;
   if (LoopVar0 >= 1)
   {
      LoopVar0 = 0;
      ready0 = 1;
   }
   U2RXIF_bit = 0;                          //Reset interrupt flag
}

My code for a single data byte looks as follows:

 UART2_Write(0x11);    //Request byte
 if (ready0 == 1)      //Data received and ready
 {
   //Parse data byte
   ready0 = 0;         //Reset data received bit
 }

This works fine.

If I need more then just the one data byte I do as follows

 UART2_Write(0x11);    //Request byte 11h
 if (ready0 == 1)      //Data received and ready
 {
   //Parse data byte
   ready0 = 0;         //Reset data received bit
 }
 UART2_Write(0x14);    //Request byte 14h
 if (ready0 == 1)      //Data received and ready
 {
   //Parse data byte
   ready0 = 0;         //Reset data received bit
 }

The problem with this method is that the next request byte could be already transmitted without being certain that the last data byte is properly received.

This causes the data to get "scrambled". Meaning that the data byte from the last request could be parsed at the current request, and so on.

I cannot seem to find a proper solution for this. Any suggestions would be great!

Circular buffer implementation:

UART interrupt:

void UART2RXInterrupt() iv IVT_ADDR_U2RXINTERRUPT 
{
  uart_rcv[write_buffer_pointer0] = UART2_Read();   // put received char in circular buffer
  write_buffer_pointer0++;                // increment pointer
  if (write_buffer_pointer0 > 511) {
  write_buffer_pointer0 = 0;            // reset pointer
  }

  U2RXIF_bit = 0;
 }

Main loop handling:

void service_UART()
 {
 UART_send(0x14);       //MAP request
 UART_send(0x1D);       //ECT request

 if (read_buffer_pointer0 != write_buffer_pointer0) {  // new data in circular buffer
    ser_in();                                // handle incoming serial data
  }
 }

UART send routine:

void UART_send(volatile char data0)
{
uart_snd[write_buffer_pointer1] = data0;
write_buffer_pointer1++;                // increment pointer
if (write_buffer_pointer1 > 511) {
  write_buffer_pointer1 = 0;            // reset pointer
}
UART2_Write(data0);
}

Handling received data:

void ser_in() 
{
volatile char rqst;
volatile char resp;

resp = uart_rcv[read_buffer_pointer0]; // read next character from buffer
read_buffer_pointer0++;                 // increment read buffer pointer
if (read_buffer_pointer0 > 511) {       // if pointer past end of buffer
    read_buffer_pointer0 = 0;         // reset pointer
}
rqst = uart_snd[read_buffer_pointer1];
read_buffer_pointer1++;
if (read_buffer_pointer1 > 511) {
   read_buffer_pointer1 = 0;
}
// do something with the data here.
if (rqst == 0x14)    //If MAP request
{
//Handle MAP Data
} 
if (rqst == 0x1D)    //If ECT request
{
//Handle ECT Data
}   
}

Solution

  • Implement two circular queues with head and tail pointers (indexes), large enough to accommodate throughput rates. Determine the minimum time the responder requires between requests and respect it. Each time you send a request add it to the first queue, the “request sent queue”. When a response arrives add it to the second queue in your interrupt routine and increment the head pointer. This is your “response received queue”.

    You can then process transactions asynchronously in your main loop. Compare the second queue head to its tail. Each time the second queue becomes imbalanced (head does not equal tail) you have received at least one response. The first queue tells you the request it was a response to. Each time you complete processing a response advance the tail pointers of both queues.

    You probably want to reset the queues if you don’t get a response (if queues remain imbalanced for too long) and make sure the queues don't overwrite.