Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 5 of 5

Thread: Teensy USB-Serial Flow control

  1. #1
    Junior Member
    Join Date
    Jul 2018
    Posts
    13

    Teensy USB-Serial Flow control

    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);
        }
      }
    }

  2. #2
    Junior Member
    Join Date
    Jul 2018
    Posts
    13
    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
    Click image for larger version. 

Name:	IMG_20180712_152840268.jpg 
Views:	36 
Size:	108.0 KB 
ID:	14188

  3. #3
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    19,206
    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.

  4. #4
    Junior Member
    Join Date
    Jul 2018
    Posts
    13
    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?

  5. #5
    Junior Member
    Join Date
    Jul 2018
    Posts
    13
    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()
    {
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •