View previous topic :: View next topic |
Author |
Message |
AdrianJ
Joined: 16 Jan 2006 Posts: 2483 Location: Queensland
|
Posted: Sat May 16, 2015 12:13 am Post subject: Buffered serial output timimg |
|
|
Hi All,
I reposted this to the main group, having verified that the behaviour is still the same under Bascom version 2.0.7.8
I am playing with the buffered serial ouput feature, in the hope that I can save some processor time in sending long messages. The intention is to print a long message, but have it go into the buffer as fast as it can be written, and then have the actual transfers to the UART happen at the normal UART speed. That way the processor is not held up during the relatively long print process.
So I started with the SERIALOUT1 sample file, and modified it a bit, to set up for longer strings:
Code: | :
'-----------------------------------------------------------------------------------------
'name : rs232bufferout1.bas
'copyright : (c) 1995-2005, MCS Electronics
'purpose : how to use a serial output buffer on the second UART
' this sample will only work for chips with a seond UART like
' the M162 and M128
'micro : Mega644P
'suited for demo : yes
'commercial addon needed : no
'-----------------------------------------------------------------------------------------
$regfile = "m644Pdef.dat" ' specify the used micro
$crystal = 3686400 ' used crystal frequency
$baud = 38400 ' use baud rate
$hwstack = 32 ' default use 32 for the hardware stack
$swstack = 10 ' default use 10 for the SW stack
$framesize = 40 ' default use 40 for the frame space
'Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
Config Com2 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
dim bk as byte
config portb.7 = output
'setup to use a serial output buffer
'and reserve 250 bytes for the buffer
Config Serialout1 = Buffered , Size = 250
Open "Com2:" For Binary As #1
'It is important since UDRE interrupt is used that you enable the interrupts
Enable Interrupts
Print #1 , "Hello world"
Do
Waitms 100
'notice that using the UDRE interrupt will slown down execution of waiting loops like waitms
set portb.7
for bk = 1 to 25
Print #1 ,bk; " 123456789"
next
reset portb.7
Loop
End
Close #1
|
You see that I print 25 groups of about 10 characters, and set and reset a port pin around the entire print. That gives me a way of measuring the exact time interval taken by the routine.
But when I run this, the time interval is the same with and without buffering, just under 40 msec.
I would have hoped that with buffering it should be much shorter.
Maybe I am missing something simple, or not understanding what the output buffering is intended to do ?
(BASCOM-AVR version : 2.0.7.8 ) _________________ Adrian Jansen
Computer language is a framework for creativity |
|
Back to top |
|
|
for_ro
Joined: 11 Nov 2007 Posts: 260
|
Posted: Sat May 16, 2015 11:44 am Post subject: |
|
|
Hi Adrian,
be aware, that you are printing 13 respectively 14 chars each loop, so your buffer will be filled.
But even with this I see a difference in the period of PortB.7. Without buffering, the high time is 88ms,
with buffering only 23ms.
The difference will become mor obvious, if you place the PortB.7 commands inside the loop.
Regards
Rolf |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Sat May 16, 2015 12:29 pm Post subject: Re: Buffered serial output timimg |
|
|
AdrianJ wrote: | I reposted this to the main group, having verified that the behaviour is still the same under Bascom version 2.0.7.8 |
You have a whole bunch of different issues here.
First, you may have not noticed, that you have to tell the compiler, which baud rate to use.
Here the second UART is used, so it's not $baud, instead $baud1.
As well the compiler did create the USART1-empty interrupt-vector, as a side effect of the missing baud-rate the interrupt was not enabled.
Which gave of course always the same results.
Second, this implicates:
Quote: | You see that I print 25 groups of about 10 characters, and set and reset a port pin around the entire print. That gives me a way of measuring the exact time interval taken by the routine. |
you're sending somewhat of 250 chars, which is not true, you're sending 316 chars. As an effect you fill up the serial buffer till it holds 250 chars, and then you have still to wait, till the serialout ISR sends one char to empty the buffer for having space for another char. Means, as soon the buffer filled up, any more prints work blocking.
Third, if you would have calculated the time to send out the chars:
Quote: | But when I run this, the time interval is the same with and without buffering, just under 40 msec. |
you would have noticed, that 40 msec is impossible for the unbuffered print, 38400 baud is 3840 chars/sec (1start-, 8 data-, 1stop-bit).
316 chars divided by 3840 is 82msec, this should have gotten your attention.
Fourth, the buffered print also creates some overhead, for example reduce the loop to 19, then you send 238 chars, which fits into the buffer.
This takes according AVR-S4's simulator 23 ms. These 238 chars in a blocking print would take 62 ms. |
|
Back to top |
|
|
AdrianJ
Joined: 16 Jan 2006 Posts: 2483 Location: Queensland
|
Posted: Sun May 17, 2015 12:10 am Post subject: |
|
|
Thanks guys,
Been working on another part of this project too hard. Once I fixed those obvious errors, it behaves as expected.
Now to see if I can shorten it down a bit more, 23 ms is still a bit longer than I want to wait - some critical timing issues here.
But I did notice that if I take out printing the value of bk from the loop, the print is *very* much faster.
Using
Code: |
for bk = 1 to 20
Print#1,"123456789"
next
|
Gives me a loop time of just over 5 msec
That is much better, and in fact I print from a byte array:
Code: |
dim bk as byte
dim bSnap(80) as Byte
config portb.7 = output
'setup to use a serial output buffer
'and reserve 250 bytes for the buffer
Config Serialout1 = Buffered , Size = 250
Open "Com2:" For Binary As #1
for bk = 1 to 80 'fill byte array with something
bSnap(bk) = bk
next
'It is important since UDRE interrupt is used that you enable the interrupts
Enable Interrupts
Print #1 , "Hello world"
Do
Waitms 100
'notice that using the UDRE interrupt will slown down execution of waiting loops like waitms
set portb.7
for bk = 1 to 3
Printbin #1, bSnap(1);80
next
reset portb.7
Loop
End
|
That gives me about 4.8 msec for the loop time and about 60 msec for the actual data to go out the buffer, a big improvement. _________________ Adrian Jansen
Computer language is a framework for creativity |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Sun May 17, 2015 1:05 pm Post subject: |
|
|
AdrianJ wrote: | But I did notice that if I take out printing the value of bk from the loop, the print is *very* much faster. |
It takes time to convert the binary value to ascii and assemble the string.
Code: | for bk = 1 to 3
Printbin #1, bSnap(1);80
next |
Quote: | That gives me about 4.8 msec for the loop time and about 60 msec for the actual data to go out the buffer, a big improvement. |
Sure? if you describe with "loop time" one single loop run, then 3 single runs of 4.8ms won't be 60ms.
62ms would be the time it takes for unbuffered sending of 240 bytes.
Notice, that as soon the printed values go to the buffer, the buffered ISR will start to send out, which takes extra time and prolongs the loop.
In case:
a) the time within the loop is of highest priority for you
b) you have more time after the loop
c) you can make sure, that you don't overload the buffer
it may work to disable the UDRE interrupt before printing and enable it after.
For the second UART:
Code: | Reset UCSR1B.UDRIE1
' print ...
Set UCSR1B.UDRIE1 |
Be careful, if you overfill the buffer within the loop, print blocks and as the buffer won't get emptied, normal code execution, beside running ISR's, is ended. |
|
Back to top |
|
|
AdrianJ
Joined: 16 Jan 2006 Posts: 2483 Location: Queensland
|
Posted: Sun May 17, 2015 11:35 pm Post subject: |
|
|
Quote: | Sure? if you describe with "loop time" one single loop run, then 3 single runs of 4.8ms won't be 60ms.
62ms would be the time it takes for unbuffered sending of 240 bytes.
|
What I mean is that the processor time between the set and reset of portb.7 is now 4.8 msec.
I set up what I posted initially just as a quick and dirty method of testing that serial output buffering worked as intended.
Your other comments are useful, but I have already addressed them in how I plan to use this.
I need to transmit only a max of 80 bytes, then there will be automatically a delay of around 200 msec before the next data frame is transmitted. But within that total cycle time, I need to receive stuff from another serial port, and do some processsing on it. What was happening without the serial output buffering is that I ran out of time for processing, and the other input buffer was overflowed.
Thanks for your input. Problem solved. _________________ Adrian Jansen
Computer language is a framework for creativity |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You cannot download files in this forum
|
|