Tutorial :Circular buffer pointer irregularities


This is a follow up on this question: Display previously received UART values.

After implementing a circular buffer on the microcontroller, it seems that there is a problem with the pointers.

Sent on RS-232: ADE1234
Received (buffer = 8): E24AE2 / E2AE24 (Flips between the two) Received (buffer = 16): D234E1 (A is skipped, since it is a synchro byte)
Received (RX_BufSize = 32): DE1223 / DEE123 / DE1234 / DE12E1 (flips randomly)
Expected receive: DE1234


// Source: Thème 207 BTS électronique â€" Académie de Strasbourg  #define RX_BufSize 8            // Taille du Buffer_RX  char Buffer_RX[RX_BufSize];     // Buffer circulaire de réception  char *ptrRX_WRdata = Buffer_RX; // Pointeur d'écriture dans Buffer_RX  char *ptrRX_RDdata = Buffer_RX; // Pointeur de lecture dans Buffer_RX  unsigned char Buffer_Cmd[7];  

Debug values displayed on LCD

//Printed debug values. Decoded output is seen via U2buf  disp_string(-62, 17, 0, "Ply2");  char U2buf[] = {slave_command, slave_pal_d, slave_bal_x,                  slave_bal_y, slave_point_a, slave_point_b, '\0'};  disp_string(-37, 17, 1, U2buf);    char U3buf[] = {Buffer_RX[0], Buffer_RX[1], Buffer_RX[2],                     Buffer_RX[3], Buffer_RX[4], Buffer_RX[5],                     Buffer_RX[6], Buffer_RX[7], '\0'};  disp_string(-37, 27, 1, U3buf);    char U4buf[] = {Buffer_Cmd[0], Buffer_Cmd[1], Buffer_Cmd[2],                     Buffer_Cmd[3], Buffer_Cmd[4], Buffer_Cmd[5],                     Buffer_Cmd[6], '\0'};  disp_string(-37, 7, 1, U4buf);  

Receive interrupt

void _ISR _NOPSV _U1RXInterrupt(void){  IFS0bits.U1RXIF = 0;      while(U1STAbits.URXDA){          *ptrRX_WRdata++=U1RXREG;          if (ptrRX_WRdata == Buffer_RX+RX_BufSize) ptrRX_WRdata = Buffer_RX;      }      if (U1STAbits.OERR){          U1STAbits.OERR = 0;      }  }  

Functions from source

int ReadRXD(char *c){      if (ptrRX_RDdata==ptrRX_WRdata) return(0); // Pas de caractère reçu      else{          *c=*ptrRX_RDdata++;          if (ptrRX_RDdata==Buffer_RX+RX_BufSize) ptrRX_RDdata=Buffer_RX;          return(1);      }  }      void Detect_Cmd_RXD(void){      int i;      char c;      if (!ReadRXD(&c)) return;      ACL_XY_AFFICHER_CARACTERE(5, 3,256+'Z',1);      ACL_XY_AFFICHER_CARACTERE(25, 3,256+c,1);      for (i=1; i<7; i++) Buffer_Cmd[i-1]=Buffer_Cmd[i];      Buffer_Cmd[6]=c;      if (Buffer_Cmd[0]=='A'){ //&& (Buffer_Cmd[4]==0xAA)){          ACL_XY_AFFICHER_CARACTERE(15, 3,256+'Q',1);            slave_command = Buffer_Cmd[1];          slave_pal_d = Buffer_Cmd[2];          if (system_player == 2){              slave_bal_x = Buffer_Cmd[3];              slave_bal_y = Buffer_Cmd[4];              slave_point_a = Buffer_Cmd[5];              slave_point_b = Buffer_Cmd[6];          }      }  }  

Detect_Cmd_RXD is called every 1/256th of a second. During that time, at least 7 values will have been sent in the UART receive buffer.

Could it be possible that the write process is so fast that it catches up on the read pointer? What can I do to solve this problem besides calling Detect_Cmd_RXD more often?


First step: Set a flag in the interrupt routine if the buffer overruns, and check for overruns in the Detect_Cmd_RXD routine. See how changing the buffer size affects the number of overruns.

Second step: If you get to a buffer size where there are no overruns, and still have corruption, take a good look at the interrupt routine. UARTs can be quite sensitive to how quickly you access their registers, or the order of operations. Check the hardware datasheet and verify that you are reading it correctly - better still, find some sample code that does similar things to what you want to do. The repeated characters when buffer size is 32 could be you reading the data register twice before the status bit has had a chance to settle down.


Shouldn't IFS0bits.U1RXIF = 0; be set at the end of the routine?

Afaik it ends the interrupt and allows a new one.

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Next Post »