prusa3d / Prusa-Firmware

Firmware for Original Prusa i3 3D printer by PrusaResearch
GNU General Public License v3.0
1.99k stars 1.05k forks source link

Using TX/RX pins on J19 connector #4698

Open RogerInHawaii opened 1 month ago

RogerInHawaii commented 1 month ago

I want to communicate between the Prusa Firmware and an external Arduino via the TX/RX pins on the J19 connector of the Einsy Rambo board on my Prusa i3 MK3.

The firmware has a MarlinSerial object that does serial communication but it communicates via the USB port on the Prusa, not those TX/RX pins on the J19 connector. I need, I think, a variation of that MarlinSerial object that is set up to use the TX/RX pins on J19.

How do I do that?

I've come across references to an MSerial2 object, but that doesn't appear to actually be IN the Prusa firmware.

I'm hoping someone can help me get this working.

ojrik commented 1 month ago

Here is a link to connect the Raspberry pi Zero via the J19 connector. Maybe it will help you.

https://help.prusa3d.com/article/prusaprint-rpi-zero-and-octoprint_2180

RogerInHawaii commented 1 month ago

Thank you for replying. :)

That does indeed show how to connect to the J19 connector and it does indeed include connections to the TX and RX pins of that connector.

I wasn't aware of the RPI Port option in the Printers Settings, so particular thanks for that.

Does setting that RPI Port to ON cause the Prusa firmware to communicate over the J19's TX and RX pins?

And does it mean that calling serial communications methods from within the Prusa firmware via the MarlinSerial class causes those communications to go via those J19 TX and RX pins?

If so, that would seem to really solve my issues.

RogerInHawaii commented 1 month ago

Well, I've done a bunch of testing. I have indeed set the RPI Port setting on the Prusa to ON. But that doesn't seem to have changed anything. I have my modified firmware installed on the printer using MarlinSerial.print("A") methods, expecting that RPI Port setting to have redirected serial output to the TX pin on the J19, but the test program I have running on an Arduino Nano Every to receive the incoming text on the RX pin on the J19 doesn't seem to be receiving anything at all.

I guess I'm still missing something.

RogerInHawaii commented 3 weeks ago

I see that

Serial0 Serial1 Serial2 Serial3

and also

HardwareSerial0 HardwareSerial1 HardwareSerial2 HardwareSerial3

and even

SoftwareSerial

are things that have been mentioned to me as possible approaches, and even seem to be .cpp and .h files in the composite set of files for the firmware. But when I try them it results in compiler errors, most often saying duplicate definitions of things named like __vector_3.

PLEASE HELP ! ! !

leptun commented 3 weeks ago

As it is written right now, MSerial (MarlinSerial) takes over both the UART0 (USB) and UART1 (J19) pins. Not only that, but it also initializes both interfaces and implements the IRQ handlers for both interfaces. If you don't care about the USB comms, you can in theory just use the menu item to switch the "RPi port" on, which should send and receive all traffic to UART1.

Sending data is easy. You can either use the Mserial methods, or more easily use printf()/puts() to send text via MSerial.

Receiving data is more complicated since the cmdqueue will read all incoming MSerial data, so your code would not get it. If you plan to use text to send commands to the printer, you can modify the command parser to accept your commands as well. See how the PRUSA commands are implemented for that. If you don't want to go through the parser and cmdqueue, you'll have to modify the cmdqueue to no longer get data from MSerial (or MYSERIAL as it is sometimes called). Then you can use MSerial for your purposes completely.

Do note however that I doubt you can use a direct connection from J19 to an arduino nano. The TX pin of the J19 goes through a voltage divider since the RPi can only handle 3.3V, so you will need a level shifter (5V on the nano side, 3.3V on the printer side) if you want to use a 5V based dev board from the J19. The Rx pin of the J19 is fine, so you don't need any level shifter in that direction.

RogerInHawaii commented 3 weeks ago

Thank you for replying and thank you for all that info. I truly appreciate it.

I'm pretty sure that, in all the 97 variations that I've tried so far, based on all sorts of information I was able to glean from sources all over, that approach was among them and I got no data received by the Arduino.

But I'll definitely give it a try and let you know how it goes.

I did come across one comment by someone that you really need to be connected really close between the J19 pin and the pins on the Arduino. I actually have about ten inches of wire. Is that an issue?

And I do have two other Arduinos, an Arduino Uno R4 and an Arduino Mega R3. Would either of those be better for this application?

leptun commented 3 weeks ago

The length of the wires won't matter that much, unless you want to run the interface at high baud rates (say >=250000). Just make sure you have a good GND connection between the two boards and don't go to ridiculous lengths (I wouldn't go past 1m for reliable communication). You also want the level shifter as close to the einsy as possible since the TX is quite weak.

The mega R3 will need a level shifter in the Einsy->Arduino direction because it's a 5V board. Same for the Uno R4 after a quick datasheet check of the RA4M1.

If you want a uart that works at 5V without level shifting, you could look into using UART2 which is used for the MMU normally and is available on ~J3~ P3. In the code that peripheral is controlled by a different serial implementation, so keep that in mind.

RogerInHawaii commented 3 weeks ago

Hi again,

My primary need at the moment, in this stage of my project, is having the Prusa sending text out through (some) TX pin to an RX pin on an Arduino. I actually have three Arduinos: Nano Every, UNO RF, and MEGA R3. I'm quite certain that they all operate at 5 volts, and I presume that applies to the TX and RX pins on each as well.

I actually also do have a couple of level shifters, tough I have never used, never wired up a level shifter in any of my prior projects.

You note that the TX pin on the J19 connector is at 3.3 Volts, so a level shifter would be needed for that pin, to the RX pin on the Arduino (and apparently ANY Arduino that I might use).

Q1: Where on the Einsy Rambo board is 3.3V available? In case I do actually try to wire in the level shifter.

You also mention UART2 which provides both TX and RX pin at 5V on a J3 connector and therefore does not need any level shifter in the circuit between the Rambo and an Arduino.

I see that there is indeed a UART2.c and UART2.h files, and it contains methods like uart2_putchar() and uart2_gettchar() and others, as well as mmu2_serial.cpp which has just a few methods for init and sending and receiving. Nothing fancy.

I'd have to figure out where the J3 connector is and how to connect to that, but at the moment that seems the easiest for me to get working, with no need for any level shifter to wire into the circuit.

I think I'll try that approach for now, using mmu_serial and see if I have any success.

Does that sound reasonable to you?

RogerInHawaii commented 3 weeks ago

Can you point me to any documentation on how to use the mmu2_serial class, or UART2?

I've spent several hours trying to use it with no success.

I include the mmu2_serial.h file in my Marlin_main.cpp file and immediately after that declare an object as:

MMU2Serial SerialViaJ3;

and when I compile the project get an error at that declaration:

MMU2Serial' does not name a type; did you mean 'MSerial'.

So I'm super confused why it doesn't like that.

I did a bunch of searching around on how to use that other serial port (that is all 5volts) and it shows all sorts of complex use or MACROS to have access to it.

I just don't understand why it's not as simple as just declaring an object of class MMU2Serial and using that object to send text over it's TX pin. And why is it saying MMU2Serial is not defined, when indeed it IS defined in the mmu2_serial.h file?

I'm very confused and feeling pretty stupid.

What am I missing?

leptun commented 3 weeks ago

Btw, I accidentally said earlier J3. I meant to say P3. Sorry for the confusion. It's a 2x5 header on the front of the einsy. A row is used by the filament sensor, the other row can be used by the MMU.

You don't have to declare a serial object. Simply include into your project and then use uart2_init(baud); to intialize it. For example, to send a string you can use vfprintf_P(uart2io, PSTR("...format..."), ...args...); For reading use vfscanf_P(uart2io, PSTR("...format..."), ...args...). Basically use the stdio functions on the uart2io stream, preferably the avr variants that are more efficient. See https://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html

There is no 3.3V output from the printer that you can use. Using uart2 is simpler since you have in a single row of pins power and bidirectional uart and a gpio that can be used for resetting the arduino for example. See the schematic page 5 for the pinout. https://github.com/ultimachine/Einsy-Rambo/blob/1.1a/board/Project%20Outputs/Schematic%20Prints_Einsy%20Rambo_1.1a.PDF

Also, I really suggest that you go to the forums for help with this. This issue is not related to the function of the stock firmware on the printer.

RogerInHawaii commented 3 weeks ago

WOW! . . . THANK YOU

That looks like, finally, the info I need.

I'll read through it and try to implement it.

I've posted my issue on a number of other forums and although suggestions were made as to how I could make it work via the J19), none of them actually worked.

I see now that the primary issue was that the TX on J19 from the Einsy Rambo board works at 3.3V, while everything else works at 5V. And in order to get it working I would need to incorporate that Level Shifter in the circuit, as YOU had described. Not a single other person mentioned that. It fully explains why none of the other suggestions worked, it wasn't that the suggestion didn't work (it MAY have) it was that the 3.3 Volt coming across from the Prusa was incompatible with the 5 Volts expected on the Arduino so the Arduino wasn't receiving what actually was (may have been) sent!!!

You eventually noted that there's another UART accessible on P3 that is ALL 5 volts. That's what I should have been working on all along, but no one else ever mentioned it or mentioned the 3.3 vs 5 issue. So THANK YOU so very much.

I'll start working on that P3, uart2 approach and let you know how it goes.

RogerInHawaii commented 3 weeks ago

Oh, and since, as you point out, "there is no 3.3V output from the printer that you can use", that would seem to mean that even if I WANTED to use a Level Shifter for the J19 approach, there wouldn't be a 3.3V source to connect to the Level Shifter to let it know what it should shift from.

So all my past attempts, all the advice given by all the other forums, never could have worked.

I guess, . . . live and learn.

and

keep posting all over on the Internet until you find the one person who really knows their stuff!

THANK YOU

RogerInHawaii commented 3 weeks ago

Just to verify where P3 is ans which are the important pins for UART2.

Is this correct?

image

RogerInHawaii commented 3 weeks ago

And I take it that this is the P3 connector from the schematics you referenced.

Is the PJ5 pin (lower right) the pin you referenced as "providing gpio that can be used for resetting the arduino for example"?

I'm not sure I'll need it right now, but might be useful in the future.

image

RogerInHawaii commented 3 weeks ago

Hi,

I hope you can take a few minutes to look over what I've been trying, but failing, to do with the TX pinon P3.

I know you suggested another forum, but I haven't gotten help over there. And you do seem to have a good handle on how to use the TX pinon P3.

So, . . .

I've added jumper wires to the VCC, GND, TX, and RX pins of the P3 connector.

I used a voltmeter to show that there is indeed 5V between GND and VCC.

When I use my (very simple, not sophisticated) logic analyzer between TX and GND, it also shows near 5V.

Q1) Is that reasonable? I would expect it to be 0v when nothing is being transmitted.

When I run my modified Marlin_main to have it (try to) send text over the TX pin of P3, my logic analyzer basically still just shows near 5V.

I even slowed the baud rate for UART2 down to 9600, on the theory than my crude logic analyzer might not handle 115200 BAUD. But it still showed basically just 5V on the TX to GND.

Here's what I'm doing in the Marlin_main code:

Near the beginning of Marlin_main.cpp I'm doing

#include

In setup() I'm doing

**void setup() {

define BaudRateBetweenUart2AndArduinoNanoEvery 115200

// Also tried 9600 for above,but it made no difference.

uart2_init(BaudRateBetweenUart2AndArduinoNanoEvery);

etc.

}**

Based on an example I found about using uart2io I included a new method to actually send text out through the TX pin on P3 (i.e. through UART2), which apparently requires a va_start and va_end to actually accomplish the sending of the text:

void my_vfprintf_P(const char *fmt, ...) { va_list args; va_start(args, fmt); vfprintf_P(uart2io, fmt, args); va_end(args); }

and then in the place where I want to do that text sending, I call the above method like this

const char TextToSend[] PROGMEM = "TURN ON LIGHT\n"; my_vfprintf_P(TextToSend);

But even when it's doing this (over and over again in hopes that I'd see some activity via the logic analyxr), the logic analyzer still shows a pretty steady 5V

I also connected the TX pin on P3 to the RX pin on my Arduino (and GND to GND) and had my Arduino running to receive the text, but it seems to get nothing, always returning 0 when it's checking

if (Serial.available() > 0)

**Q2) Is there something that I"m missing? Something extra that needs to be done to assure that

vfprintf_P(uart2io, fmt, args);

actually does indeed send the text through the TX pin on P3?**