Teensy USB-Serial Flow control

Status
Not open for further replies.
O.K. I have built a quick device to be able to drip feed CNC programs to my CNC machine. It has an old control and the floppy drive has broken with zero hope for repair. Enter: Teensy, since Teensy has a real UART and hardware serial, i figured it would make a great fit. For the most part it has done well, it is able to send data to the CNC and get it to start running. On the CNC, I enter "Tape mode", and just press start to start receiving a file. I have this working correctly with another computer that also has a hardware serial. The goal is to get rid of USB-Serial eventually and be able to dump programs from the SD card, replacing the floppy. So far I am able to start dumping the file to the CNC machine and it runs for a bit, but it (seems) like it gets hung up on flow control. Software flow control refuses to work, whereas, on the other test system, it doesn't seem to matter which type of flow control i set but it works. RTS/CTS is available on the CNC and I am aware that you are supposed to connect RTS on the Teensy to CTS on the CNC and Vice Versa. The first question I have is there any code that needs to be written to further implement RTS/CTS beyond the serial1.attachRts(pin) and serial1.attachCts(pin)?

Code:
/* USB to Serial - Teensy becomes a USB to Serial converter
   http://dorkbotpdx.org/blog/paul/teensy_as_benito_at_57600_baud

   You must select Serial from the "Tools > USB Type" menu

   This example code is in the public domain.
*/

// set this to the hardware serial port you wish to use
#define HWSERIAL Serial1

unsigned long baud = 4800;
const int reset_pin = 4;
const int led_pin = 13;  // 13 = Teensy 3.X & LC
                         // 11 = Teensy 2.0
                         //  6 = Teensy++ 2.0
const int rts_pin = 2;
const int cts_pin = 18;

void setup()
{
  pinMode(led_pin, OUTPUT);
  digitalWrite(led_pin, LOW);
  digitalWrite(reset_pin, HIGH);
  pinMode(reset_pin, OUTPUT);
  // Next 4 lines debug Tx/Rx 
  //pinMode(0, OUTPUT);
  //digitalWrite(0, LOW); 
  //pinMode(1, OUTPUT);
  //pinMode(1, LOW);
  // Next four lines Debug RTS/CTS 
  //pinMode(rts_pin, OUTPUT);
  //digitalWrite(rts_pin, HIGH);
  //pinMode(cts_pin, OUTPUT);
  //digitalWrite(cts_pin, HIGH);
  //
  Serial.begin(baud);	// USB, communication to PC or Mac
  HWSERIAL.begin(baud, SERIAL_7E1);	// communication to hardware serial
  HWSERIAL.attachRts(rts_pin);
  HWSERIAL.attachCts(cts_pin);
}

long led_on_time=0;
byte buffer[80];
unsigned char prev_dtr = 0;

void loop()
{
  unsigned char dtr;
  int rd, wr, n;

  // check if any data has arrived on the USB virtual serial port
  rd = Serial.available();
  if (rd > 0) {
    // check if the hardware serial port is ready to transmit
    wr = HWSERIAL.availableForWrite();
    if (wr > 0) {
      // compute how much data to move, the smallest
      // of rd, wr and the buffer size
      if (rd > wr) rd = wr;
      if (rd > 80) rd = 80;
      // read data from the USB port
      n = Serial.readBytes((char *)buffer, rd);
      // write it to the hardware serial port
      HWSERIAL.write(buffer, n);
      // turn on the LED to indicate activity
      digitalWrite(led_pin, HIGH);
      led_on_time = millis();
    }
  }

  // check if any data has arrived on the hardware serial port
  rd = HWSERIAL.available();
  if (rd > 0) {
    // check if the USB virtual serial port is ready to transmit
    wr = Serial.availableForWrite();
    if (wr > 0) {
      // compute how much data to move, the smallest
      // of rd, wr and the buffer size
      if (rd > wr) rd = wr;
      if (rd > 80) rd = 80;
      // read data from the hardware serial port
      n = HWSERIAL.readBytes((char *)buffer, rd);
      // write it to the USB port
      Serial.write(buffer, n);
      // turn on the LED to indicate activity
      digitalWrite(led_pin, HIGH);
      led_on_time = millis();
    }
  }

  // check if the USB virtual serial port has raised DTR
  dtr = Serial.dtr();
  if (dtr && !prev_dtr) {
    digitalWrite(reset_pin, LOW);
    delayMicroseconds(250);
    digitalWrite(reset_pin, HIGH);
  }
  prev_dtr = dtr;

  // if the LED has been left on without more activity, turn it off
  if (millis() - led_on_time > 3) {
    digitalWrite(led_pin, LOW);
  }

  // check if the USB virtual serial wants a new baud rate
  if (Serial.baud() != baud) {
    baud = Serial.baud();
    if (baud == 57600) {
      // This ugly hack is necessary for talking
      // to the arduino bootloader, which actually
      // communicates at 58824 baud (+2.1% error).
      // Teensyduino will configure the UART for
      // the closest baud rate, which is 57143
      // baud (-0.8% error).  Serial communication
      // can tolerate about 2.5% error, so the
      // combined error is too large.  Simply
      // setting the baud rate to the same as
      // arduino's actual baud rate works.
      HWSERIAL.begin(58824);
    } else {
      HWSERIAL.begin(baud);
    }
  }
}
 
Furthermore, today I was able to do some testing. So it seems RTS/CTS is working fine on this device I built because I was able to short RTS/CTS on the Teensy board I built and the Teensy device just kept streaming data (an indicator LED was also added) over serial1. Of course this is not the intended operation, as flow control is required to allow the (old) CNC to stay in sync with this newer technology. It seems that I am not getting a CTS signal from the CNC. The Teensy board is running off of the 5 volt supply on the CNC, so as to avoid any grounding issues. Hopefully I'm doing all of this correctly, from my other experience with Beaglebone, etc. When I put my Serial Software in CTS/RTS mode, it stops after just one line of code waiting for the RTS signal of the CNC to trigger the CTS signal of the Teensy board (cable is wired (CNC) RTS >> (Teensy) CTS and (Teensy) RTS >> (CNC) CTS). The indicator LED does not light up. So I suppose the next step is to check the CNC paramaters file and adjust, but also possibly make another indicator light for CTS signal on the CNC. Any input is appreciated... As well as any insight into the RTS/CTS handshake that I might be missing
IMG_20180712_152840268.jpg
 
To check the Teensy side, you could just connect a switch or wire to the CTS input. When high, Teensy should send serial output normally. When you connect it low, Teensy should stop transmitting. If you connect a LED+resistor between the transmit output and 3.3V (looks like you probably already have this), it's easy to see when data is transmitting.

As far as the old CNC equipment is concerned, can't really help much there. But one possibility to consider is it may simply be able to keep up with the baud rate and data stream you're transmitting. In that case, you'd expect it to keet the CTS signal high all the time.
 
Sorry for the long delay, I was working on several other projects. But anyhow, I was able to create a cable tester (Breakout jumper box style) AND also made a new cable. I was also able to find the parameters for the CNC machine in question. I tried turning on CTS/RTS, but checked the pins and there is no high signal (apparently 3.3v on this machine) when CTS/RTS handshaking is used (on a known working test bed machine that works for this purpose, but only with software flow control). A couple other issues with the machine is that it only has an 8 byte buffer, which should probably be matched and then an XON/XOFF signal sent and received. Are there any libraries that deal with these functions(it looks like changing buffer byte size is trivial)? or should it be hardcoded with an if statement and a couple variables pointing to a hex value? and the else going back to the beginning?
 
SO I have been able to make some progress. With some debug code I was able to make this thing send from the SD card, 8 bytes at a time, I'm quite certain that this code could use an overhaul as it was a merge of a couple of examples. Does anyone have an idea how to get it to read an XOFF/XON signal from the CNC? Should be fairly trivial at this point, and I'll give it a go sometime this week. So far this code takes (G)code from the SD card and sends it out to serial, 8 bytes at a time.
Code:
/*
  SD card file dump
 
 This example shows how to read a file from the SD card using the
 SD library and send it over the serial port.
 	
 The circuit:
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11, pin 7 on Teensy with audio board
 ** MISO - pin 12
 ** CLK - pin 13, pin 14 on Teensy with audio board
 ** CS - pin 4, pin 10 on Teensy with audio board
 
 created  22 December 2010
 by Limor Fried
 modified 9 Apr 2012
 by Tom Igoe
 
 This example code is in the public domain.
 	 
 */

#include <SD.h>
#include <SPI.h>
#define HWSERIAL Serial1

unsigned long baud = 4800;
const int reset_pin = 4;
const int led_pin = 13;  // 13 = Teensy 3.X & LC
                         // 11 = Teensy 2.0
                         //  6 = Teensy++ 2.0
// On the Ethernet Shield, CS is pin 4. Note that even if it's not
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
// 53 on the Mega) must be left as an output or the SD library
// functions will not work.

// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
// Teensy audio board: pin 10
// Teensy 3.5 & 3.6 on-board: BUILTIN_SDCARD
// Wiz820+SD board: pin 4
// Teensy 2.0: pin 0
// Teensy++ 2.0: pin 20
const int chipSelect = 4;

void setup()
{
 //set pins:
 pinMode(led_pin, OUTPUT);
 digitalWrite(led_pin, LOW);
 digitalWrite(reset_pin, HIGH);
 pinMode(reset_pin, OUTPUT);
 //set serial:
 Serial.begin(baud); // USB, communication to PC or Mac
 HWSERIAL.begin(baud); // communication to hardware serial
 //constants
 long led_on_time=0;
 byte buffer[8];
 unsigned char prev_dtr = 0;
 //variables
 unsigned char dtr;
 int rd, wr, n, i;
 
 //UNCOMMENT THESE TWO LINES FOR TEENSY AUDIO BOARD:
 //SPI.setMOSI(7);  // Audio shield has MOSI on pin 7
 //SPI.setSCK(14);  // Audio shield has SCK on pin 14
  
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  Serial.print("Initializing SD card...");
  
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
  
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open("12345678.prg");

  // if the file is available, write to it:
  if (dataFile) {
    rd = dataFile.available();
    
    //"i" is debug for byte count
    i = 1;
    while (dataFile.available()) {
      Serial.println(i);
      i++;
      if (rd > 0) {
         Serial.println("datafile is available");
         wr = dataFile.available();
         Serial.println("Bytes available for write:");
         Serial.println(wr);
         if (wr > 0) {
           // compute how much data to move, the smallest
           // of rd, wr and the buffer size
           if (rd > wr) rd = wr;
           if (rd > 8) rd = 8;
           // read data from the file
           n = dataFile.readBytes((char *)buffer, rd);
           // write it to the com port
           HWSERIAL.write(buffer, n);
           // turn on the LED to indicate activity
           digitalWrite(led_pin, HIGH);
           led_on_time = millis();
         }
      }
    }
    dataFile.close();
    Serial.println("File Finished");
  }  
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  } 
}

void loop()
{
}
 
Status
Not open for further replies.
Back
Top