CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

What is faster - several putc or printf?

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
40inD



Joined: 30 Jul 2007
Posts: 112
Location: Moscow, Russia

View user's profile Send private message

What is faster - several putc or printf?
PostPosted: Thu Apr 13, 2017 2:10 am     Reply with quote

I need to minimize conversion time before sending data by serial port.
I have 3 int16 variables A, B, C
So, which code will be faster?:
Code:

      putc(make8(A,1));
      putc(make8(A,0));
     
      putc(make8(B,1));
      putc(make8(B,0));
     
      putc(make8(C,1));
      putc(make8(C,0));
     // always sending 6 bytes

or
Code:

printf("%lu,%lu,%lu", A, B, C); // sending various amount of bytes

Also, in which case the total conversion+sendig time will be smaller?
(rate is 9600)
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Thu Apr 13, 2017 3:07 am     Reply with quote

In each case the next byte will be sent before the hardware buffer empties, so sending will be continuous.
The total time for the printf, will vary with the value.
Since in the first, there is no conversion time at all, and six bytes is the minimum the printf can generate (since you are adding commas), the putc will always be as fast or faster.

However big 'caveat'. What happens if the bus loses a bit?. Can the former ever recover?. With the latter you can test for the ',' and know where you are. With the former it'll only re-align if there is a gap in the data. In both cases it is unlikely you will 'know' if the data has gone wrong, but much more so, with the 'raw' data..

This is why anything sending 'raw' data like this, needs to have some way of testing if the data is valid before using it. So (for instance), pausing for at least one character time before sending (so the UART will know the next bit is the start of a character), and sending a seventh byte that is a checksum of the data before, and rejecting it all if this does not match. This way you can have reasonable confidence in the data...
40inD



Joined: 30 Jul 2007
Posts: 112
Location: Moscow, Russia

View user's profile Send private message

PostPosted: Thu Apr 13, 2017 3:33 am     Reply with quote

It is understood about CRC, CRC can be added as 4th variable or can be in vairable "C". I think about the common principle.
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Thu Apr 13, 2017 4:29 am     Reply with quote

When you print the raw data, you are sending 8 bits per byte transmitted.
When you print with decimal numbers, you are sending effectively 3 and a bit bits per byte transmitted (3.162bits). Send hex, and you send 4 bits per byte transmitted.
How many bytes may need to be sent, is inversely related to how many bits you send per byte. Sending in decimal, is the worst, and also since the processor can't simply perform /10 for the transmission, it is also bad in terms of work involved. The only reason ever to send in decimal, is because a human needs to be able to read it. Hex provides a slightly better 'compromise', more efficient maths, still human readable, more efficient use of the bits, and allowing other characters to be used as separators etc..
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Thu Apr 13, 2017 7:45 am     Reply with quote

Another way of thinking about it is that printf calls (or effectively has to) putc() for each characters transmitted. Therefore printf will always have greater overhead than putc. The flexible nature of printf tends to involve quite a lot of overhead.

With hardware UARTS, transmitting can easily be overlapped with formatting. At 9600 baud transmitting a character takes very roughly a millisecond. In general, at all but the slowest PIC clock rates, it takes very much less than than that time to format the next character, so printf is pretty much always going to have to spend a lot of time waiting for the previous character to be sent. So the overall time is generally dominated by the time taken to send, not format.

With software UARTs, formatting and sending cannot be done in parallel, so the times for both add up.

Sending anything other than single bytes always requires some form of formatting. On this forum we use a pretty complex protocol called the English Language. This allows us to know when sentences begin and end (using capital letters and full stops repectively) and to do simple error checking: "Eh? That didn't make sense!" and "That's not spelled correctly" and so on. English is a very complex and rich protocol however, and comms between computers must be much simpler. This has dominated the last fourty years or so of computer science, and has produced some very useful protocols, such as HTTP and TCP/IP on which this post, and all Internet traffic is based.

At it's very most basic, a protocol has to deal with a few simple problems: when does data start and end, how mcuh data is there, and, how do I know this data is correct? And even that last one is often ignored. If you send a series of single bytes, each is complete and easily identified, but if you read a stream of pair of bytes that went ...123123123..., how would you know if it was "12,31,23,12,31,23" or "x1,23,12,31,23"? Early, simple systems sometimes used timed gaps, e.g. sending "12 31 12 31 23" mwant something different from "x1 23 12 31 23" and so on. MODBUS RTU and ASCII uses this principle. Later protocols reserve certain characters for start and stop, sending something like <start char>123123123<stop char>. That way, the receiving end knows its got a whole message, and didn't, for whatever reason, start receiving part-way through a message.

One key issue is making sure the start and stop and any other special protocol characters do not occur in the data itself, as otherwise the receiver would still get confused occasionally. One way of dealing with that is to use another special character, often called an escape character to proceed special characters, including the escape character itself where they occur in the data. The receiving end strips the escapes out. This technique is called byte stuffing.

This sort of transmission protocol can be as simple or complex and sophisticated as you need it to be. It is the start of computer networking.

Personally, for int16s I'd be tempted to send them as four, and always foru hex digits (easy and quick to format) with a newline. to mark the end:

AB23<NL>
456E<NL> and so on.

The receiving end ignores anything until it receives a new line, then takes the next four characters as the 16 bit value, saving them if they are valid hex, have no extra characters, including whitespace, followed by a newline. Anything else is ignored. Five bytes sent per 16 bit value, and it's human-readable to boot, though not particularly human-friendly.
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Thu Apr 13, 2017 7:55 am     Reply with quote

However I have to add a 'gotcha' to this. Smile
The CCS printf, does a lot of it's decisions on formatting at 'compile time'. This is why a variable is not allowed as the formatting string for printf.
The plus to this is that if the formatting is simple (so would for instance just result in a putc), CCS is 'smart enough' to substitute this. So (for instance)

putc(val);

and

printf("%c", val);

will usually result in almost exactly the same code....

So the extra overhead in the example being given, is the extra of the divisions by 10, and the number of extra characters, rather than being caused by printf itself.

In this case, it is the extra characters that will be the really big expense. 65535, is going to take 6mSec+ to send (at 9600bps), while the two bytes will only take just over 2mSec. 3.16 significant bits per transmitted character (so 5 characters needed), for 16 bits, plus an extra marker character, versus just two bytes....

Agree wholeheartedly on hex. Key here is that since each received byte is a nibble, it is a 'doddle' for the receiving processor to decode, and still leaves you characters 'free' for formatting etc..

As another poster said in another recent thread, just increase the baud rate for faster performance.
40inD



Joined: 30 Jul 2007
Posts: 112
Location: Moscow, Russia

View user's profile Send private message

PostPosted: Tue Apr 25, 2017 5:52 am     Reply with quote

I can't increase the baud rate due to physical layer limitations. The goal was to minimize time spended for formatting data to send (and time to send too). Because PIC works almost in realtime.

So I chose the first variant.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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


Powered by phpBB © 2001, 2005 phpBB Group