Discussion Forum

Problems with putchar and putbuf in "Getting Started" and Traffic example

Next Thread | Thread List | Previous Thread Start a Thread | Settings

DetailsMessage
Read-Only
Author
Loren Amelang
Posted
7-Dec-2007 01:13 GMT
Toolset
None
New! Problems with putchar and putbuf in "Getting Started" and Traffic example

The main issue has been nicely explained in the C166 forum by the following post from Mike Kleshov:
A problem with serial IO in the 'Traffic' example:
<http://www.keil.com/forum/docs/thread2936.asp>

Briefly, the putbuf routine in the Traffic example code, and in the "Getting Started" manual's "interrupt-driven serial I/O" example, moves output characters to the output buffer if the hardware is busy, but sends them directly to the hardware if it is not busy. There is no way to ensure that the hardware state and TI interrupt will not change while putbuf is in the middle of this process. When that happens, the order of characters output to the serial port is swapped.

Had I not limited my searches to C51 posts while struggling with this nasty bug, _many_ hours would have been saved! Hopefully this post will alert C51 users who are having problems with putchar or printf and Keil's older suggested interrupt serial routines.

Replacing the putbuf code with a putchar modeled on the newer Keil examples in
<http://www.keil.com/download/files/intsio.zip>
or
<http://www.keil.com/download/files/intsio2.zip>
solved the last of the problems I was struggling with in my earlier post Persistent C51 printf curiosities.

The Traffic example also neglected to disable interrupts during critical parts of putchar and putbuf. The com_putchar in the intsio example disables interrupts explicitly. In intsio2 the "#pragma disable" statement, which appears to be unique to Keil, is used to disable interrupts. Without some attention to disabling interrupts, very strange output glitches can happen!

Another problem with the Traffic implementation was the "while (sendfull)" section of putchar. It appeared to provide a wait for space if the output buffer was full, but it didn't work, or at least printf didn't wait for it. About the same number of characters were dropped whether sendfull was set or not (but in different patterns). With our new serial code we still face an absolute speed limit on how many characters we can force through the serial hardware, and sometimes need to add delays between output items. But we are no longer under the illusion that printf should wait for buffer space.

The other breakthrough that made printf much less mysterious was adding a linker OVERLAY directive:

<http://www.keil.com/support/docs/805.htm>
-----
If there is memory used by the function, you should use the linker OVERLAY directive to remove the function from overlay analysis. For example:
[OVERLAY (PRINTF ! *, PUTCHAR ! *, PUTBUF ! *)]
This prevents memory used by this function from being overlaid. If this function calls other functions that are also used elsewhere in your program, you may need to exclude those functions from overlay analysis as well.
-----

<http://www.keil.com/support/docs/2042.htm>
-----
In µVision, enter [routine name] ! * in the Overlay field on the Linker Misc Tab of the Project Options dialog. This command removes [routine name] from overlay analysis. The memory used by [routine name] for local variables is not overlaid with that of other functions.
-----

For the Traffic serial routines, I put "printf ! *, putchar ! *, putbuf ! *" in the Project -> Options -> BL51 Misc -> Overlay box, and got less garbage. When I rewrote the serial routines and eliminated putbuf, to avoid linker warning 15 "putbuf not found" I had to remove it from that "linker control string".

Finally, if you have printf issues and haven't read the MAXARGS limitations of the C51 compiler, _immediately_ go read <http://www.keil.com/support/docs/867.htm>. The limitations are spooky because you can often seem to get away with more complex printfs - for awhile... And then some seemingly unrelated change will break one of your printfs...

Loren

Next Thread | Thread List | Previous Thread Start a Thread | Settings