UART from arduino to J21 pins and voltage reduction. Missing bytes.

Hello.

I have a project where I use a TX2 board with a high speed camera and a GPS module. I need to get the NMEA data from the GPS to the module, and for that I’m using UART. In between the GPS and the Jetson I use an arduino, the reason for this is because we were afraid the GPS could damage the Jetson board as its J21 pins can only handle 1.8V (or so what it would see).

My problem is that the Jetson doesnt recive all data (or is unable to handle it) correctly. But what it receives is at least correct. The issue is not with the arduino, as the serial monitor shows correct (and processed) NMEA.

I have tried both with minicom and GtkTerm, and written code in C. (I think raspberry pi example).

Thanks in advance.

Insight:

System drawing: https://i.imgur.com/OLvckdr.png
GtkTerm settings: https://i.imgur.com/jC5KvLE.png
NMEA on jetson (missing bytes) : https://i.imgur.com/srEyFEH.png
NMEA on PC serial monitor: https://i.imgur.com/k7Rrh4c.png

ARDUINO CODE: (A lot of it is commented out, only the bare necessity remains)

/*
  6-8-10
  Aaron Weiss
  SparkFun Electronics

  Example GPS Parser based off of arduiniana.org TinyGPS examples.

  Parses NMEA sentences from an EM406 running at 4800bps into readable
  values for latitude, longitude, elevation, date, time, course, and
  speed.

  For the SparkFun GPS Shield. Make sure the switch is set to DLINE.

  Once you get your longitude and latitude you can paste your
  coordinates from the terminal window into Google Maps. Here is the
  link for SparkFun's location.
  http://maps.google.com/maps?q=40.06477,+-105.20997

  Uses the NewSoftSerial library for serial communication with your GPS,
  so connect your GPS TX and RX pin to any digital pin on the Arduino,
  just be sure to define which pins you are using on the Arduino to
  communicate with the GPS module.
*/

// In order for this sketch to work, you will need to download
// NewSoftSerial and TinyGPS libraries from arduiniana.org and put them
// into the hardware->libraries folder in your ardiuno directory.
// Here are the lines of code that point to those libraries.
#include <SoftwareSerial.h>
#include <TinyGPS.h>

// Define which pins you will use on the Arduino to communicate with your
// GPS. In this case, the GPS module's TX pin will connect to the
// Arduino's RXPIN which is pin 3.
#define RXPIN 10
#define TXPIN 9
//Set this value equal to the baud rate of your GPS
#define GPSBAUD 9600

// Create an instance of the TinyGPS object
TinyGPS gps;
// Initialize the NewSoftSerial library to the pins you defined above
SoftwareSerial uart_gps(10, 11);

// This is where you declare prototypes for the functions that will be
// using the TinyGPS library.
void getgps(TinyGPS &gps);

// In the setup function, you need to initialize two serial ports; the
// standard hardware serial port (Serial()) to communicate with your
// terminal program an another serial port (NewSoftSerial()) for your
// GPS.
void setup()
{
  // This is the serial rate for your terminal program. It must be this
  // fast because we need to print everything before a new sentence
  // comes in. If you slow it down, the messages might not be valid and
  // you will likely get checksum errors.
  Serial.begin(115200);
  //Sets baud rate of your GPS
  uart_gps.begin(9600);

  Serial.println("");
  Serial.println("GPS Shield QuickStart Example Sketch v12");
  Serial.println("       ...waiting for lock...           ");
  Serial.println("");
}

// This is the main loop of the code. All it does is check for data on
// the RX pin of the ardiuno, makes sure the data is valid NMEA sentences,
// then jumps to the getgps() function.
void loop()
{
  while (uart_gps.available())    // While there is data on the RX pin...
  {

int c = uart_gps.read();    // load the data into a variable...

    Serial.write((char)c);
    if (gps.encode(c))     // if there is a new valid sentence...
    {
      //Serial.println(" gps.encode(c)");
      //Serial.println("");
      //getgps(gps);         // then grab the data.
    }
  }
}

// The getgps function will get and print the values we want.
void getgps(TinyGPS &gps)
{
  int year;
  byte month, day, hour, minute, second, hundredths;
  gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths);
  // Print data and time

  Serial.print("D");
  if (month < 10) {
    Serial.print(0, DEC);
  }
  Serial.print(month, DEC); Serial.print("/");
  if (day < 10) {
    Serial.print(0, DEC);
  }
  Serial.print(day, DEC); Serial.print("/"); Serial.print(year);
  Serial.print("T");
  if (hour < 10) {
    Serial.print(0, DEC);
  }
  Serial.print(hour, DEC); Serial.print(":");
  if (minute < 10) {
    Serial.print(0, DEC);
  }
  Serial.print(minute, DEC); Serial.print(":");
  if (second < 10) {
    Serial.print(0, DEC);
  }
  Serial.print(second, DEC); Serial.print(".");
  if (hundredths < 10) {
    Serial.print(0, DEC);
  }
  Serial.println(hundredths, DEC);
}

C code on jetson.

#include <stdio.h>
#include <unistd.h> 	//Used for UART
#include <fcntl.h> 		//Used for UART
#include <termios.h>	//Used for UART

int main()
{

	//-------------------------
	//----- SETUP USART 0 -----
	//-------------------------
	//At bootup, pins 8 and 10 are already set to UART0_TXD, UART0_RXD (ie the alt0 function) respectively
	int uart0_filestream = -1;
	
	//OPEN THE UART
	//The flags (defined in fcntl.h):
	//	Access modes (use 1 of these):
	//		O_RDONLY - Open for reading only.
	//		O_RDWR - Open for reading and writing.
	//		O_WRONLY - Open for writing only.
	//
	//	O_NDELAY / O_NONBLOCK (same function) - Enables nonblocking mode. When set read requests on the file can return immediately with a failure status
	//											if there is no input immediately available (instead of blocking). Likewise, write requests can also return
	//											immediately with a failure status if the output can't be written immediately.
	//
	//	O_NOCTTY - When set and path identifies a terminal device, open() shall not cause the terminal device to become the controlling terminal for the process.
	uart0_filestream = open("/dev/ttyS0", O_RDONLY | O_NOCTTY | O_NDELAY);		//Open in non blocking read/write mode
	if (uart0_filestream == -1)
	{
		//ERROR - CAN'T OPEN SERIAL PORT
		printf("Error - Unable to open UART.  Ensure it is not in use by another application\n");
	}
	
	//CONFIGURE THE UART
	//The flags (defined in /usr/include/termios.h - see http://pubs.opengroup.org/onlinepubs/007908799/xsh/termios.h.html):
	//	Baud rate:- B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000, B2500000, B3000000, B3500000, B4000000
	//	CSIZE:- CS5, CS6, CS7, CS8
	//	CLOCAL - Ignore modem status lines
	//	CREAD - Enable receiver
	//	IGNPAR = Ignore characters with parity errors
	//	ICRNL - Map CR to NL on input (Use for ASCII comms where you want to auto correct end of line characters - don't use for bianry comms!)
	//	PARENB - Parity enable
	//	PARODD - Odd parity (else even)
	struct termios options;
	tcgetattr(uart0_filestream, &options);
	cfsetispeed(&options, B115200);
	cfsetospeed(&options, B115200);
	options.c_cflag = B115200 | CS8 | CLOCAL | CREAD;		//<Set baud rate
	options.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
	options.c_oflag = 0;
	options.c_lflag = 0;
	tcflush(uart0_filestream, TCIFLUSH);
	tcsetattr(uart0_filestream, TCSANOW, &options);

	
	//----- CHECK FOR ANY RX BYTES -----
	while (uart0_filestream != -1)
	{
		// Read up to 255 characters from the port if they are there
		unsigned char rx_buffer[256];
		int rx_length = read(uart0_filestream, (void*)rx_buffer, 255);		//Filestream, buffer to store in, number of bytes to read (max)
		if (rx_length < 0)
		{
			//perror("read");
			//An error occured (will occur if there are no bytes)
		}
		else if (rx_length == 0)
		{
			perror("nodata \n");
			//No data waiting
		}
		else
		{
			//Bytes received
			rx_buffer[rx_length] = '

#include <stdio.h>
#include <unistd.h> //Used for UART
#include <fcntl.h> //Used for UART
#include <termios.h> //Used for UART

int main()
{

//-------------------------
//----- SETUP USART 0 -----
//-------------------------
//At bootup, pins 8 and 10 are already set to UART0_TXD, UART0_RXD (ie the alt0 function) respectively
int uart0_filestream = -1;

//OPEN THE UART
//The flags (defined in fcntl.h):
//	Access modes (use 1 of these):
//		O_RDONLY - Open for reading only.
//		O_RDWR - Open for reading and writing.
//		O_WRONLY - Open for writing only.
//
//	O_NDELAY / O_NONBLOCK (same function) - Enables nonblocking mode. When set read requests on the file can return immediately with a failure status
//											if there is no input immediately available (instead of blocking). Likewise, write requests can also return
//											immediately with a failure status if the output can't be written immediately.
//
//	O_NOCTTY - When set and path identifies a terminal device, open() shall not cause the terminal device to become the controlling terminal for the process.
uart0_filestream = open("/dev/ttyS0", O_RDONLY | O_NOCTTY | O_NDELAY);		//Open in non blocking read/write mode
if (uart0_filestream == -1)
{
	//ERROR - CAN'T OPEN SERIAL PORT
	printf("Error - Unable to open UART.  Ensure it is not in use by another application\n");
}

//CONFIGURE THE UART
//The flags (defined in /usr/include/termios.h - see http://pubs.opengroup.org/onlinepubs/007908799/xsh/termios.h.html):
//	Baud rate:- B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000, B2500000, B3000000, B3500000, B4000000
//	CSIZE:- CS5, CS6, CS7, CS8
//	CLOCAL - Ignore modem status lines
//	CREAD - Enable receiver
//	IGNPAR = Ignore characters with parity errors
//	ICRNL - Map CR to NL on input (Use for ASCII comms where you want to auto correct end of line characters - don't use for bianry comms!)
//	PARENB - Parity enable
//	PARODD - Odd parity (else even)
struct termios options;
tcgetattr(uart0_filestream, &options);
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
options.c_cflag = B115200 | CS8 | CLOCAL | CREAD;		//<Set baud rate
options.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_oflag = 0;
options.c_lflag = 0;
tcflush(uart0_filestream, TCIFLUSH);
tcsetattr(uart0_filestream, TCSANOW, &options);


//----- CHECK FOR ANY RX BYTES -----
while (uart0_filestream != -1)
{
	// Read up to 255 characters from the port if they are there
	unsigned char rx_buffer[256];
	int rx_length = read(uart0_filestream, (void*)rx_buffer, 255);		//Filestream, buffer to store in, number of bytes to read (max)
	if (rx_length < 0)
	{
		//perror("read");
		//An error occured (will occur if there are no bytes)
	}
	else if (rx_length == 0)
	{
		perror("nodata \n");
		//No data waiting
	}
	else
	{
		//Bytes received
		rx_buffer[rx_length] = '\0';
		printf("%i bytes read : %s\n", rx_length, rx_buffer);
	}
}

//----- CLOSE THE UART -----
close(uart0_filestream);

return 0;

}

';
			printf("%i bytes read : %s\n", rx_length, rx_buffer);
		}
	}
	
	//----- CLOSE THE UART -----
	close(uart0_filestream);
	
	return 0;
}

Tested with raspberry pi as receiver instead of the jetson. It periodically lost bytes, for 10 seconds it got everything, the next 10 seconds there were missing bytes and so on (10 seconds just as an example, not that consistant).

I have also tried with a volt regulator, but no luck.

I have tried different settings, with parity bits and stop bits, but they yield no different results.

My first comment would be Linux has great support for uBlox GPS devices, I would investigate using your ublox module and cut out the Arduino, this allows you to use GPSD https://en.wikipedia.org/wiki/Gpsd and all the lovely benefits it gives you.

But you might not want that, you might want to have your Arduino doing the parsing, as you say, you’re concerned about the electronics…

Regarding the Arduino, my suggestion would be to assemble and build up a string then call Serial.print/println(…) once, rather than call Serial.print several times to print 2-3 characters at a time. Calling Serial.print(…) is slow and its perhaps more manageable to build up a String and call it once, that may explain the missing bytes.

Thanks for the reply!

Made the changes to the arduino code, so that instead of Serial print, I build up a string, but still there are missing bytes.

I should get “D04/18/2018T11:53:24.00*”, I instead get “0/821T14:80*” and also instead of new lines:

"D04/18/2018T11:53:24.00*"
"D04/18/2018T11:53:25.00*"
"D04/18/2018T11:53:26.00*"

I get new lines and tabs:

0/821T14:80*
                   0/821T14:80*
                                          0/821T14:80*

I dont know if maybe the arduino is at fault or not, but I do receive the correct string when using USB from arduino to PC with serial monitor.

I’ll probably just end up using the gps directly to the jetson board, its not crucial to use the arduino.

One thought, it may not be an issue but I wouldn’t use the ‘/’ (slash) character to separate numbers when you call Serial.Print(…).

I would also clear your buffer after you print it, in case your buffer read length varies.

J21 is level translated to 3.3V, but the UART on J21 is also used by the serial console, so not useful for GPS input.
Instead, use J17. It is also level translated to 3.3V.

FYI, J21 and J17 on the dev carrier board are 3.3V (there are places it is 1.8V, e.g., the camera socket, but when exposed on the headers this is 3.3V).

In cases where speed goes up and bytes are lost you can improve reliability with two stop bits.

Ok, I’ll change that, its not important for the string either way :)

Thank you, this is good to know!

Maybe a dumb question, but with J21 I use /dev/ttyS0 to access the data received, is it the same for J17?

Anyway, thanks a lot for replying! Appreciated!

I can’t remember what J17 is, but try /dev/ttyS1 (I can’t remember) - when in doubt, trial and error!

Will try as soon as I get back home. Thanks!

Words I can live by.

J21 is a logged in session…serial console…"/dev/ttyS0". J17 is “/dev/ttyTHS2”.

I’m gonna mark this as answer, since credit goes to multiple people:

Thanks to: linuxdev, david_evans_g and snarky

First off. I tried to do the patch thing to enable THS2, but no luck, had to flash. This lead me to flash to the newest version of jetpack, were THS2 were enabled by default.

After that I had to try to find the RX pin, and after looking back and forth through forums and user guides, I was left to try and see. And after finding the pin and launching minicom, it worked! All beautiful bytes were present. This worked with the arduino, and with the gps wired directly to the jetson board.

Thank you guys so much for the help.

TL;DR Updated to newest jetpack, flashed, hooked the GPS to J17 and voila.

J17:
[O]-GND
[O]
[O]
[O]-RX
[O]
[O]

The pinout is documented in the module carrier board data sheet in the download section.

Are you referencing: "Jetson TX1-TX2 Developer Kit Carrier Board BOM "? I haven’t got to read it through, but I was reading about the pins there. Unfortunatly I do not know where any of the pins mentioned(Ex. A30, C12 etx) is located on the board, and I wasn’t able to find it either, as I’m not quite sure what I’m even looking for.

Sidenote:
If I’m going to use the jetson in another project at some time, I will probably sit down and set aside more time to actually learn the board.

The pins of format for a row/column (e.g., “A30” or “C12”) are from the module connector itself.