Serial: can't write from arduino UNO to Raspberry Pi 3B

Hi,

I’ve been trying to get some sort of communication between an Arduino UNO and a Raspberry Pi 3B. I had already tried i2c but failed so I’m stuck with serial. So far, I can write from the Raspberry and read that on the Arduino but not vice versa.
I’m trying to use digital pins 0 (Rx) and 1 (Tx) with the UART0 pins of the Raspberry (pin 8 - Tx, pin 10 - Rx) through a logic level converter. I need the converter because the Arduino and Raspberry use different logic levels. Here is my setup:

ARDUINO | LOGIC LEVEL CONVERTER | RASPBERRY

0 (Rx) Hv1 Lv1 8 (Tx)
1 (Tx) Hv2 Lv2 10 (Rx)
GND GND GND GND
5V Hv Lv 3.3V

The arduino is powered from a DC adaptor through its USB plug so there should be no communication on USB.

Setting up the serial on RPi3 is not trivial but I followed this guide:

In a nutshell, I had to add the following line to /boot/config.txt :enable_uart=1
This freed up the miniuart and fixed the GPU clock it’s using, providing a constant baudrate.

I can write from the RPi and read the correct value on the arduino. I can also write from the RPi to itself and read it if I connect its Tx and Rx pins, so the RPi should be fine. But when I try write from the Arduino, I can’t read anything on the RPi. I can only assume that there is something wrong with the Aruino Tx, as I changed the logic level shifter to another one but the problem remained.
Bizarrely, when the Arduino is powered from a laptop and a serial monitor is opened, the arduino still reads the correct data from the RPi but writes to the serial monitor of the laptop (serial monitor displays gibberish, as expected).

Arduino code: reads 1 byte from serial, sends back, blinks times

const int LED_PIN = 13;

uint8_t data =2;

void setup() {
    pinMode(LED_PIN, OUTPUT);
    Serial.begin(9600);
}

void loop() {
    while (!Serial.available()) { /* wait */ }
    data = Serial.read();
    Serial.write(data);
    delay(150);
    blinkTimes(data);
}

void blinkTimes(uint8_t input)
{
  for (int i=0;i<input;i++)
        {
        digitalWrite(LED_PIN, HIGH);
        delay(150);
        digitalWrite(LED_PIN, LOW);
        delay(150);
        }
}

Raspberry code (Python): writes , reads 1 byte, prints that byte

import serial
import time


message = 5

arduino = serial.Serial('/dev/serial0',baudrate=9600,timeout=3.0)
time.sleep(2)
arduino.write(bytes([message]))
a=arduino.read(1)
print(a)
arduino.close()

Logic level converter: (it’s cheap but it works, I’ve used it before)

The simplest way of using serial is to simply plug the Arduino into the USB connector of the Raspberry Pi.

The other thing is don't open the serial, do stuff, and close, make it send / display continuously. When the Arduino powers up or is reset by the opening of the serial port there is a delay before it starts running your code due to the boot loader running first. So give a bit of time at both ends before calling it a day in your code.

Thanks for the quick answer.
I can get it working by USB cable but it's a last resort. I have to keep things as small and light as possible.
There is a delay between opening serial and writing in it on the Raspberry side (time.sleep()). However, no matter how long that delay is (tried 30 sec) no data arrives when reading.

Grumpy_Mike:
When the Arduino powers up or is reset by the opening of the serial port

That won't happen if he is bypassing the USB connection and just connecting to Rx Tx and GND

@kelofm this Python - Arduino demo may be of interest. However it was written on the assumption that it would be connecting via the USB cable.

Maybe a useful development path would be to get a simple example working over the USB cable and then try implementing it without the USB cable.

Rather than echoing characters I suggest you write a short Arduino program that just sends "Hello World" every second.

And for receiving data in the Arduino have a look at Serial Input Basics which I wrote more recently than the Python demo.

...R

kelofm:
ARDUINO | LOGIC LEVEL CONVERTER | RASPBERRY

0 (Rx) Hv1 Lv1 8 (Tx)
1 (Tx) Hv2 Lv2 10 (Rx)
GND GND GND GND
5V Hv Lv 3.3V

You don't need to connect the 5V to 3.3V, get rid of that.

The RPi TX can be connected directly to the Arduino RX, it will go HIGH with 3V.

Arduino TX to RPi RX does need leveling, of which there are many ways.

When nothing is being sent on the Arduino TX the line should be HIGH. The 3.3V side of the level converter should show 3.3V relative to GND on a meter. If you don't see that then signal is not getting through.

TTL serial keeps the lines HIGH where you would think they should be LOW but that way, serial lines would be vulnerable to weak fields and false a lot. The logic is reversed, the connection is stronger and ... you get an easy way to check if the lines are live. Hope you got a meter!

You don't need to connect the 5V to 3.3V, get rid of that.

That is powering the level shifter.

Power the shifter? For one line?

He could put a diode on the Arduino TX line blocking the 5V from the RPi and then a pullup from the RPi 3.3V to the RPi RX through a 10K resistor. Then when TX goes LOW it pulls the pullup line LOW and RPi sees LOW else it sees HIGH. That's a no-bleed level-shift for the cost of a diode and resistor... 10 cents if you paid too much!

I learned that one from an RPi site. They showed how to roll 2-ways with FETs as well.

Power the shifter? For one line?

Yes it is the pull up voltage.
But you are right the level shifters are not needed, just put a 501R and 1K in the Arduino TX to Pi's RX and nothing the other way and connect the grounds.

Grumpy_Mike:
Yes it is the pull up voltage.
But you are right the level shifters are not needed, just put a 501R and 1K in the Arduino TX to Pi's RX and nothing the other way and connect the grounds.

For sure connect the grounds!
Bleedin voltage dividers! Losing current at every 0 and even when nothing is sent.
That's why I love the diode-n-pullup solution, no bleed except when 1's are sent.

Losing current at every 0 and even when nothing is sent.

We are talking about a Raspberry Pi here. That just gulps current down, about 500mA when just ticking over.