Make Teensy and Raspberri Pi communicate? (without effort for the Teensy)

Status
Not open for further replies.

feklee

Active member
Teensy:
  • Output: Every second, the Teensy sets an output, X.
  • Input: Every second, the Teensy checks for an input, Y.

Raspberry Pi:
  • Input: When it finds time, it checks the value output by the Teensy, X.
  • Output: When it finds time, it sets the input for the Teensy, Y.

Details:
  • Teensy 3.2 or better
  • The Teensy is busy doing real-time motion tracking. Setting X and reading Y should take minimum effort, i.e. no longer than a few hundred micro seconds.
  • The Raspberry Pi has all the time in the world.
  • For X and Y 10-bit precision is sufficient.
  • If there is some error in transmission (see below), this is not a problem.

One solution would be to use analog communication: Output X using the Teensy's DAC, read Y using an analog pin on the Teensy. This would require adding a DAC and an ADC to the Raspberry Pi. Although analog transmission is totally fine, I'm not sure if digital-analog-analog-digital is a smart solution.

Any suggestions?
 
I would probably start off going with the USB solution as it is the simplest. You could also use the UART on the RPI expansion connector and connect it up to one of the UARTS on the T3.x boards.
 
How about plug the Teensy into a RPi USB port and use serial communication to send the data back and forth.
Thing is that communication is completely asynchronous: While the Teensy sets X every second, the Raspberry Pi may read it only every minute. Also, vice versa, while the Teensy reads Y every second, the Raspberry Pi may write it every millisecond.

The advantage of the solution that I proposed is that each device can read the value whenever it wants. Synchronization is not necessary, and neither is there the need to empty a buffer to get to the final value. The disadvantage of course is the introduction of analog data transmission, especially as the Raspberry Pi has no analog pins.

What would be interesting is if the Raspberry Pi could write Y into the Teensy's RAM, and read X from it, anytime and without interrupting the Teensy. Is that possible with DMA?
 
There are many ways to do what you wish... If you wish to buy more hardware to go analog, go for it... However it adds the complexity of adding analog to the RPI and if you do the straight forward calls to analogRead on teensy it adds in delays to do the reading...

Personally I would start off with serial communications... Yep so you may have to toss data. You could then add in other hints between the two. Like use two GPIO pins between the two. Have the Teensy use one to signal that the it has or wants data and the RPI does the same on the other side. When or how these signals work would be used is up to you. You could setup interrupt handler to handle the data ...


You could setup the Teensy as an I2C slave to the RPI... When the RPI wishes to talk to the Teensy it can simply ask it for X and tell it for Y. Then on the Teensy, when it sets X it just puts it into some fixed memory location and reads Y from some fixed memory location. And then your I2C slave callback function updates Y from the RPI or returns X to the RPI...

Somehow setup some external dual ported memory, where each can read it or write it...

But again I would start off with Keep It Simple solutions before resorting to more complicated stuff...
 
I came here to say pretty much what KurtE said. You can easily expand the serial buffer RAM on both sides if necessary, and/or use flow control with GPIO pins and something like attachInterrupt() to monitor that on the Teensy side for immediate results. Sending 10+ bits of data is no problem at all if done digitally, but you're going to have a hard time getting 10 bits of precision converting the signal to analog on one side and resampling on the other.
 
Thanks for the suggestions. Note, however, that I don't want to interrupt the Teensy while it is busy: The Teensy should only set X and read Y once per second! Furthermore, I don't think the Teensy will have time to sift through a big buffer. This means, Y should somehow be available immediately. If it was possible to set up some kind of serial ring buffer of length 1, this could be a solution.

Concerning conversion from digital to analog and back, I do understand there will be a loss, and that’s OK. As I wrote: “If there is some error in transmission […], this is not a problem.” Still, converting to analog and back just doesn’t feel right.

What about DMA as mentioned above?
 
What about DMA as mentioned above?

The RPi doesn't have access to the Teensy's RAM to be able to do DMA. You'd have to use some transport mechanism like I2C or SPI to send the bits to one of the Teensy's interfaces so you could use DMA, and I can't see a scenario where rolling your own hardware + software to send 2 bytes of data via DMA would be more efficient than serial packets.

Are you doing anything else with the GPIO pins on the RPi? You could use 10 pins on the RPi to output the data to the Teensy, and 10 more pins to read the data coming back....
 
Thanks for the suggestions. Note, however, that I don't want to interrupt the Teensy while it is busy: The Teensy should only set X and read Y once per second! Furthermore, I don't think the Teensy will have time to sift through a big buffer. This means, Y should somehow be available immediately. If it was possible to set up some kind of serial ring buffer of length 1, this could be a solution.

Concerning conversion from digital to analog and back, I do understand there will be a loss, and that’s OK. As I wrote: “If there is some error in transmission […], this is not a problem.” Still, converting to analog and back just doesn’t feel right.

What about DMA as mentioned above?
For serial UARTs, the Serial1/Serial2 connections already have a 8 byte hardware FIFO for Teensy 3.2/3.5/3.6. The Teensy LC does not have this.

I suspect the USB serial connection has a similar buffer.

But first of all, before worrying about potential problems, code it up, and try it out using the serial output support. It may be there is no problem. You can get yourself tied into knots worrying about potential problems that may not be problems. You don't need any additional h/w to try this other than a USB cable (assuming that the Teensy's power requirement can be met by the Pi).

If there are problems with USB, then try connecting up the Pi serial port to either Serial1 or Serial2 of the Teensy. It doesn't sound like you need to worry about RTS/CTS (flow control), but if you do, those are available.

If you are still having problems, then perhaps use one or two gpio pins, to do the signaling.

Sure DMA can be used, but generally you would want to use it when you are doing a lot of I/O. It doesn't sound like that is the case with your code.

Note for serial UART or gpio pins, the pi and the teensy need to share ground connections.
 
You can get yourself tied into knots worrying about potential problems that may not be problems.
Makes sense. I am more of a software developer. With hardware, to me the amount of options is often overwhleming; And some options require components which first need to be ordered. That makes me plan ahead, sometimes perhaps a bit too much.

I can try to estimate the worst-case performance. Definitely, exchanging values should not take more than about 300 microseconds, maybe 500.

If there are problems with USB, then try connecting up the Pi serial port to either Serial1 or Serial2 of the Teensy.

I'm just reading about Serial1 and Serial2. The USB port I would like to keep for programming the Teensy from my laptop.

Are you doing anything else with the GPIO pins on the RPi?
Unfortunately yes, for plenty of LEDs, rotary switches, etc. It’s not that there is an abundance of pins.

You could use 10 pins on the RPi to output the data to the Teensy, and 10 more pins to read the data coming back....
Guess I could use shift registers as shared storage, one for X and one for Y. Of course, conflicts when reading and writing at the same time need to be avoided. I assume that there are standard solutions.
 
As Michael mentioned and I tried to imply, I would try the simple things first...

For example suppose you are using Serial1 to communicate and you don't wish slow down much.. Also assume that the Y value from the RPI can fit into one byte...

Then your main code loop would simply need to do a quick read of Serial1 and save the last value...
Now if your code ever calls things that end up calling yield, like calls to delay, you could do your own version of yield that does something like:

Code:
// Code like yield today.
void yield() {
    // You could do it the way yield does it or in line...
    if (Serial1.available()) serial1Event();
}

void serial1Event() {
    new_x = Serial.read();
}

or could put it into one
Code:
void yield() {
    int ch = Serial1.read();
    if (ch != -1) {
        new_x = ch;
    }
}
Where new_x is some global you look at when appropriate... You could also set flag saying you had a new value...

Again lots of options.
 
I agree with others - use serial. On the other hand, shared SPI or I2C ram would be interesting.
 
I suspect you may be vastly underestimating both Teensy and Raspberry Pi's capability to implement USB communication efficiently.
 
One issue I ran into with USB was if I powered down the Teensy after a successful connection to the Pi, and powered the Teensy back up again, I was unable to reconnect the USB. Only by power cycling the Pi would make the Teensy visible again. This was on a Pi 3 running Raspbian Jessie. I think it's a limitation of the Pi or OS not the Teensy itself. I was able to power cycle the Teensy just fine on x86/Win 10 and x86/Ubuntu.
 
One issue I ran into with USB was if I powered down the Teensy after a successful connection to the Pi, and powered the Teensy back up again, I was unable to reconnect the USB. Only by power cycling the Pi would make the Teensy visible again. This was on a Pi 3 running Raspbian Jessie. I think it's a limitation of the Pi or OS not the Teensy itself. I was able to power cycle the Teensy just fine on x86/Win 10 and x86/Ubuntu.

What I found like this, was not that the RPI would not see the board, but it would instead give it a new device name:
So if you code is looking for: /dev/ttyACM0 it won't find it as it may come back with /dev/ttyACM1

In my own code, I instead setup UDEV rules to give the device a name that I can find, as I don't like that you can run into issues of having two Teensy boards or some other board that uses the ACMx driver and could be different from boot to boot.

So for example my servo controller code, I setup by Serial # to create /dev/ttyDXL
Which my code looks for as the main name.. I then fall back to looking for /dev/ttyACM0 if not found.

This also helped in now sometimes I setup my Teensy code to talk through Hardware Serial port and use the hardware port on expansion connector. So to use this all I need to do is change my UDEV rule and the code does not need to change.
 
Status
Not open for further replies.
Back
Top