1 2 Previous Next 18 Replies Latest reply on Jul 30, 2020 8:04 PM by CaDu_3933941

    UART Flow Control

    CaDu_3933941

      Hi all,

       

      Like some might remember, I have been working in an RC car for which I need a transmitter and Receiver.

       

       

      From the Transmitter size, I am sending packets of data to be unpacked by the receiver.

       

      My problem is that it seems that data is being overrun. The transmitter, which sends the car's control signals, is running less processes than the receiver (which is running anything from a digital filter to a PID controller). My theory is that this causes the transmitter to send data at a much faster rate than the receiver can handle. To solve this, I tried to implement an error checking scheme with cheksum and other things. Now my problem seems to persist, for which I then I tried to implement some sort of flow control, where the transmitter does not send data unless the receiver sends a data_ready bit. So far, I have been unsuccessful so I was hoping anyone could take a look a it?

       

      I am attaching both the receiver and the transmitter:

        • 1. Re: UART Flow Control
          MoTa_728816

          Hi,

           

          I just skimmed your sources.

           

          Your transmitter seems to sending a packet each 20ms, which is 50Hz or 50 times per second.

          I wonder how quickly the car must react to the control.

          An RC airplane may require very fast response, but for the RC car it may not require that quick response.

           

          So, if I were you I would try one of these

          (1) Change the CyDelay(20) in the RC_Transmitter's loop to CyDelay(50), this will make the response to 20Hz.

          (2) In the RC_Receiver, use a GPIO and set it every time packet_received is set and clear it at the beginning of the for (;;)

              so that you can measure the time required for the packet received event.

              After you get a ball figure measure of required time, set the CyDelay() in the Transmitter to be longer than that.

           

          moto

          • 2. Re: UART Flow Control
            CaDu_3933941

            Motoo,

             

            I added that delay in the transmitter since it seems that's the only way it can operate without an overrun. I should've been more clear.

            Ideally, I would want to get rid of that delay and manage the flow control the following way:

            - The transmitter would send data and wait for the receiver to unpack it and send back an acknowledge bit. Once the Ack bit is received by the transmitter, the next packet would be sent, so on and o forth.

             

            I am assuming this scheme would be enough to avoid said overrun (If you have any ideas, I would appreciate it)

            • 3. Re: UART Flow Control
              MoTa_728816

              Hi,

               

              If that is the case, I would try to modify your main.c of RC_Transmitter like below.

              The changing points are,

              (1) I clear the RxBuffer before sending packet

              (2) Let Transmitter wait for the ack, with timeout (I defined RX_TIMEOUT_MS 500, but you can change it as you like)

              (3) If some response was received, read data_ready or set data_ready as it means timeout occurred.

              Note: May be for the ack value using something beside 1 is good, for example 0xA5 or something which can not happen easily.

              But for the time being, I just used the test for only 0 or not.

              =================

                      if(data_ready||!UART_GetRxBufferSize()){

                          Data_Out[tx_index++]=(Increase_Decrease<<6)|Cruise_Control<<4|Y_2;

                          Data_Out[tx_index++]=Y_1;

                          Data_Out[tx_index++]=Servo_2;

                          Data_Out[tx_index++]=Servo_1;

                          for(i = 0; i<=(tx_index-1); i++){

                              sum+=Data_Out[i];

                          }

                          Data_Out[tx_index++] = sum & 0xFF;

                          Data_Out[tx_index++]=CR;

                          UART_ClearRxBuffer() ; /* === */

                          UART_PutArray(Data_Out,tx_index); // Data Out

                          data_ready=0;

                      }

               

                      // wait for a response from the receiver

                      timeout_count = 0 ;

                      while(UART_GetRxBufferSize() == 0) {

                          timeout_count++ ;

                          if (timeout_count >= RX_TIMEOUT_MS) {

                              break ;

                          }

                      }

               

                      if (UART_GetRxBufferSize()) { // if we have receiced a response

                          data_ready = UART_ReadRxData();

                      } else { /* timeout occures, assume we can send new one */

                          data_ready = 1 ;

                      }

              =================

               

              Since I have no way to test this, I just made sure that the project is "compile-able".

               

              moto

              • 4. Re: UART Flow Control
                CaDu_3933941

                Motoo,

                 

                Thanks, how would this be processed on the receiver side?

                • 5. Re: UART Flow Control
                  CaDu_3933941

                  Also, What would be the purpose for clearing the RX buffer before sending the next packet?

                  • 6. Re: UART Flow Control
                    MoTa_728816

                    Hi,

                     

                    > Thanks, how would this be processed on the receiver side?

                    In the main.c of RC_Receiver line 302 - 305

                     

                            if(data_ready){

                                UART_WriteTxData(1);

                                data_ready=0;

                            }

                     

                    When data_ready != 0, receiver sends back 1 to the transmitter.

                    But this response has not been really utilized.

                    So I added some lines to confirm the response from the receiver.

                     

                    But I regret that I should have made it something like below

                     

                         UART_WriteTxData(0xA5) ;

                     

                    so that a simple noise can not be mistaken as a response.

                    But to start with this may be OK.

                     

                    If you change this. You also would like to change main.c of Transmitter line 103-107

                    from

                     

                            if (UART_GetRxBufferSize()) { // if we have receiced a response

                                data_ready = UART_ReadRxData();

                            } else { /* timeout occures, assume we can send new one */

                                data_ready = 1 ;

                            }

                     

                    to

                     

                            if (UART_GetRxBufferSize()) { // if we have receiced a response

                                data_ready = UART_ReadRxData();

                                 if (data_ready != 0xA5) { /* 0xA5 is the expected response */

                                            data_ready = 0 ;

                                   }

                            } else { /* timeout occurred, assume we can send new one */

                                data_ready = 1 ;

                            }

                     

                    moto

                    • 7. Re: UART Flow Control
                      MoTa_728816

                      Hi,

                       

                      > Also, What would be the purpose for clearing the RX buffer before sending the next packet?

                      This time, the Transmitter is expecting receive a response from the Receiver,

                      but there could be some noise and/or garbage data already received in the RX buffer,

                      so I clear the Rx buffer to get rid of them to prepare for the new response which should be sent

                      from the Receiver after Transmitter sends the packet.

                       

                      To be honest, this may not be necessary, but trying to make the program more robust,

                      adding this line won't harm, I hope.

                       

                      moto

                      • 8. Re: UART Flow Control
                        CaDu_3933941

                        Got it, son on the receiver side, where on the code should I state that data_ready = 1 in order to enter that if statement? Because I was originally thinking I could set it to 1 at the end of the interrupt right before clearing it.

                        • 9. Re: UART Flow Control
                          MoTa_728816

                          Hi,

                           

                          In terms of "communication" may be after the line of

                           

                               packet_received = 0 ;

                           

                          in the block of "if (packet_received) {"

                           

                          But to allow safe calculation, may be after the line of

                                  // Servo Control

                                  PWM_Servo_WriteCompare(Servo);

                           

                          And put

                           

                                  if(data_ready){

                                      UART_WriteTxData(1); // 1 or 0xA5 depending on your check procedure in the transmitter

                                      data_ready=0;

                                  }

                           

                          moto

                          • 10. Re: UART Flow Control
                            CaDu_3933941

                            Got it,

                             

                            Also, any chance that processing the buffer on the UART ISR Handler might be holding the CPU up for too long?

                            • 11. Re: UART Flow Control
                              MoTa_728816

                              Hi,

                               

                              As far as I see, the RX_Handler seems to be ok.

                               

                              But may be you need to have RX_ISR_ClearPending()  outside of  "if (UART_GetRxBufferSize() .. " block

                              ===================

                              CY_ISR(RX_Handler){

                                  if(UART_GetRxBufferSize() &&

                                      packet_received == 0){

                                      Bytes_In[i]=UART_GetByte();  

                                      if(Bytes_In[i] == CR){ /*End of message received*/

                                           /*If end of message received, unpack buffered data onto corresponding variables*/

                                          packet_sum = (Bytes_In[0]+ Bytes_In[1]+Bytes_In[2]+Bytes_In[3])&0xFF; /*Calculates cheksum an compares*/

                                          if(packet_sum == Bytes_In[4]){

                                              packet_received =1;

                                          }

                                          else packet_received = 0;

                                      }

                                      i++;

                                      if(i == MSG_LENGTH) {

                                          i = 0;

                                      }

                                      data_ready=1;

                              //        RX_ISR_ClearPending(); /* from here */

                                  }

                                   RX_ISR_ClearPending(); /* To here */

                              }

                              ===================

                               

                              And also if the devices connected allow, you may want to make I2C faster.

                              400KHz ?

                               

                              moto

                              • 12. Re: UART Flow Control
                                CaDu_3933941

                                Woops, thanks for that. I didn't realize it.

                                 

                                Would speeding up the I2C help?

                                • 13. Re: UART Flow Control
                                  MoTa_728816

                                  Hi,

                                   

                                  > Would speeding up the I2C help?

                                  At least it will shorten the main loop time.

                                  But only if the devices connected can go with that speed.

                                   

                                  moto

                                  • 14. Re: UART Flow Control
                                    CaDu_3933941

                                    Got it, I shall try that.

                                     

                                    Another thing I noticed, it seems like the communication is fine if I power up the devices the following order:

                                    1. Receiver ON

                                    2.Transmitter ON

                                     

                                    However, if I turn off the receiver off and then back on, it stops working and it seems as if the data packets get stored in the wrong buffer addresses.

                                     

                                    I contrast, if I turn the transmitter off and then back on, while keeping the receiver on, communication will pick back up just as normal.

                                     

                                    Another thing, I have a cruise control mode and when communication between both tx and rx is fine, whenever I set the cruise control to come on, then the communication falls apart once more and the receiver stops responding. The Cruise control functionality is this one:

                                     

                                    if(Cruise_Control_Status==TRUE){

                                               

                                                I2C_DataWrite[0]=0x05;

                                                I2C_DataWrite[1]=0xFF;

                                                I2C_MasterWriteBuf(LED_ADDR, I2C_DataWrite, 2, I2C_MODE_COMPLETE_XFER);

                                                while(I2C_MasterStatus()!=I2C_MSTAT_WR_CMPLT);

                                                start_measure();

                                                while(!dataReady){}

                                                speed=65*iFreq/20;

                                                speed_out=Speed_Filter(0.1);

                                                if(Increase_Decrease == 0x01||

                                                    Increase_Decrease == 0x02){

                                                    Timer_Speed_Set_Start();

                                                    Reset_Speed_Write(1);

                                                    Reset_Speed_Write(0);

                                                   

                                                }

                                                if(!c){

                                                    Speed_Set = (int)speed_out;

                                                    c=1;

                                                }

                                                PWM_Motor_Start();

                                                PID(Speed_Set,2.0,0.8,0);

                                            }

                                     

                                     

                                    You can find the PID and speedout functions on the project files I provided for the receiver.

                                     

                                    Would any of this look like something that would hold the program up?

                                    1 2 Previous Next