Page 1 of 2

Two devices connected to a single UART

Posted: Sat Mar 01, 2014 1:26 am
by FiddlerJones
Hi!

As I explained in some of my previous cry for help posts, my project is an high altitude balloon flight.

I connected the BMP085 sensor via I²C, the Adafruit Ultimate GPS via USB with an USB to UART bridge (CP2102, borrowed from a friend), and the NTX2 radio telemetry via UART.

Now, I'd like to connect the GPS via UART too (to save weight and easier testing), so, I'd like to connect two devices to a single port capable to manage only one. That could seem a problem without solution, but... From the GPS I only need to read data (therefore I only need the RX pin) and the NTX2 only need to send data (therefore I only need the TX pin). I've already tried to connect them one at a time and they work.
I connected the GPS only with the RX pin and I was able to read the data. Then I rebooted and connected the radio only with the TX pin, and I was able to send those data via radio.
Then I tried to connect them altogether... and it kinda worked... Briefly.
After a few data sent correctly, the software stops working, gives me some kind of error and quit.
Or, while is working, the character on the screen are replaced with something strange! I took a photo:

Image

N.B. I didn't change the code in the above tests, and I always had the GPS fix.
In the first two tests the software stopped with the "IndexError", in the last one something weird was coming out and I used ctrl+C to interrupt.
Then I tried to run the software for the last time and again the weird character appeared, but I didn't do anything this time and in a few seconds I had the "IndexError" again, plus, all the character on screen were sort of "corrupted", even the "pi@raspberrypi". Unfortunately I didn't take a photo.

Anyway, this is my code:

Code: Select all

import serial
import time
import crcmod

crc16f = crcmod.predefined.mkCrcFun('crc-ccitt-false')


def send(data):
	NTX2 = serial.Serial('/dev/ttyAMA0', 50, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_TWO) 
	NTX2.write(data)
	print data
	NTX2.close()


def read_gps():
	alt = 0
	ora = 0
	lat = 0
	lon = 0

	gps = serial.Serial('/dev/ttyAMA0', 9600, timeout=1)
	NMEA = gps.readline()
	gps.close()
	
	print "Lettura GPS ok"
	
	print NMEA
	data = NMEA.split(",")

	lat = data[2]
	northsouth = data[3]
	lon = data[4]
	westeast = data[5]
	alt = int(float(data[9]))
	ora = data[1]
	ora = float(ora)
	string = "%06i" % ora 
	hours = string[0:2]; minutes = string[2:4]; seconds = string[4:6]
	ora = str(hours) + ':' + str(minutes) + ':' + str(seconds)			
	return lat, lon, alt, ora

id = 0
while True:
	GPS = read_gps()
	lat = GPS[0]; lon = GPS[1]; alt = GPS[2]; ora = GPS[3]; temp=15 #temperatura di prova con BMP scollegato
	nome = "EOSO_TRY"
	stringa=str(nome + ',' + str(id) + ',' + str(lat) + ',' + str(lon) + ',' + str(alt) + ',' + str(temp))
	csum = str(hex(crc16f(stringa))).upper()[2:]
	csum = csum.zfill(4)
	dati = str("$$" + stringa + "*" + csum + "\n") 
	send(dati)
	id += 1
	time.sleep(1)
Reading the pySerial Api I found out that there is a function named "flush" that "Flush of file like objects. In this case, wait until all data is written", maybe using it will prevent the raspberry to go in such a confusion, I just have no idea how!

Any thoughts? Should I stop trying so hard and just buy my own USB to UART bridge instead?

Re: Two devices connected to a single UART

Posted: Sat Mar 01, 2014 2:39 am
by ame
Do you have ground connected to both devices?
i.e. GPS Tx -> Pi Rx, GPS GND -> Pi GND, Pi Tx -> NTX Rx, NTX GND -> Pi GND

Other than that, maybe your problem is caused by closing and opening the port often.

I think it's possible on some hardware to have different Rx and Tx baud rates (you are receiving at 9600bps and transmitting at 50bps), but I don't know if the Pi hardware supports it, or how to set up this configuration.

How about opening the port once
ser = serial.Serial('/dev/ttyAMA0')
and using
ser.baudrate = 50
ser.stopbits = 2
or
ser.baudrate = 9600
ser.stopbits=1

before you attempt to read or write to the port?

Or maybe try flushInput() and flushOutput() before reading or writing.

I am wondering if maybe this is happening:
GPS sends data all of the time. UART attempts to receive it and buffer it at the *previously selected baud rate*. If the last selected baud rate was 50, then the UART will get GPS data, but it will be horribly garbled. Without a flush, your program will read the contents of the UART buffer, some of which will be garbled characters.

Anyway, what you are trying to do seems perfectly reasonable, but you must think carefully about what is actually happening during the time the port is closed, and every time you reopen it with a different baud rate. You might want to pay close attention to the Tx pin to be sure you aren't keying the transmitter at these points in time.

I actually want this to work as it's an efficient use of hardware (and saves space and weight), plus a cool project.

Re: Two devices connected to a single UART

Posted: Sat Mar 01, 2014 4:08 am
by danjperron
The TX and RX are using the same clock. You can't have different baud rate.


But you could simulate serial transmission using pigpio on any gpio pin.

http://abyz.co.uk/rpi/pigpio/python.htm ... add_serial

Daniel

Re: Two devices connected to a single UART

Posted: Sat Mar 01, 2014 5:38 am
by ame
That is a great idea!

How about modifying it for two stop bits?

Re: Two devices connected to a single UART

Posted: Sun Mar 02, 2014 4:54 am
by danjperron
You don't need to modify the code. You could simulate also an extra stop bit by delaying the next characters for about one baud. I don't thing you will have a problem if you delay for more than one baud anyway.


Daniel

Re: Two devices connected to a single UART

Posted: Sun Mar 02, 2014 9:26 pm
by FiddlerJones
Ok, in order:

All GND pins are connected together.
I tried to open the port once and change the baudrate without closing it. Didn't work.
I tried "flushing" in every way and moment possible. Didn't work.
I tried setting the same baudrate for the two devices (9600). I know, the radio signal would have been incomprehensible, it was a test just to see if the software would'nt crash. It did. The problem is not the baudrate.
I also tried to add some sleep time in order to make the UART "rest". Didn't work.

I did not try to simulate an extra stop bit for the gps, because I have no idea how to code it, suggestion?

About simulating the UART on a generic GPIO: wouldn't that bring some timing issues? Anyway I will sure try it when I have some time.

P.s. here's the situation after a few tests, when the raspberry pi itself goes nuts:

Image

By the way, thank you all for the advice!

Re: Two devices connected to a single UART

Posted: Mon Mar 03, 2014 1:56 am
by ame
From the photo I can see something's not right (yes, thank you Captain Obvious). I would expect to see garbled characters in the serial strings received because of electrical interference or something, *but* the big giveaway is garbled characters in the Python error messages. These are generated internally and have not been sent across any sort of data link.

So, if you don't see this sort of thing with your hardware attached then your hardware is affecting the Pi's general operation somehow. I wonder if you are drawing too much current somewhere? Is your GPS configured for 3.3V signalling? The GPIO UART input will only accept 3.3V. Is the radio module input buffered somehow? The GPIO output is limited to a few milliamps.

Splitting the Tx and Rx is not the issue here (it's a good idea and it's do-able). There's something else going on.

Re: Two devices connected to a single UART

Posted: Mon Mar 03, 2014 3:07 am
by FiddlerJones
The garbled characters are in raspbian itself!

Anyway, as I said, the radio and the GPS works great individually, so the GPS works fine at 3.3V, it has an internal linear-drop out for when it's fed with higher voltages. It even has a clean 3.3V output.

The GPS draws about 20mA and so does the Radio. I don't think there's a problem here cause the max drainable current should be 50mA. But tests doesn't cost anything, so I will try to connect the GPS to the 5V pin (which shouldn't have the 50mA limit as it's almost directly connected to the USB power input) and see if that changes something. But that's a problem. I'm doing the "indoor" tests with a model B, but I will fly a model A hacked to run only on 3.3V, where the 5V and 3.3V lines are combined, of course I will bypass the current draw limit as the lines are combined, but I'm not sure if I'll cause damages or something as I don't know why there's the 50mA limit, and where I can find the component that bind the "normal" 3.3V line to 50mA (I don't see anything like a polyfuse in the schematics near the GPIO 3.3V line or even near the 3.3V RG2 output)
Anyway, I'll test the 5V thing out, and if it works, I'll test again on the model A crossing my fingers.

So, until now we understand that that's not a baudrate problem as when I even out the baudrates of the two devices, the problem was still there, and when I'm setting different baudrates for the devices the code actually works (briefly).

Re: Two devices connected to a single UART

Posted: Mon Mar 03, 2014 3:37 am
by jbeale
I have managed to get garbled characters out of the pi's serial port after using 'cat' to display a binary file. It might have been some control codes affecting my "PuTTY" terminal emulator that I was using to connect to the Pi.

Re: Two devices connected to a single UART

Posted: Mon Mar 03, 2014 4:39 am
by cleverca22
danjperron wrote:The TX and RX are using the same clock. You can't have different baud rate.


But you could simulate serial transmission using pigpio on any gpio pin.

http://abyz.co.uk/rpi/pigpio/python.htm ... add_serial

Daniel

But the pi does have 2 uarts in it
Due to how the traces are routed, both tx's and rx's lead to the same rx/tx pair on the header, which I normally consider a problem.

But in this case you could set rx to one uart and tx to the other, then it will act as two separate ports

Re: Two devices connected to a single UART

Posted: Mon Mar 03, 2014 5:25 am
by ame
cleverca22 wrote:
danjperron wrote:The TX and RX are using the same clock. You can't have different baud rate.


But you could simulate serial transmission using pigpio on any gpio pin.

http://abyz.co.uk/rpi/pigpio/python.htm ... add_serial

Daniel

But the pi does have 2 uarts in it
Due to how the traces are routed, both tx's and rx's lead to the same rx/tx pair on the header, which I normally consider a problem.

But in this case you could set rx to one uart and tx to the other, then it will act as two separate ports
That would work. What is the UART1 device name?

I still think there's a problem elsewhere though.

Re: Two devices connected to a single UART

Posted: Mon Mar 03, 2014 5:11 pm
by jojopi
The screen corruption is caused by printing a Ctrl+N (python -c 'print(chr(14))'). The console emulates a VT100 terminal, and that code invokes the G1 character set, which by default is DEC Special Graphics. In this set, lower-case letters are replaced by line drawing characters and other symbols. However, because the font being used on the Linux console may not provide all the DEC symbols, some letters are unchanged.

The command "reset" will fix the display.

The different baud rates is the (main) problem. Unless you can stop the GPS from transmitting while writing to the NTX2, the input buffer will fill with garbage. Even after you switch the rate back, the receiver may take time to resynchronise.

I do not think there are Linux drivers for the Mini UART, so you would have to access the hardware directly. It does not support two stop bits (or nine data, or stuck parity that you could use instead), and to use it as a receiver without interrupts you would need to empty the FIFO regularly.

So actually, big-banging the output using pigpio has the least timing difficulties. I believe you can add the extra stop bit just by spacing the characters 11 periods apart:

Code: Select all

dati = "hello world"
for i in range(len(dati)):
  pigpio.wave_add_serial(TX_GPIO, 50, 1000000/50*11*i, dati[i])
You need to decrease PI_WAVE_MIN_BAUD in pigpio.h before compiling. I have only been able to test down to 75 baud, because that is the limit of pl2303 USB UART I have.

Re: Two devices connected to a single UART

Posted: Tue Mar 04, 2014 12:40 am
by danjperron
Maybe is possible to compile a module for the first uart PL10. This way you could have ttyAMA1.

And then use the alternate pin configuration to get the RX of ttyAMA1 and the TX of ttyAMA0.

Re: Two devices connected to a single UART

Posted: Tue Mar 04, 2014 12:56 am
by cleverca22
drivers/tty/serial/Makefile
obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o

it looks like you can just enable the 2nd uart in 'make menuconfig' then set the alternate function of GPIO14 or GPIO15 to ALT5

http://elinux.org/RPi_BCM2835_GPIOs

GPIO14 can either be TXD0 or TXD1
and GPIO15 can either be RXD0 or RXD1

Re: Two devices connected to a single UART

Posted: Tue Mar 04, 2014 2:15 am
by jojopi
I am not convinced the Mini UART is a pl010.

Even if there is an upstream driver that is roughly compatible, it would need to be given Pi-specific details such as the register base address and where the clock comes from. And the fact that it shares AUXIRQ with two of the SPI modules (not the one there is a driver for, I think).

Although enabling both UARTs is the most elegant solution, I doubt it is worth the effort when it can only help people in unusual unidirectional cases.

Re: Two devices connected to a single UART

Posted: Tue Mar 04, 2014 2:24 am
by danjperron
Yes this why I prefer the first method I posted. The pigpio.

But it is always good to find other approach. Even if they are worst.

Another solution will be the usb to serial adapter. Adafruit have one version with ttl output.

Re: Two devices connected to a single UART

Posted: Tue Mar 04, 2014 2:40 am
by ame
danjperron wrote:Yes this why I prefer the first method I posted. The pigpio.

Bug it is always good to find other approach. Even if they are worst.

Another solution will be the usb to serial adapter. Adafruit have one version with ttl output.
pigpio is a good solution as it requires no extra hardware. An adapter will add some weight, and it looks like weight saving is important in this project. This has been a very interesting discussion.

Re: Two devices connected to a single UART

Posted: Tue Mar 04, 2014 2:50 am
by FiddlerJones
I succeeded transmitting the data from a generic GPIO pin with the pigpio library. I had some timing issues with the baudrate set to 50, or 75, or 100, or 110, or 150, or 200 (I couldn't even hear the RTTY on the radio). Fortunately at 300 baud worked great and I was able to decode it with Fldigi.
I set Fldigi for just one stop bit, so I didn't need to simulate the second stop bit when transmitting. The transmission was ok, but I kept losing a few packets (no idea why). So I tried the solution to simulate two stop bits suggested by jojopi and it worked great!

Anyway, when I have some time I'll test some solution with the UART anyway. I still don't get why, if the problem is the baudrate, when I set the two devices at the same baud the problem persists. There's no way at all to clear the RX buffer? I'm gonna try switching the baudrate to 9600 right after the transmission and wait a few seconds more, hoping the buffer would cleans itself. I'll even try to wait some minutes, to see if the buffer is the problem.
It's a matter of curiosity, and after all 50 baud from the UART is more reliable... If it is stable of course.

P.s. the USB to TTL works, I already tried one. But it weights more and occupies the only USB input, which I was planning to use for another camera.

Re: Two devices connected to a single UART

Posted: Tue Mar 04, 2014 3:03 am
by danjperron
Perfect problem solved!

Just in case,

Did you kill the tty console /dev/ttyAMA0 in the /etc/inittab (last line)?
Did you remove it also from the /boot/cmdline.txt?

Maybe the garbage you have sometimes are from the debug console?

Re: Two devices connected to a single UART

Posted: Wed Mar 05, 2014 12:07 am
by FiddlerJones
Yes of course I killed those processes.

Anyway, here's a quick update of what I've done:
- Connected the GPS to the 5V pin. Did not work, it isn't a power supply problem.
- Switched to 9600 baud right after the transmission and add some extra sleep time. It went a little better, but the software crashed anyway, just less often. It didn't work though.
- Even out the baudrate. Like above, less crash, but crashed anyway.
- Even out the baudrate, the parity, the stop bit and everything else, opening the port just once. The software finally wasn't crashing, though the data from the NTX2 were undecodable.

The problem is not only the baudrate. Opening and closing so often the port also makes the Pi goes mad.
But I figured that I don't care if some of the RX data are garbled, I can just ignore those and focus on the actual data. The python error I got was because the data returned by the function was not formatted in the way the software expected them to be.
So I changed the code:

Code: Select all

import serial, time, crcmod

crc16f = crcmod.predefined.mkCrcFun('crc-ccitt-false')
id=0

def send(data):
   NTX2 = serial.Serial('/dev/ttyAMA0', 50, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_TWO) 
   NTX2.flush()
   time.sleep(0.5)
   NTX2.write(data)
   NTX2.close()
   print data
   NTX2 = serial.Serial('/dev/ttyAMA0', 9600, timeout=1)
   NTX2.flush()


def read_gps():
   gps = serial.Serial('/dev/ttyAMA0', 9600, timeout=1)
   gps.flush()
   NMEA = gps.readline()
   gps.close()
   data = NMEA.split(",")

   if (NMEA.startswith("$GPGGA")):
      lat = data[2]
      northsouth = data[3]
      lon = data[4]
      westeast = data[5]
      alt = int(float(data[9]))
      ora = data[1]
      ora = float(ora)
      string = "%06i" % ora 
      hours = string[0:2]; minutes = string[2:4]; seconds = string[4:6]
      ora = str(hours) + ':' + str(minutes) + ':' + str(seconds)         
      return lat, lon, alt, ora
   
   else:
      return 0, 0, 0, 0


while True:
   while True:
      GPS = read_gps()
      lat = GPS[0]; lon = GPS[1]; alt = GPS[2]; ora = GPS[3]; temp=15
      if lat==0 and lon==0 and alt==0 and ora==0:
         break
      
      else:  
         nome = "EOSO_TRY"
         stringa=str(nome + ',' + str(id) + ',' + str(lat) + ',' + str(lon) + ',' + str(alt) + ',' + str(temp))
         csum = str(hex(crc16f(stringa))).upper()[2:]
         csum = csum.zfill(4)
         dati = str("$$" + stringa + "*" + csum + "\n") 
         send(dati)
         id += 1
         print ora
      
      time.sleep(1)
And... Yes! It worked!
Only if the RX data are in the correct format they can get out of the function, otherwise I get a null string, but still in the correct format, so the software doesn't crash. I can't clean the UART buffer, but I can ignore what's in it if it's not useful!
So, I finally got to transmit with the reliable UART clock and at 50 baud, which may provide a longer transmission range, yeeeh!

In the end, it is actually possible to connect two devices to a single UART, even if they work at different baudrates, provided you use one at a time, one just for transmission while the other one just for reception, and, more importantly, you are careful of what you get from the RX pin. That's good to know!

Thank you all for the help!

Re: Two devices connected to a single UART

Posted: Wed Mar 05, 2014 12:54 am
by jojopi
FiddlerJones wrote:The problem is not only the baudrate. Opening and closing so often the port also makes the Pi goes mad.
There is a known issue that reopening the port causes a spurious transmit (https://github.com/raspberrypi/linux/issues/148). I am not sure if that explains your results.

You could clear the input (with termios.tcflush), but there is no way to predict how long the receiver will take to resynchronize after the baud rate is changed. So your method of detecting invalid data in software is actually by far the most reliable. As long as you can receive some valid data between transmissions, you have solved it.

Re: Two devices connected to a single UART

Posted: Thu Mar 06, 2014 11:11 am
by daveake
My first 4 Pi weather balloon flights all used this method - separating Tx/Rx for NTX2 and GPS. The first flight used a Lassen GPS which doesn't need to be sent to, but after that I used UBlox devices which do- they *have* to be put into "flight mode" otherwise they stop working above 18km. For those the Pi Tx line has to go to the GPS as well as the NTX2.

All I did software-wise was to open the port, set baud rate etc for the GPS, wait till I had the position data, then close the port. After that it opened the port again, sent the NTX2 data, then closed it. That final close waits till the data has been sent before the program loops back to read the GPS again. This closing/flushing is absolutely vital to the technique.

These days I use a Ublox with i2c interface, making for a much cleaner software design and more efficient use of the radio channel.

The Adafruit "Ultimate", I should warn you, only works up to 27km. Not very ultimate. An average balloon flight will easily exceed that, meaning that you won't have *any* new position data from the moment it exceeds 27km till sometime after it falls back below that altitude. You're much better off with a UBlox (work up to 50km) e.g. from http://ava.upuaut.net/store/index.php?r ... path=59_60. Just make sure to put it in flight mode.

Dave

Re: Two devices connected to a single UART

Posted: Sun May 15, 2016 6:47 pm
by hydr5
Hi,

I want to do the same thing than FiddlerJones ie getting GPS data and sending it to NTX2 over a serial communication.
But I can't get it working because of the close() instruction which make the data I get from the GPS crazy ^^

This works fine :

Code: Select all

import serial, time

if __name__ == "__main__":

  try:
    while True:
      
      ser = serial.Serial('/dev/ttyAMA0', 9600)
      line = ser.readline()
      print line
      #ser.close()

  except:
    print "Exception"

But when I add the close() method I get data like this :
5)�AM��ͱ������ٱ�ݱ�ٱ�ű���1XXXX2.18,1.37,1.70*0C��ٹ����ɱ�ű�ݱŹ�ݱ���ѱ5��ݹɱ5����

I have no other solution than closing the serial connection because I must re-open another for the NTX...
I also tested with flush(), flushInput(), flushOutput(), added some timers... but nothing is working.

Thanks for assistance!

Re: Two devices connected to a single UART

Posted: Mon May 16, 2016 4:24 pm
by FiddlerJones
If you read my poorly written code above, you can find what I used a solution to avoid data corruption.

You cannot. Unless you wait a bit before reopening the UART port, the time to wait is not constant though, so you cannot know if you'll end up with correct data or not, unless waiting a "worst-case-scenario-long" amount of time, and that is not so good, since most of the times you can avoid data corruption in 0.5 seconds or less.

So you just reopen it right away, and start to read the data, until you get the correct format. In my case the serial raw data was always a string beginning with "$GPGGA":

Code: Select all

uart = serial.Serial('/dev/ttyAMA0', 9600, timeout=1)

while True:
	uart.flush()

	NMEA = uart.readline()

	if (NMEA.startswith("$GPGGA")):
		#do your work with the raw string and *return* your result
	
The loop is finished only on return, and it returns only if the data are in the correct format.
I found that brute-forcing the reading of the data could increase the time to let the UART reset, so a `sleep(.5)` in the while loop is not a bad idea.

When you have to write the using the UART (es. transmitting from the NTX2), you have to wait the "worst-case-scenario-long" time, and/or write multiple time the same data. What I did was a combination of both (keep sending the same GPS data after getting them, and while doing other stuff (taking pictures, writing logs on a file, getting temp and pressure, etc.).

Re: Two devices connected to a single UART

Posted: Mon May 16, 2016 5:47 pm
by hydr5
Thanks for your answer!

My problem is that I cannot get well formed data.
In this short code:

Code: Select all

import serial, time

def read_gps():

  gps = serial.Serial('/dev/ttyAMA0', 9600, timeout=1)
  gps.flush()
  NMEA = gps.readline()
  gps.close()
  line = NMEA.split(",")
  print NMEA

  if(NMEA.startswith("$GPGGA")):
    return line

  else:
    return 0, 0, 0, 0

while True:
  gpsData = read_gps()
  print gpsData
  time.sleep(.5)
I nerver enter my if condition because NMEA sentences are truncated or altered.
I also see that if I change the timer out of the range ~0.2-0.8s, I get bad data but into this range I only get $GPRMC sentences...

I think I'm missing something :-(