AVRTools icon indicating copy to clipboard operation
AVRTools copied to clipboard

Serial Output using Print() and Println() functions

Open Cjkeenan opened this issue 4 years ago • 8 comments

So I am trying to output to a serial port using the Serial0 class, and while the write() method works perfectly, but I am trying to use the print() and println() methods and they do not work for me.

I began tracing the functions used in that call, specifically if I called Serial0::println(1) it references Writer::println(int n, int base) which references Writer::print(int n, int base, bool nl) which references Writer::write(char* str, bool nl) which references Writer::write(char* str) which simply and only returns 0 per the writer.cpp file.

  1. I have a question about why that write function along with all of the other write functions only return 0. The functions I am talking about are the ones located in lines 36-67 of writer.cpp.

  2. I also am wondering about why the function Writer::println(int, int base, bool nl) returns with a function call to Writer::write(char* str, bool nl) versus the Writer::write(int n, int base, bool nl).

Sorry if this was confusing and let me know if you wish to have any more details such as my specific source code I am running.

Cjkeenan avatar Mar 07 '20 06:03 Cjkeenan

Hi,

I don't see or experience any problems, so please send me a MINIMAL executable example demonstrating the problem. Please include the output you see and explain how what you see differs from what you expect. Often the process of creating such a minimal executable example of the problem will lead you to figuring out what was wrong or finding a bug in your own code.

Some explanation to help your understanding of the code:

Serial0::println(1) calls Writer::print( 1, kDec, true ), which is specifically one of the functions Writer::print( XXX n, int base, bool addLn ) where XXX is one of int8_t, int, or long.

These three functions convert a integer number (e.g., 1234) into its corresponding string representation ("1234") via a call to the function printNumber(). The function printNumber() creates that string representation of the number and outputs the string representation to the Serial port via the virtual function write( const char* str ) declared in base class Writer in Writer.h. In this case, the virtual function actually called is implemented by Serial0::write( const char* str ), which in turn calls USART0::write( const char* c ) to actually output the string to USART0.

USART0::write( const char* c ) returns the number of characters it writes to USART0, which is then returned up the call chain by all the calling functions. USART0::write( const char* c ) specifically does not return 0.

So per your questions:

(1) Your observation is incorrect: The functions located in lines 36-67 of Writer.cpp are NOT the actual functions called. These are virtual functions and as the the comments in them indicate, they are stubs never to be called. The actual implementations are in the derived classes.

(2) Your question makes no sense: there is NO function Writer::write(int n, int base, bool nl). Nor is there a function Writer::write(char* str, bool nl). The sequence of calls is explained above.

Again, if it "does not work" for you, you need to explain what you mean by "not work" and provide a minimal example that I can execute to reproduce the problem you have observed. By minimal I mean something like:

// Include whatever header files you need to make your example code compile

#include "AVRTools/ArduinoPins.h"
#include "AVRTools/InitSystem.h"
#include "AVRTools/USART0.h"
#include [whatever other headers you need]

int main()
{
    initSystem();

    Serial0 s;

    s.start( 9600 );
    // You'll probably need to insert a delay to give USART0 hardware time to initialize/stabilize
    // before you try to output anything to USART0

    s.println( 1 );

    // I uploaded this code to an Arduino Uno and I connected a serial terminal to USART0
    // I opened the serial terminal causing the Arduino to reset and execute the code above
    // I expected to serial terminal to receive the text string "1" following by a carriage return
    // Instead the serial terminal received the text string "Boo!" and no following carriage return
}

igormiktor avatar Mar 07 '20 17:03 igormiktor

The following code works 100% for me on both an Arduino Uno and an Arduino Mega 2560.

#include "AVRTools/InitSystem.h"
#include "AVRTools/SystemClock.h"
#include "AVRTools/USART0.h"

int main()
{
    initSystem();
    initSystemClock();

    Serial0 s;

    s.start( 38400 );

    delayMilliseconds( 2000 );

    USART0::write( "\n\nUSART0 test\n" );

    s.write( "\n\nwrite() test\n" );
    s.write( '1' );
    s.write( '\n' );
    s.write( "write() done\n" );

    s.println( "\n\nprintln() test" );
    s.println( 1 );
    s.println( "println() done" );

    int i = 0;
    s.println();
    while ( 1 )
    {
        delayMilliseconds( 1000 );
        s.println( i++ );
    }
}

It produces the following output on my serial terminal connected to USART0:

␊
␊
USART0 test␊
␊
␊
write() test␊
1␊
write() done␊
␊
␊
println() test␊
1␊
println() done␊
␊
0␊
1␊
2␊
3␊
4␊
5␊
6␊
7␊
8␊

igormiktor avatar Mar 07 '20 20:03 igormiktor

First of all, thank you so much for the quick response, so I ran your code and it is still giving me issues. I am coding in MPLAB X IDE v5.30 with the AVR GCC v 5.4.0 compiler included in the XC8 compiler and I get this output from the Arduino Mega's USB port connect to my laptop using TeraTerm with a Baud Rate of 38400:

1
 &/)òþÿÿ
        1
         println() done

                       0
                        1
                         2
                          3
                           4

Cjkeenan avatar Mar 14 '20 02:03 Cjkeenan

Hi,

Is that the complete output? Seeing the complete output is helpful, so I can see exactly what the USART0::write() and the s.write() tests produced. Also, does TeraTerm have an option to show the "invisibles" (the output I showed you above shows the LF bytes). Or if not, can TeraTerm display raw byte values and could you send those to me please.

Clearly something weird is happening, but I am not sure yet what it is. Seems to be a combination of things. Some observations, all PRELIMINARY at this stage:

  • The move to the right of each line of output seems to simply be misinterpretation of the "LF" from a unix-style (AVRTools assumption) to Windows (your TeraTerm). If true, that's of no consequence and might even be fixable by a setting option in TeraTerm.

  • Completely confused why one line is gibberish ("&/)òþÿÿ") and others following it correct. The code is really boring, vanilla stuff so if one works the other should too (and vice versa).

  • All the print() and write() functions at the end "output" to the USART hardware using USART0::write() so if that function is working 100%, the only part of the code that talks to actual hardware is working. The rest of the code is "generic" and not dependent on hardware, so can be tested outside of an AVR processor.

  • GCC 5.4.0 is pretty old. I've been using GCC 7.4, and some older versions had some serious codegen bugs on AVR. But I can’t recall which versions had those problems. Any chance you can try a more modern GCC version?

I'll stand-by for a complete output and hopefully a dump of the raw byte values (“hex dump") that came over the serial line. Meantime I'll keep thinking about what might be going wrong...

igormiktor avatar Mar 14 '20 13:03 igormiktor

Yes, that is the complete output, and that is why it is so confusing, the random characters remind me of an incorrect baud rate at the beginning but then it magically gets fixed. I am downloading AVR-GCC 9.2.0 and going to try that. The reason it is taking so long between comments btw, is that I do not have easy access to the hardware. Also the move to the right after each line is because there is no carriage return printed (\r), not sure if that is a Windows vs Unix thing or not, but that would fix those extra spaces.

Cjkeenan avatar Mar 14 '20 18:03 Cjkeenan

I spent a while installing MPLAB X IDE v5.35 (<-- note minor version difference). Took me a while to figure it out (OT: it's a sucky piece of software ;). I connected it up to my avr-gcc 7.4.0. Moved all the code over, and built and uploaded the resulting hex file to a Arduino Uno (ATmega328p). I got the correct output:

<0xe0> <0xe0> <0x1c><0x1c><0x1c><0xe0><0x1c> <0xe0><0x1c><0x1c><0xe0><0xe0><0xe0><0x1c><0xe0><0xe0><0xe0><0x1c>␊ ␊ USART0 test␊ ␊ ␊ write() test␊ 1␊ write() done␊ ␊ ␊ println() test␊ 1␊ println() done␊ ␊ 0␊ 1␊ 2␊ 3␊ 4␊ 5␊ 6␊ 7␊ 8␊ 9␊ 10␊ 11␊ 12␊

Note that the stuff at the top is purely connection noise and/or Arduino reboot stuff. So you can disregard that.

So I am rather perplexed. It could be the GCC version. The fact that the "beginning" of your output is missing (e.g, the stuff related to the USART0::write( "\n\nUSART0 test\n" ); call) also makes me wonder if your TeraTerm is perhaps screwy or somehow not initiating the connection quickly enough or correctly.

Any chance you could try a different serial terminal program?

igormiktor avatar Mar 14 '20 19:03 igormiktor

The move to the right is definitely the missing \r (which is a Windows thing: Linux \n means a real new line; Windows interprets \n as "drop one line but stay where you are", so requires the stupid \n\r combo). There should be an option in TeraTerm to interpret \n as \n\r as most devices you connect to via serial will use \n (and not \n\r) for a new line.

igormiktor avatar Mar 14 '20 19:03 igormiktor

Ideas to experiment with (even if they don't work, we'll get some insight):

  • Add more delay after s.start( 38400 ); maybe 5 or 10 seconds just to make sure it is not a terminal handshake thing.
  • If the above still doesn't work, after the 5-10 seconds delay, add the line USART::write( "Junk\n\n" ); then delay again 5 seconds, then continue with the rest of the code. Want to see if maybe it takes some data pushed down the line to allow it to synch?
  • Try a different terminal program than TeraTerm
  • Try different baud rates
  • Try from a linux system instead of Windows

Let me know what happens.

BTW, I've been doing everything from a Linux system (don't have any WIndows machines, so can't test that, sorry!)

igormiktor avatar Mar 14 '20 20:03 igormiktor