Uart.configure flags other than NO_CTSRTS

Hello,

I have an imp005 breakout board, and I want to use its UART0 for a flow-controlled UART communications application. I used it before at typical settings like 9600bps, 1 start and 1 stop bit, no parity, NO_CTSRTS flag, it works like a charm. It’s uart.configure is working, subsequent initializations are working as well and I can transmit bytes to the target device as shown by server.log messages.

But whenever I change the flags to enable flow control i.e. I have to use other flags other than NO_CTSRTS, it seems my device hangs up and no longer responds after the uart.configure call. Other subsequent initializations with server.log messages after that uart.configure no longer shows messages, hence I conclude device hanged up.

So far what I tried are to use flag 0 in uart.configure instead of NO_CTSRTS just like below:

ret = this.uart.configure(baudParm, 8, PARITY_NONE, 1, 0, printer_cb);

If I checked code syntax there is no problem, but after the uart.configure there is no more device response. I also tried to use flag CALLBACK_WITH_FLAGS and put a parameter inside the callback function:

ret = this.uart.configure(baudParm, 8, PARITY_NONE, 1, CALLBACK_WITH_FLAGS, printer_cb);

function printer_cb(parm) {
server.log(“UART read detected” + parm)
}

No code syntax errors reported, but just like above in flag 0, after the uart.configure there are no more server.logs from subsequent initializations printed leading me to conclude device hanged up.

Is there something I’m not doing right here? I just want to use RTS/CTS for UART0.

If you enable HW RTS/CTS on UART0, the uart will be looking for the CTS input to be low before it can transmit data. I don’t think the input is pulled low internally. It must be pulled or driven low externally. If you start transmitting on UART0, the first few bytes will go into the tx buffer (TX FIFO buffer is 80 bytes by default). Once the buffer is full, squirrel will suspend completely until the CTS input goes low. This has caught me out before. I don’t think the WRITE_HALF_DONE bit in the flags helped me either. The imp005 uart0 doesn’t behave like uarts on other imps.

As @cvrdrvn noted, if you’re seeing hangs then this is because the other end of the link has not dropped RTS (which is an output, and should be connected to CTS on the imp).

WRITE_HALF_DONE can be used on imps, including 005, to avoid blocking; if you never load more than half a TX FIFO full of data when you get that bit set in a status callback then you are guaranteed to never block (this is to ensure you can write responsive streaming TX code).

Thanks for the answers. That would mean I have to look out for the 3rd party board my imp005 is communicating with on why it’s not asserting the correct signal.

With this, I would like to change my approach to SW flow control in order to eliminate dependence on RTS/CTS lines. My question is now, is SW flow control supported in imp005 UART? Is it covered by the NO_CTSRTS flag in the uart.configure() API? As much as I want to eliminate flow control, the external board I’m communicating with only supports RTS/CTS and XON/XOFF flow controls.

XON/XOFF is pretty easy to implement in squirrel. The advantage of the imp005 is that you have massive amounts of RAM. You can set your rx buffer to something really large and just send the XOFF character with uart.write() when you want the sending party to temporarily stop. Once you’re ready to receive data again, just send an XON.
Flow control is less common nowadays. It was essential when you had modems/printers with limited throughput and devices that would try to stream lots of data to them. Do you need it because the imp is streaming data or because the 3rd party board (printer?) is streaming data to the imp?

If the device is a printer, it may well have USB (which is better for high throughput and has flow control too) - the USB stack on the imp is pretty easy to use, and USB printers are also generally really easy to use, mostly just having a single bulk OUT endpoint that you just fling data at.

If you have a multimeter you can just check the voltage of the CTS pin at the imp end. If it’s showing 3.3v, then the printer is not letting you send to it - that’s likely an unusual situation especially at the start of a transaction, so it could be a miswiring.

One thing… you aren’t just hooking up the printer’s external RS232 port to the imp are you? RS232 is not TTL serial, you need to use a level shifter as RS232 voltages will damage/destroy TTL serial.

Hi @cvrdrvn, actually from my imp005 side, I don’t think I’ll practically run out of buffer space. I also use the uart.flush() method to be extra certain. It’s from the 3rd party, external board that will more likely these flow control signals (RTS/CTS or XON/XOFF) may come from, as that board explicitly said it only supports RTS/CTS or XON/XOFF.

Hi @hugo it’s actually a thermal printer board. From its specs it has a 4KB buffer. As for the RS-232/TTL distinction, yes I’ve taken that into consideration. So, does the imp support XON/XOFF/SW flow control?

No, there is no software flow control in impOS (XON/XOFF). Which thermal printer? We’ve had various ones connected to imps in the past, eg Mini Thermal Receipt Printer : ID 597 : $49.95 : Adafruit Industries, Unique & fun DIY electronics and kits (that one has no flow control though)

@hugo It’s a Fujitsu FTP-62GMCL473 2" thermal printer.

Hmm, can’t find a datasheet on that one aside for the print engine (which connects to an interface board which has the serial). Got a link?

Also, keep in mind that XON/XOFF only works if either your data isn’t binary (ie it’s all printable characters) OR you can escape out any genuine data that corresponds to the XON or XOFF characters. In-band signalling affects the data :frowning:

It might be better to:

  • Wire the RTS output of the printer to a different imp005 input pin. Don’t use the CTS/RTS pins of uart0, as they aren’t addressable in squirrel.
  • Send data in chunks of a couple of KB and check the CTS input on the imp005 inbetween transmissions. If it’s high, wait until it goes low before sending more data.
  • Wire the CTS input of the printer to an imp005 output pin. Drive it low.

@cvrdrvn thanks for the suggestion. I see you’re suggesting for the hw flow control to be bit-banged. This means I have to carefully intervene with the serial transmission while frequently checking the bit-banged RTS/CTS signals? I always send my data through uart.write then flush it and assume these methods will do all the work for me. Does this mean I may have to do some separate buffering, and submit all print data to that buffer, then periodically do uart.write on buffer contents while checking for the bit-banged RTS/CTS?

I also observe that I don’t receive much data from the printer. It’s the imp that will be transmitting data most of the time to the printer. I’m thinking of this: since the printer supports SW flow control, it would be the side more likely to send XOFF in its TXD line (RXD in imp side) if it can’t receive any more and send XON if it can receive. Since those XON/XOFF will go through my (imp005) RXD side, I think the callback I registered through uart.configure will be called to handle that accordingly. So I’ll have to place code in that callback that stops transmission and wait for XON?

@hugo, as for the link, I don’t know if they share it online. I’m not sure either if I’m at liberty to share printer documents from work this since it’s covered with NDA. I’m checking which I can safely show that is not covered. So this printer you shared, it has no flow control. Does this have a large buffer and can handle large data like bit image in several KB?

The printer I shared has a 4kB buffer and no flow control.

As has been noted in this thread, imp005 does have hardware flow control and it does work - it’s even fully tested on our automated integration tests that run 24/7. Hence, the issue is not with the imp - and workarounds like software flow control are not needed.

What is needed is working out why the printer is asking you to not send anything to it. Maybe this is a miswiring, maybe this is a configuration that needs to be set on the printer… but the answer will likely be in the printer docs, and debugging this will require at least a multimeter, if not a cheap logic analyzer to capture the serial lines.

eg: https://www.amazon.com/KeeYees-Analyzer-Device-Channel-Arduino/dp/B07K6HXDH1/ref=sr_1_4?crid=NDICH4379ETO&dchild=1&keywords=logic+analyzer&qid=1615823440&sprefix=logic+analy%2Caps%2C218&sr=8-4

… $13.99, works with the open source Sigrok logic analyzer software.

I partially agree with @hugo here. If you can, hw flow control is definitely preferable to sw flow control. There are still a few quirks with the imp005 implementation to be mindful of.
If the printer is correctly wired to the imp and is driving its RTS (the imp’s CTS) low, you will be able to transfer data. Things can get tricky when the printer uses flow control to tell the imp to back off. You will be dependent on the WRITE_HALF_DONE bit in hardware.uart0.flags() to tell you to stop transmitting. I was not able to get this to work reliably on the imp005, but I could have got my code wrong. The documentation is slightly ambiguous as it doesn’t make it clear whether the flag bit is edge-triggered or level-triggered. Since the docs note that some other flag bits were not implemented on the imp005, I had assumed that this could have been one of them.

As an alternative, you could also wire the CTS input to a general input pin on the imp005 and setup a handler for change-of-state (CTS on uart0 is not addressible in Squirrel). This would notify you that flow control is/isn’t in effect. This is what I do.
As I’ve already mentioned, use a huge TX buffer on the imp005, big enough to accommodate the entire file you are sending. This will insure against Squirrel blocking if CTS is high for a prolonged period. Once the TX buffer overflows, it’s game over.

Thanks guys. I’ll take note of that especially the buffer size necessity. This buffer size is set by uart.settxfifosize() and its RX equivalent, right?

Yes. I think you can only do it if the uart is disabled, so call .settxfifosize() before calling .configure()

On the flags, etc: in imp005’s underlying silicon, all 3 UARTs are totally different implementations, and not all of them support the same flags.

However, WRITE_HALF_DONE is a software implemented flag, based on buffer space availability and so is the same on all imp types. It only sets as the FIFO drains past the halfway point, not as the FIFO is refilled by the application.

The bit doesn’t tell you to stop transmitting though - the purpose of this bit is to allow non-blocking streaming of large amounts of data. When you get this bit set in a flags callback, you can write half the TX FIFO size without incurring any blocking - and hence maintain TX streaming at high bitrates.

Hi @hugo, just want to clarify.

Hardware flow control (RTS/CTS) is working on imp005 as you said. That means UART0 HW flow control (only U0 has RTS/CTS pins). And to use that HW flow control, the flag I have to use in uart.configure() should NOT be NO_CTSRTS right? I don’t think I’ll be using other flags except that one related to RTS/CTS, so is it correct to use 0 as my flag? Just like below:

uart.configure(baudParm, 8, PARITY_NONE, 1, 0, printer_cb);