views:

288

answers:

2

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

Initialization

// 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?

+1  A: 

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.

Tony van der Peet
+1  A: 

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

Afaik it ends the interrupt and allows a new one.

Marco van de Voort