Main Site Documentation

USB Host -> FTDI : tips on changing latency settings?


#1

Hi.

I’ve got a project going where I’m using a FEZ Spider to control a 3D Printer. The printer has an Arduino Mega and that firmware usually talks over a usb/serial cable to a PC. My project is to have the FEZ replace the PC so I can move the printer around without having to drag a PC/laptop around, too.

I’ve got a lot of this working - I can use the FEZ touch-screen to select a file on an SD card and send it to the printer and the print head moves around and sorta behaves like I’d expect. The problem is that the movement is really jerky - something in the coms isn’t feeding the printer fast enough and what should be a series of smooth moves turns into a series of starts & stops.

I think I’m being bit by the default latency timer values in the FTDI cable and, in particular, by it slowing down the rate I get told about the printer ack’ing commands - the ack is just a small, 4 byte (“ok\r\n” ) response.
.
Anybody have any tips on how I’d go about adjusting the latency settings? Google supplies me with many, many tips on doing it from Windows (regedit or device manager) but I’m pretty sure those aren’t going to work on the Spider USB-host…


#2

Can you use a hardware serial port on the FEZ instead of a FTDI?


#3

I’ve got another (unfinished) project using a Panda II that does something like that. I think it’d work but it would also require a special cable to connect to the shield on the printer… I was hoping to avoid stuff like that, if at all possible, and have a more plug-n-play solution…


#4

I’m sure the FEZ is fast enough to communicate over a hardware serial port with zero latency.

By using USB, you’re creating a lot of overhead and delays that you don’t want here.

(I don’t know a 3D printer, but it would be nice if they had a movement buffer you could fill with position and timing data and then start the whole movement with a single command)


#5

Yup. That’s the way most of these machines work, though - usb ftdi cable from the PC to the printer… I’d really like to keep that model, if possible…

[quote](I don’t know a 3D printer, but it would be nice if they had a movement buffer you could fill with position and timing data and then start the whole movement with a single command)
[/quote]
That sorta is how it works… Home machines are almost all driven by a “gcode file” which is just a plain text series of movement commands - more details at http://reprap.org/wiki/G-code if you’re interested. You can get an idea how how quickly I need to send stuff here: http://www.youtube.com/watch?v=bIBuUfd4cwY - each move is around 30-60 bytes with a 4-byte ack.

My code on the Spider tries hard to keep the outgoing pipe to the printer as full as it can - it knows the serial buffer size (128 bytes on a Mega) and will send as many commands as it can at once, even before they’ve been acked.

I’ve spent a bunch of time trying to get things as fast & efficient as possible but I think the FTDI chip is slowing me down on the ack side - I’m nearly positive that it’s queuing up those 4-byte acks coming back from the printer so I get a bunch of acks at once instead of one at a time. That lets the send-side queue drain and causes jerky motion. :frowning:


#6

I think I’ve finally figured this out - ty, google!!

A couple bits of random code to help future fezzers who might be searching for this answer…

Consts gleaned from many different places: (though now what I know to look for, I’m sure there are many that have them all in one convenient place)


	const byte FTDI_RESET = 0x00;
	const byte FTDI_MODEM_CTRL = 0x01;
	const byte FTDI_SET_FLOW_CTRL = 0x02;
	const byte FTDI_SET_BAUD_RATE = 0x03;
	const byte FTDI_SET_DATA = 0x04;
	const byte FTDI_GET_MODEM_STATUS = 0x05;
	const byte FTDI_SET_EVENT_CHAR = 0x06;
	const byte FTDI_SET_ERROR_CHAR = 0x07;
	const byte FTDI_SET_LATENCY_TIMER = 0x09;
	const byte FTDI_GET_LATENCY_TIMER = 0x0A;

	const ushort FTDI_SIO_SET_DTR_MASK = 0x1;
	const ushort FTDI_SIO_SET_DTR_HIGH = (1 | (FTDI_SIO_SET_DTR_MASK << 8));
	const ushort FTDI_SIO_SET_DTR_LOW = (0 | (FTDI_SIO_SET_DTR_MASK << 8));
	const ushort FTDI_SIO_SET_RTS_MASK = 0x2;
	const ushort FTDI_SIO_SET_RTS_HIGH = (2 | (FTDI_SIO_SET_RTS_MASK << 8));
	const ushort FTDI_SIO_SET_RTS_LOW = (0 | (FTDI_SIO_SET_RTS_MASK << 8));

The actual code to set the latency and reset the arduino on the other end of the cable - “rawDevice” is USBH_RawDevice that you get from the USBHostController Connected event:


	ushort port = 1;

	// set DTR low for a second to reset arduino
	rawDevice.SendSetupTransfer(0X40, FTDI_MODEM_CTRL, FTDI_SIO_SET_DTR_LOW, port);
	Thread.Sleep(1000);

	// set DTR back to high to reboot, wait another second for it to come alive
	rawDevice.SendSetupTransfer(0X40, FTDI_MODEM_CTRL, FTDI_SIO_SET_DTR_HIGH, port);
	Thread.Sleep(1000);

	// set latency to 1ms; values between 1-255 are (supposedly) valid
	ushort latency = 1;
	rawDevice.SendSetupTransfer(0x40, FTDI_SET_LATENCY_TIMER, latency, port);

This was only tested on a device with vendor id 0x0403 and product id 0x6001 (FTDI 232R usb-serial, in my case).

edit: and, another note for those wondering why their usb-serial connection just doesn’t seem to want to do high-speed, the deal is that FTDI cables (which have a little chip in the cable itself) will buffer data and not send it until it’s collected +62 bytes or until (by default) 16ms have elapsed… This thread is about changing that 16ms to a lower value, 1ms in the case above. There’s (apparently) overhead in doing this - the cable sends “got nothing!” every 1ms now instead of every 16ms on an idle line - but if speed’s really important and you’re doing lots of little packets, it’s worth it!


#7

Thanks for sharing.


#8

Woohoo!! It works! Just did the first FEZ-driven print… :smiley:

[quote]I’m sure the FEZ is fast enough to communicate over a hardware serial port with zero latency.

By using USB, you’re creating a lot of overhead and delays that you don’t want here.
[/quote]
I was pretty worried about that - this printer is a real speed demon and any slow downs will totally hose the print. GC in particular worried me but I was careful to pre-allocate all the stuff I’d need before starting the print, run Debug.GC then not allocate anything else until the print finished… Some of these prints can go for many, many hours - days even.

Here’s the first print as it was going… It’s a little hard to see but it’s drawing ~1.5mm squares to fill in the center at 100mm/s. Each of these moves is ~35 bytes to the printer with a 4-byte ack coming back.


#9

Impressive!

Oh man, I need to finish my Mendel!!! :wall:

Btw, share your zelda theme in the following thread:

http://www.tinyclr.com/forum/1/4685/


#10

You do! And, if it’s a RAMPS board, you’ll be able to run it headless with a FEZ…

Now I just need to clean up the code some and start designing a case for the FEZ, which I’ll probably print via the FEZ… :o


#11

My goal is to use FEZ as “The board” for everything, well, almost for everything. I do have 4 stepper controllers separately.

As for the case, start with something like Base Camp, just for fun.

http://www.tinyclr.com/forum/21/4649/#/3/msg44471


#12

I’d love to see a FEZ-based printer - any time I go near the firmware for my printer, the arduino IDE makes me want to scream. That stuff’s just painful after you get used to msdev.

I’ve thought about doing hardware control (all the stuff the Mega does today) on a heavily-RLP’ed Panda or something and having that talk to a Spider or Hydra or something. If you did it instead, that’d be way better than me doing it! :slight_smile:

I may print one up - something like openscad can probably generate the model for it without too much trouble. Hm… Maybe a smaller version that you can print several times and snap/bolt/wiretie together would be nice.

There are a couple places I’d like to take the bot in the fairly-near future so the case is still pretty high on my list…


#13

Well, the speed looks great. I wouldn’t have even tried it over USB, so I’m glad you persisted!
Nice work!


#14

Thanks!

Until I actually saw it work, I wasn’t convinced it would work…

Next up is trying to figure out how to display the temperature without incurring GC or slowing down - no new strings while it’s running, if I can avoid it… :\


#15

Could be as simple as this:

string str = "XX°C";

str[0] = (char)(48 + (temp / 10));
str[1] = (char)(48 + (temp % 10));
Display(str);


#16

I’m not sure that’ll work - strings are imutable so any change results in a new string being allocated. I think the this[] indexer in string only supports gets, too…

I’m using Glide and, when not printing, am updating a TextBox control with the temperature. If I could set the text with a char[] or byte[], that’d be an excellent option. It seems to only take strings, though.

My plan A is to try to figure out how to render the TextBox text myself and pass that a char[]/byte[]. Plan B is to have static bitmaps for 0-9 and swap in the right ones as needed. Not horribly confident either will work as well as I hope, though… :\