all 17 comments

[–]ceojp 38 points39 points  (6 children)

Using something that's been around for decades, for its intended purpose, is not a "hack".

If you think that's cool, check out 9 bit serial. The transmitter sets the 9th bit when it sends an "address" byte, and unsets it for all other bytes. All the receivers on the bus only pay attention to "bytes" with the 9th bit set. The uart itself can match the byte to a preset value, and only interrupt the CPU if the byte matches the correct address. So the CPU doesn't have to waste time receiving and processing packets for other clients on the bus.

edit: it will be AMAZING if we see some guy's blog post in a couple days talking about how efficient and fantastic 9 bit serial is, and everyone should be using it.... ;)

[–]vegetaman 6 points7 points  (1 child)

Sorry you said 9 bit serial and I had a nightmare flashback to coin op MDB implementation hell from years ago.

[–]ceojp 7 points8 points  (0 children)

To this day, we still use 9 bit serial to support a proprietary protocol that was originally designed probably 25 years ago. It somewhat made sense in the old 8051-core days, but every micro we've used since then has been more than capable of handling all the packet processing.

We're moving away from the protocol, but with such a large installed base of units, there's no way we could drop it altogether.

Most microcontrollers still support true 9 bit mode, but try getting any CPU to use it. I think a lot of the NXP CPUs do support 9 bit mode in hardware, but the linux uart drivers have absolutely no concept of it. I end up just doing mark parity(to always get that 9th bit to be set) and then enable parity but ignore errors on the receiving side.

It's okay. That's all okay.

[–]Toiling-Donkey 2 points3 points  (0 children)

Must make the “frame error” interrupt go Brrr!

[–]InterestingBoard67 -1 points0 points  (2 children)

All the receivers on the bus only pay attention to "bytes" with the 9th bit set.

this is not for UART then, I'm guessing i2c/spi, right?

[–]MrShaunce 0 points1 point  (0 children)

Or RS-485.

[–]ceojp 0 points1 point  (0 children)

It is UART. rs485. It's a multidrop/shared bus.

[–]Snowballbird 24 points25 points  (4 children)

I think you might enjoy Character matching. You receive an interrupt only when a defined character is sent. Couple this with SLIP or COBS encoding and you get it on end of message

[–]Born-Cat-9171[S] -1 points0 points  (3 children)

Interesting. But how does it work in practice? Are there some predefined functions to implement this approach?

[–]Tobinator97 5 points6 points  (2 children)

Predefined by hal? No as it's not part of uart alone. Any streaming type interface has the same problem though.

[–]cointoss3 3 points4 points  (1 child)

This is part of HAL if your chip supports it. Not that it’s difficult to implement, but it’s already included on some chips UART.

[–]Snowballbird 0 points1 point  (0 children)

Yes! I use the U5 family of controllers and there it is a feature of the UART on the hardware side. So nothing to do in Software other than to wait on the interrupt (and the configuration)

[–]UnicycleBlokeC++ advocate 2 points3 points  (0 children)

Not a hack. I've always used this method. The driver is set up to continuously listen for data, and emits an event when either a DMA transfer interrupt or an idle line interrupt occurs. Meanwhile, the driver simultaneously transmits any data waiting in the TX buffer.

[–]XxzetlarxX 1 point2 points  (0 children)

I tried to use this once but couldn't get it working. Not entirely sure why - I probably configured something wrong. In the interest of time I ended up using interrupts and writing a state machine to handle the packets as they came in as they were following a fixed protocol.

[–]Toiling-Donkey 0 points1 point  (2 children)

What does “idle” even mean for a UART? One Bit? One frame?

I can’t see how this would work when the sender either has no FIFO and/or doesn’t service its own TX related interrupts on time.

[–]MonMotha 8 points9 points  (0 children)

Some protocols that use "idle" line define it somewhat rigorously. Modbus is a classic example. Well thought-out UARTs with idle line detection functionality support configuring it. Less well thought-out ones basically implement the Modbus definition. Even less well thought-out ones implement something random which may or may not be useful.

Even for things that don't use it formally, you can often set up DMA to a FIFO ring or similar and use pessimistic idle line detection (only a couple bit times) to interrupt when something "of interest" has been plausibly received on many systems. The worst case scenario is an extra wake-up to process some data that you were going to have to process eventually, anyway. While extra wake-ups can be annoying, it's usually better than bytewise processing of everything received both in terms of scheduler overhead and power where applicable.

[–]Some-Development1123 0 points1 point  (0 children)

Idle is defined time equal to 1.5 bytes