Page 1 of 1

Speed USART

Posted: Wed May 06, 2015 12:57 pm
by AndrF
I use pic18f26k20 & usart.bas. Baudrate = br115200. The transfer of an array of 1024 bytes takes approximately 0.3 seconds (controller - PC). It is possible to speed up? Sorry for bad English...

Re: Speed USART

Posted: Wed May 06, 2015 1:21 pm
by Jerry Messina
Your English is fine.

At 115200 baud each byte takes approx 86usec to transfer, so it should be possible to send 1024 bytes in 88msec or so... at least a lot faster than 300msec.

A few questions -
1) What's the main clock frequency for the 26K20?
2) How are you coding the array transfer? Could you show a bit of code?
3) I assume you're not using any kind of handshaking, correct?

Re: Speed USART

Posted: Wed May 06, 2015 1:38 pm
by AndrF
Jerry Messina wrote:Your English is fine.
Yandex online translator...
Jerry Messina wrote: A few questions -
1) What's the main clock frequency for the 26K20?
Device = 18F26K20
Clock = 16
...
USART.SetBaudrate(br115200)
Jerry Messina wrote: 2) How are you coding the array transfer? Could you show a bit of code?
packets of 128 bytes + 5 bytes (checksum, length...):

Code: Select all

Sub WriteUartData()
	Dim iCrcM0 As Word, i As Byte

        ' Calc checksum
	iCrcM0 = 0
	For i = 0 To g_UsartBuffer(2) - 1
		If i <> 3 AND i <> 4 Then
			iCrcM0 = iCrcM0 + g_UsartBuffer(i)
		EndIf
	Next
	g_UsartBuffer(3) = iCrcM0.Byte1
	g_UsartBuffer(4) = iCrcM0.Byte0
        ' Send Array
	For i = 0 To g_UsartBuffer(2) - 1
		USART.WriteByte(g_UsartBuffer(i))
	Next
End Sub
Jerry Messina wrote: 3) I assume you're not using any kind of handshaking, correct?
Correct.

Re: Speed USART

Posted: Wed May 06, 2015 2:33 pm
by Jerry Messina
For a packet of 133 bytes (128 + 5), WriteUartData() takes approx 12msec to compute the xsum and send the packet.

You could improve on the xsum calculation slightly but that's about it (right now it takes about 920usec).
The rest of the time (~11msec) is determined by the baudrate, so you'd have to run the uart faster to have any big effect on the time.

Re: Speed USART

Posted: Mon May 11, 2015 7:54 am
by SHughes_Fusion
The k22 series will happily run at 64MHz if you enable the PLL - I've got a few running at this speed in various application which are talking to an RN42 bluetooth module at 115200 baud.

You can also set faster baud rates quite easily but you will have to configure the UART yourself to achieve this, or edit the module to add calculations for other baud rates. You can easily get in to the mega-bauds with the clock speed you are running at.

Re: Speed USART

Posted: Mon May 11, 2015 9:29 am
by Jerry Messina
That's a good point. Bumping up the clock speed might help a lot.

I should have worded my previous post a bit differently. His packet routine takes about 12ms/128 byte packet, so it should be about 96ms to transfer 8 packets (1K). The OP said it was taking 300ms to transfer 1K of data.

Most of the time is being spent elsewhere, not in the transfer.

Re: Speed USART

Posted: Mon May 11, 2015 9:34 am
by SHughes_Fusion
That is a point, we could do with seeing more of the code to help optimise it further.

I did wonder if, for example, testing I<3 or I>4 would be more efficient than testing i<>3 and I<>4?

I'd also comment that using an interrupt-based buffered routine would allow the last lot of data to be being sent while the checksum was being calculated for the next lot - if you see what I mean. I'd guess that a lot of time is being spent here just waiting for the transmit buffer to empty.

Re: Speed USART

Posted: Mon May 11, 2015 10:27 am
by Jerry Messina
>I did wonder if, for example, testing I<3 or I>4 would be more efficient than testing i<>3 and I<>4?

You can speed up the xsum calculation portion of WriteUartData() a good bit, but that isn't really the limiting factor. Even sending the data isn't too bad... you're only ever waiting one char time at worst. This is a case where using transmit interrupts won't help much. Likely it'd actually make it slower unless as you say, you could work on the next packet while transferring the previous. Still only saves a few hundred usec at best.

WriteUartData() isn't the issue. It's elsewhere. 200 of the 300ms is being spent doing something, but not transferring the data.

Re: Speed USART

Posted: Mon May 11, 2015 11:28 am
by Jerry Messina
For kicks I put together some examples showing optimizations of the checksum portion of WriteUartData().

Code: Select all

clock=16
dim g_UsartBuffer(128 + 5) as byte

// original routine: 862us
Sub WriteUartData()
   Dim iCrcM0 As Word, i As Byte

   ' Calc checksum
   iCrcM0 = 0
   For i = 0 To g_UsartBuffer(2) - 1
      If i <> 3 AND i <> 4 Then
         iCrcM0 = iCrcM0 + g_UsartBuffer(i)
      EndIf
   Next
   g_UsartBuffer(3) = iCrcM0.Byte1
   g_UsartBuffer(4) = iCrcM0.Byte0
End Sub

// opt 1: remove tests from loop = 670us
Sub WriteUartData1()
   Dim iCrcM0 As Word, i As Byte
   dim len as byte

   ' Calc checksum
   iCrcM0 = 0
    ' set packet xsum bytes to 0 (adding zero doesn't change result)
   g_UsartBuffer(3) = 0
   g_UsartBuffer(4) = 0
   
   ' precompute len
   len = g_UsartBuffer(2) - 1
   ' xsum the packet
   For i = 0 To len
      iCrcM0 = iCrcM0 + g_UsartBuffer(i)
   Next
   ' put xsum 
   g_UsartBuffer(3) = iCrcM0.Byte1
   g_UsartBuffer(4) = iCrcM0.Byte0
End Sub

// opt 2: remove tests from loop and remove index calcs = 303us
Sub WriteUartData2()
   Dim iCrcM0 As Word
   dim len as byte

   ' Calc checksum
   iCrcM0 = 0
    ' set packet xsum bytes to 0 (adding zero doesn't change result)
   g_UsartBuffer(3) = 0
   g_UsartBuffer(4) = 0
   
   ' precompute len
   len = g_UsartBuffer(2)

    FSR0 = addressof(g_UsartBuffer)
    while (len <> 0)
      iCrcM0 = iCrcM0 + POSTINC0
      len = len - 1
    end while
    
   g_UsartBuffer(3) = iCrcM0.Byte1
   g_UsartBuffer(4) = iCrcM0.Byte0
End Sub

// test data
dim i as byte
// fill a packet w/data
for i = 0 to bound(g_UsartBuffer)
    g_UsartBuffer(i) = i
next
// set packet size
g_UsartBuffer(2) = 128 + 5

writeuartdata()     // 862us
writeuartdata1()    // 670us
writeuartdata2()    // 303us
I wasn't sure about the original logic and exactly what data the routine should be checksumming, so I did the entire 133 bytes.

You can get a decent boost just by being smart about what's in the for loop. We gained almost 200us just by recoding the for loop logic.

The last routine shows the benefits you can gain by taking advantage of the PIC18 low-level FSR instructions. The routine is almost three times as fast as the original.

Re: Speed USART

Posted: Mon May 11, 2015 12:50 pm
by octal
Be careful with this implementation. The loop variable "i" is a BYTE type variable, that means that if your g_UsartBuffer(2) variable is equal to ZERO, the loop will be executed from 0 to (-1) :wink:

Also, if you send frequently long buffers of data (with more than 1 byte), you better avoid the systematic test "If i <> 3 AND i <> 4 Then" in the loop and prefer to write your code as:

Code: Select all


Sub WriteUartData()
   Dim iCrcM0 As Word, i As Byte

   ' Calc checksum
   iCrcM0 = g_UsartBuffer(0) + g_UsartBuffer(1) + g_UsartBuffer(2)
   For i = 5 To g_UsartBuffer(2) - 1
         iCrcM0 = iCrcM0 + g_UsartBuffer(i)
   Next
   g_UsartBuffer(3) = iCrcM0.Byte1
   g_UsartBuffer(4) = iCrcM0.Byte0
End Sub