3
votes

The problem

  • An external source sends these four bytes 0x2A, 0x42, 0x78, 0x25
  • The PIC32 UART Does not generate an int
  • The external source sends one more byte
  • The PIC32 UART then generates an int
  • In that int, Only the 0x25 byte from the previous transmission appears
  • i.e., the first three disappear
  • Once in awhile (Maybe 5% of the time) the UART does produce all 4 bytes properly

[Friday Evening Debug Results]

We wrote another echo routine; it just reads what it gets and writes it back out.

We built it in release mode (on advice of another here)

I wrote a routine to send the same number out 25 times, and see what I get back.

After that, I inc the value and send it out 25 times, and loop.

Results are appended at the end of this message.

I'm not getting the first null byte back. Based on various factors, I won't worry about that at this moment.

The next five rounds, I'm getting everything back perfectly

I'll try to include all relevant source code, hope it isn't a wall of text. If more code is needed to understand this, please ask.

This is the init code for the UART in question. I can include the

  //*****************************************************************//
  void initUART1(void)   // UART1 for MCU1/2 communication
  {
   U1MODE=0;                     //// Mode Register, Manual DS61168D page 180
   U1MODEbits.FRZ=0;
   U1MODEbits.SIDL=0;
   U1MODEbits.IREN=0;
   U1MODEbits.RTSMD=0;

   U1MODEbits.UEN=0b00;           //// Just TX/RX, No CTS/RTS

   U1MODEbits.WAKE=1;
   U1MODEbits.LPBACK=0;
   U1MODEbits.ABAUD=0;
   U1MODEbits.RXINV=0;
   U1MODEbits.BRGH=1;
   U1MODEbits.PDSEL=0b00;
   U1MODEbits.STSEL=0;

   U1STA=0;
   U1STAbits.ADM_EN=0;
   U1STAbits.UTXINV=0;
   U1STAbits.URXEN=1;
   U1STAbits.UTXBRK=0;
   U1STAbits.UTXEN=1;
   U1STAbits.ADDEN=0;
   U1STAbits.OERR=0;     
                                 //// Status register, Manual DS61168D page 183

   //U1BRG=21;                    ////  21 for 921600 (80 MIPS)
     U1BRG=172;                   //// 172 for 115200 (80 MIPS)

   IFS0bits.U1RXIF=0;
   IPC6bits.U1IP=5;
   IPC6bits.U1IS=3;
   IEC0bits.U1RXIE=1;

   U1MODEbits.ON=1;
  }


  //*****************************************************************//

This is the interrupt service routine that handles this specific UART

  //*********************************************************//
  void __ISR(_UART1_VECTOR, ipl5) IntUart1Handler(void)   //MCU communication port
  {     
    if(INTGetFlag(INT_SOURCE_UART_RX(UART1)))  //if it's a rx interrupt
    {
       U1RxBuf=UARTGetDataByte(UART1);

    switch (CmdRecording)
    {
     case 0:
           if(U1RxBuf=='*')
           {
            CmdRecording=1;  //set the cmd recording flag
            Command_U1[0]=U1RxBuf;
            TimeOut=1;  //time out=1 means the timeout for MCU1 command receiver is enabled
            initT3(0x0100);  //time out=0 means the timeout for MCU1 command receiver is enabled
           }
           else
         {
          putcharUART1('$');
          putcharUART1('e');
          putcharUART1('2');
          putcharUART1('%');
         }
           break;
     case 1:
           CmdRecording=2;  //set the cmd recording flag
           Command_U1[1]=U1RxBuf;
           break;
     case 2:
           CmdRecording=3;  //set the cmd recording flag
           Command_U1[2]=U1RxBuf;
           break;
     case 3:
           CmdRecording=0;  //reset the cmd recording flag
           Command_U1[3]=U1RxBuf;
           if(U1RxBuf=='%') //if this is the last command byte
           {
                if((Command_U1[1]=='O'))
            {
               CMD_Err=0;      //clear error
             CMD_OK=1;      //send cmd OK;
            }
              else if((Command_U1[1]=='e'))
            {
               CMD_OK=0;      //clear OK
             CMD_Err=1;     //send cmd Err;
            }
            else
            Command_flag=1;
           }
           else
           {
            Command_flag=0;
           }

           disableT3(0);  //the command receiving is done, disable the time out #0 (command receving time out)
           TimeOut=0;  //the command receiving is done, disable the time out

           break;
     default:
           break;
    }
     INTClearFlag(INT_SOURCE_UART_RX(UART1));
    }

    if ( INTGetFlag(INT_SOURCE_UART_TX(UART1)) )  //if it's a tx interrupt
    {
        INTClearFlag(INT_SOURCE_UART_TX(UART1));
    }
  }

  //***********************************************//

This is data that I saw when running the bytes through the "echo" system; i.e., the routine which reads one, writes one.

The PIC-32 is running at 80 MHz, and the UART is doing 115200 bps, so I'm not worried about the speed.

  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 
  02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 
  03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 
  04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 
  05 05 05 05 05 05 05 05 05 05 05 05 05 05 05 05 05 05 05 05 05 05 05 05 05
1
'Only the last byte appears' - where? You have this Command_U1 array - what's in the four bytes?Martin James
Your ISR is primarily concerned with RX, for TX it merely clears the interrupt flag - I would suggest that this is not at all "all relevant source code"Clifford
Command-U1 holds 0x00, 0x00, 0x00, 0x00User.1
@Clifford, This is the PIC32 Interrupt routine that receives the bytes. This is the problem. When I send (from another source) bytes to this UART, I don't see the first 3.User.1
Just discovered: no int after sending 4 bytes. Am trying one at the time now.User.1

1 Answers

5
votes

It looks like the UART probably has a 4 byte FIFO and does not generate an interrupt until the FIFO is full. I am not familiar with the part, but often you can program the UART to generate an interrupt at a specific FIFO level or after an n-character time-out, so that data in a non-full FIFO can be read. Further, if this is the case, your ISR should loop until the FIFO is emptied, rather than simply reading a single character.