Speed USART
Moderators: David Barker, Jerry Messina
Speed USART
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...
-
- Swordfish Developer
- Posts: 1473
- Joined: Fri Jan 30, 2009 6:27 pm
- Location: US
Re: Speed USART
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?
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
Yandex online translator...Jerry Messina wrote:Your English is fine.
Device = 18F26K20Jerry Messina wrote: A few questions -
1) What's the main clock frequency for the 26K20?
Clock = 16
...
USART.SetBaudrate(br115200)
packets of 128 bytes + 5 bytes (checksum, length...):Jerry Messina wrote: 2) How are you coding the array transfer? Could you show a bit of code?
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
Correct.Jerry Messina wrote: 3) I assume you're not using any kind of handshaking, correct?
-
- Swordfish Developer
- Posts: 1473
- Joined: Fri Jan 30, 2009 6:27 pm
- Location: US
Re: Speed USART
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.
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.
-
- Posts: 219
- Joined: Wed Sep 11, 2013 1:27 pm
- Location: Chesterfield
Re: Speed USART
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.
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.
-
- Swordfish Developer
- Posts: 1473
- Joined: Fri Jan 30, 2009 6:27 pm
- Location: US
Re: Speed USART
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.
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.
-
- Posts: 219
- Joined: Wed Sep 11, 2013 1:27 pm
- Location: Chesterfield
Re: Speed USART
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.
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.
-
- Swordfish Developer
- Posts: 1473
- Joined: Fri Jan 30, 2009 6:27 pm
- Location: US
Re: Speed USART
>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.
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.
-
- Swordfish Developer
- Posts: 1473
- Joined: Fri Jan 30, 2009 6:27 pm
- Location: US
Re: Speed USART
For kicks I put together some examples showing optimizations of the checksum portion of WriteUartData().
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.
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
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
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 :wink:](./images/smilies/icon_wink.gif)
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:
![Wink :wink:](./images/smilies/icon_wink.gif)
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