Announcement

Collapse
No announcement yet.

Buffered UART

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Buffered UART

    Hi

    I am at a point in project where I need to optimize my code to get a fastest execution time.
    More precisely, when the user is using a slider widget, I have some data to send on the serial/UART. Since the user can play quickly with the slider, I need my serial communication to be fast, to prevent lag.

    I have setup my UART to work in buffered mode, thinking it would give me a faster execution.

    Here is what I understood :
    - Using normal mode, serout() needs to wait until there is some free space to send the next data.
    - Using buffered mode, serout() will fill a circular buffer. When using com_TXbufferHold(OFF), the data in the buffer is automatically sent on the UART.
    This mode should execute faster, since I am filling a variable, and not directly the UART register.

    However, trying a buffered and non-buffered code gives me the same execution duration :

    Code:
    // Global Variable
    #constant TX_COM_BUFFER_SIZE_ENCODED_FRAME 1024
    var TXbuff [TX_COM_BUFFER_SIZE_ENCODED_FRAME];
    
    
    
    func main()
    
    [Some inits]
    
    com_Reset();
    com_SetBaud(COM0, 39700); // Parameter for the function is Baud/10
    com_Init(RXbuff, BACKGROUND_SERIAL_COM_BUFFER_SIZE,0);
    com_TXbuffer(TXbuff,TX_COM_BUFFER_SIZE_ENCODED_FRAME*2,0); // Each array cell is 2 bytes


    Code:
    func sendSerialFrame(var cmd, var * dat, var dataLength)
    
    var i := 0;
    var checksum := 0;
    
    var tst_start ;
    var tst_stop ;
    
    
    tst_start := sys_T();
    
    
    // Make sure the previous frame is completely sent (equivalent to while(isDMABusy()) )
    while(com_TXcount() > 0) ;
    
    
    // Tell TXBuffer that we want to fill the buffer, but not send directly
    com_TXbufferHold(ON);    // REMOVED WHEN TRYING NON-BUFFERED
    
    
    // START CODE
    serout(SERIAL_COMMUNICATION_START_CODE) ;
    
    // Command (need to add an ESCAPE if required)
    if((cmd == SERIAL_COMMUNICATION_START_CODE) | (cmd == SERIAL_COMMUNICATION_STOP_CODE) | (cmd == SERIAL_COMMUNICATION_ESCAPE_CODE))
         serout(SERIAL_COMMUNICATION_ESCAPE_CODE) ;
    endif
    serout(cmd) ;
    checksum := cmd ;
    
    
    // All data
    // Using the same loop, compute the checksum.
    // Using a while() is a bit faster than for() !!
    while(i<dataLength)
         // If any of these byte needs an ESCAPE, add the ESCAPE to the encoded frame
         if((dat[i] == SERIAL_COMMUNICATION_START_CODE) | (dat[i] == SERIAL_COMMUNICATION_STOP_CODE) | (dat[i] == SERIAL_COMMUNICATION_ESCAPE_CODE))
              serout(SERIAL_COMMUNICATION_ESCAPE_CODE) ;
         endif
         serout(dat[i]) ;
    
         // The checksum does not take into account the START, STOP and ESCAPE
         checksum := checksum + dat[i] ;
         if(checksum > 255)
              checksum := (checksum - 256) ;
         endif
    
    i++ ;
    wend
    
    
    // Checksum
    serout(checksum) ;
    
    // STOP CODE
    serout(SERIAL_COMMUNICATION_STOP_CODE) ;
    
    // Release TX buffer : all the data will be sent !
    com_TXbufferHold(OFF);   // REMOVED WHEN TRYING NON-BUFFERED
    
    // Display the execution duration
    tst_stop := sys_T();
    putstrXY(0,0,"Total: ");
    putnumXY(50,0, DEC, tst_stop-tst_start);
    endfunc

    Is there something I am missing, or misanderstanding ?
    My baud is setup for ~400k, 8 bits, No parity. A 512 byte frame should take ~13ms to be sent out.
    I know I have a bit of extra commands to encode my frame, but I find it suprising to get a 27ms execution time for sendSerialFrame(), in both buffered and non-buffered.


  • #2
    Hello Vincent,

    Using com_TXbuffer will not speed up the transfer of byte frames nor it would make the processor tick any faster. Therefore, you can't expect sendSerialFrame() to execute faster than it already is. The function will only let you store the data in a var array as a circular buffer.

    Perhaps you could increase the baud rate if you need faster transmit speed? Doing so, of course, you should expect higher error percentage.

    Best regards,
    Sherwin

    Comment


    • #3
      Have a look at your code carefully, especially where you have put
      tst_start := sys_T();
      You are not timing what you think you are timing.

      Regardless, a TX buffer will help you transmit faster, holding the TX until the buffer contains a frame will actually slow the transmission time a bit.
      Mark

      Comment


      • #4
        Sherwin, Mark, thanks for your messages.

        I was expecting the buffer transmit to be faster, as I am filling a circular buffer rather than the UART directly. Turns out it does not make any significant difference speedwise.

        I checked on the oscilloscope my frame, which I should have done in the first place.
        Using the same code as posted in my initial post, and getting the same results in both buffered and non-buffered.
        My 512 byte frame takes ~13ms to be sent out, which is the expected duration (512 bytes + Start and Stop bits = 5120 bits | @400k = 12.8ms).
        However, the piece of code I use to monitor the duration is telling me 27ms.

        Code:
        tst_start := sys_T();
        // ACTION TO MEASURE //
        tst_stop := sys_T();
        putstrXY(0,0,"Total: ");
        putnumXY(50,0, DEC, tst_stop-tst_start);
        I tried something similar with sys_GetTimer() and sys_SetTimer(), and it's providing similar results.
        Since I am trying to optimize my program, I need to spot the slowest functions. I don't need something extra accurate, but a quick overview if a given function should be a bit more rafined to get a faster execution.

        Comment


        • #5
          Any hint on why I am measuring a 13ms on my oscilloscope but 27ms with my code ?
          What would a better code to measure the execution time of a section of code ?

          Comment


          • #6
            Hi Vincent,

            The hint is in post #3. Since you are holding back the buffer with com_TXbufferHold(ON), you'll have to put com_TXbufferHold(OFF) in between sys_T().

            Code:
            tst_start := sys_T();
            // ACTION TO MEASURE //
            com_TXbufferHold(OFF);
            tst_stop := sys_T();
            Hope this helps.

            Best regards,
            Sherwin
            Last edited by sherwin4D; 28 February 2020, 11:06 AM.

            Comment

            Working...
            X