Adding capabilities to my ELS system

I believe FTDI as @dkemppai refers to is just a common chipset/driver for a serial to USB cable.

With a Linux variant (i.e., RPI5), you just 'cat' the serial device created by the FTDI converter. It has been a few years (decades?) since I've done this, but a script something like
sleep 5 < /dev/usb-serial-port &
stty [apppropriate rs-232 baud/parity/data bits] < /dev/usb-serial-port
cat /dev/usb-serial-port > my-data-file

should work. The sleep (or some other trick) is needed since linux kernel reverts the serial-port to default parameters when it is closed by all devices, by attaching a sleep or something else on it, the stty command can complete and the cat command start without that happening. You can wrap that in a bash script to restart it endlessly (the cat will close if the far end resets the serial connection). A bit more scripting gets you a time/date stamp added to the "my-data-file" name so you get a time & date for each data file, or you can use an append operation >> to just keep growing the same data file

edited to add: I see @dkemppai replied while I was typing
 
Last edited:
I send the timestamp as a 32 bit number right from the ARM cycle counter. Rollovers are easy enough to find on the PC, so I just deal with it there. The whole point is to reduce the number of bytes being sent.

The advantage of the FTDI cable is it completely offloads the USB overhead to a dedicated IC in the FTDI cable. The teensy can just treat it as a serial port. USB stalls and other delays are hidden from the teensy. But honestly, any other serial device would do the same thing. An RPI acting as a data logger would another way to achieve the same goal. The point is to offload as much overhead from the teensy as possible.

Since Mac is Linux/Unix based can you just redirect serial port data to a file? (I'm not a Mac or Linux guy) On windows I'm using realterm, or teraterm. My preferred is teraterm, but it has trouble with too much binary data. Realterm seems to handle that without issue. Would realterm run on Mac?

As for processing the data, I used an excel macro to decode the packets. Only because that has been my tool of choice for over 25 years. (I have the code base to make that happen quickly). You're welcome to that code, but unless you muck around with macro programming, it may not be super intuitive.
Dumb question. The actual interface on the Teensy to the FTDI is simply a HW serial port? Not the host USB port, or anything else? Two wires? Four? Never used the device.

I have bad experience already with not being able to unwrap the rollover. My sessions can take far longer than 7 seconds for testing, I'm logging 20-30 minute sessions. (Things work great, until they don't.) Time is not always obvious to unwrap, especially if not in a common file.

The bigger issue is a whole list of variables (or even 15% of them) is too long to send out in real time (without affecting execution). So I need to be selective. In C one cannot just make a list of all the variables and send them (reflection). You have to purposely copy them to a buffer individually, and then spool them out of the buffer. Copying a list steals a lot of time from the process. (Can't use DMA, since we don't know where they are mapped to, and that could change every build...)

Does HW serial disable interrupts, like USB?

Do I need a FTDI cable that ends in a USB C (My laptop is USBC only) ? And my USBC port knows that it's just serial, not USB?

FTDI is slow @ 3Mbps. Why is this better than USB @ 480Mbps, or Ethernet at 100 Mbps? Sure there's overhead, but is that it? Easier to debug? So I connect one end to a Teensy serial port, and the other to my Mac laptop or RPI5 USB ports?
 
Dumb question. The actual interface on the Teensy to the FTDI is simply a HW serial port? Not the host USB port, or anything else? Two wires? Four? Never used the device.
Yes, the FTDI interface is a HW serial port on the Teensy. You only need one pin and a ground reference to send that data out. So, if you have access to any of the serial hardware TX pins it should work for you.

I have bad experience already with not being able to unwrap the rollover. My sessions can take far longer than 7 seconds for testing, I'm logging 20-30 minute sessions. (Things work great, until they don't.) Time is not always obvious to unwrap, especially if not in a common file.
I'm sending data often enough I don't miss a rollover. So any time the counter is less than the previous count I just add a 32 bit count to the number. But if you don't send enough data it could be an issues.

The bigger issue is a whole list of variables (or even 15% of them) is too long to send out in real time (without affecting execution). So I need to be selective. In C one cannot just make a list of all the variables and send them (reflection). You have to purposely copy them to a buffer individually, and then spool them out of the buffer. Copying a list steals a lot of time from the process. (Can't use DMA, since we don't know where they are mapped to, and that could change every build...)
I'm just writing the values directly from the ISR or wherever I'm using them. Again YMMV.

Does HW serial disable interrupts, like USB?
Using the additional buffer for serial does use a serial interrupt. It should not disable other hardware interrupts. That interrupt just copies data to the outgoing serial hardware FIFO so should be fast. You can define a large buffer, in my case I have 4K defined.


Code:
#define FTDISerial Serial5  //LCDSerial = Serila#5
#define FTDISerialTxBufferSize 4096
DMAMEM byte FTDISerialTXbuffer[FTDISerialTxBufferSize];

Code:
  //Init FTDI Serial.  Init Pins 20, 21, Serial 5 here.
  pinMode(20, OUTPUT);  //Serial pin needs to be output.
  pinMode(21, INPUT); 
  FTDISerial.begin(3000000);                                                 
  FTDISerial.addMemoryForWrite(FTDISerialTXbuffer, FTDISerialTxBufferSize);  //Update serial buffer.
  NVIC_SET_PRIORITY(IRQ_LPUART8, 96);                                        //Set Interrupt Priority.

After the above, just write it like any other serial device.

Do I need a FTDI cable that ends in a USB C (My laptop is USBC only) ? And my USBC port knows that it's just serial, not USB?
The FTDI cables come with USB to serial drivers. It will show up as a serial port if you use their provided driver.

FTDI is slow @ 3Mbps. Why is this better than USB @ 480Mbps, or Ethernet at 100 Mbps? Sure there's overhead, but is that it? Easier to debug? So I connect one end to a Teensy serial port, and the other to my Mac laptop or RPI5 USB ports?
For me it's just easier, and a completely different interface into the teensy. I leave a terminal program open on the FTDI serial all the time. It's just a second channel completely independent of the Arduino/Teensy hardware. When the teensy/arduino serial monitor crashes, this one is still working.

Maybe this isn't ideal for your hardware setup, and an RPI would be better. What's the highest baud you can run on an RPI pin?

My experience is that *printf gets big and slow very quickly. If you can stream data down the USB and not use strings, it will probably be fast enough to help you debug. The down side is you need to process that data in the PC.
 
What's the highest baud you can run on an RPI pin?
Not sure, at the moment. RPI5 and Arm seem to like to obfuscate specs these days and give no insight into the HW.

I found a reference to boosting a clock on the RPI forum, to get 6.25Mbps. The UART clock gets boosted up to 100MHz, which is divided by 16 to get 6.25Mbps. Whether it actually works, I don't know.
 
I don't need to use printf statements, they were for my convenience, I understand they do all sorts of conversion. I can use something like
Code:
Serial5.write( (uint8_t *) &x, sizeof(x));
to write out stuff in binary. Works for all data types, but not arrays.
It turns out I have Serial5 available. All of this will require mods. Hope it's worth the effort.
 
You can remap the RX pin (21) to a standard input or output any time after serial.begin() by just redefining it as an input or output. That will disconnect it form the crossbar mapping. That's what I do for the LCD serial in my setup, using TX only.
 
I have no experience with the PL**** chip sets. IIRC some are knockoffs, but I suspect anything from Digikey would be fine.

I've run the FTDI cables and chips in dozens of applications, some of which run non stop for years on end.

I have a few extra FTDI cables laying around now if you wanted to borrow one to play with to see if it works. (I bought a few extras, the found a stash of them later)
 
Hmm, trying to come up with something generic that can get me in the ball park for all of this stuff
File#, Line#, Time, Variables, '\n'

File# is uint16_t, Line# is uint16_t, time is uint64_t, variables are what ever.
But to have a chance at parsing I need to pass the variable name and value. Or I won't know how to recover what it is!

I can't number the variables. I barely know what they are when written out. I won't remember what they are when I code this, and that makes the likelihood of a garbage log near certainty.

Code:
  uint16_t filenum = 0;  uint16_t linenum = 516; uint64_t timestamp = mycycles();
  FTDISerial.write( (uint8_t *) &filenum, sizeof(filenum) );
  FTDISerial.write( (uint8_t *) &linenum, sizeof(linenum) );
  FTDISerial.write( (uint8_t *) &timestamp, sizeof(timestamp) );
  // write out the variables you are interested in...
  FTDISerial.write('\n');

@dkemppai How is your's set up to log? Are you only logging a small amount of stuff?
 
@dkemppai How is your's set up to log? Are you only logging a small amount of stuff?
Bare minimum. It changes based on what I'm looking at. I define 'packets' with a 8 bit fixed header. For each header I know how much data to expect. No footer, no line terminations, etc. Not human readable. In some cases the packet may only contain the timestamp counter value, taken when the index pulse occurred, for example.

Processing starts with reading a header from the file then the fixed length of data based on the packet header. Rinse and repeat. Zero error checking.

This does require keeping track of what you put in the data stream following each header on both ends.

My writes look something like this
Code:
 if (FTDISerial.availableForWrite() > 8) {
    //FTDISerial.write(2);  //Write Encoder 1 timestamp header.
    //FTDISerial.write((uint8_t *)&Enc1IndexCycleCnt, sizeof(Enc1IndexCycleCnt));
  }

This is how all of the spindle speed, and lead screw position data was recorded when I was mapping my screw for errors. I sent the timestamp and encoder counts for all four encoders 2000 times per spindle revolution. All of the plots were constructed in the PC.
 
Back
Top