SoftwareSerial for low baud rate

In my application, all COM ports and USB are used (USB hub is not an option). I need to interface with yet another serial device (at 2400 baud) which will transmit a 12 ASCII character string at random times twice a day.

I’m looking for a SoftwareSerial solution for receiving the data. Is PinCapture or InterruptPort the preferred route?

Has anyone done this before or have some sample code?

You can use, interrupt port, PinCapture or software UART in RLP.

I’m trying to avoid going down the RLP rabbit hole just yet.

Working with PinCapture or InterruptPort, I’ve captured the OnInterrupt event and I can see the pin toggles via changing values of the data2 parameter. I can also see the time difference between toggles using the time parameter.

The data1 parameter is a constant value and I can’t find any good documentation on the event parameters. What is the data1 parameter supposed to represent?

I data1 represents the port, and data2 represents the state of the port 0/1. I think data1 is the CPU pin number.

I got this info from the Beginners Guide, which everyone should read carefully.

@ Mike
I’ve read the Beginners Guide several times for different reasons. It’s not hard to miss this events parameters since the only clue is the name of the parameters in one line of code.

Nevertheless, it was enough info. Thanks for the clarification.

@ Everyone
I’ve been working on the SoftwareSerial implementation for hours, but it appears to be beyond my reach. Here’s as far as I’ve gotten:

Connected to a COM port, I receive the following 12 characters:

4800E51DFF4F

Using the code below, I’m getting the following states in the OnInterrupt event:

0101010101010101010101010110101011010101010101010101010101010101010101010101010101010101


        public static void Main()
        {
            InterruptPort port = new InterruptPort((Cpu.Pin)FEZ_Pin.Digital.Di2, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptNone);
            port.OnInterrupt += InterruptPort_OnInterrupt;

            var counter = 0;
            while (true)
            {
                if (_receivingData)
                {
                    if (counter++ > 20)
                    {
                        var bitString = "";
                        for (var i = 0; i < _bitChange; i++)
                        {
                            bitString += StateChanges[i];
                        }
                        Debug.Print("StateChanges (" + _bitChange + "): " + bitString);

                        _receivingData = false;
                        _bitChange = 0;
                        counter = 0;
                    }
                }
                Thread.Sleep(100);
            }
        }

        private static readonly uint[] StateChanges = new uint[100];
        private static readonly long[] BitTimings = new long[100];
        private static byte _bitChange;
        private static bool _receivingData;
        static void InterruptPort_OnInterrupt(uint port, uint state, DateTime time)
        {
            if (!_receivingData) _receivingData = true;

            StateChanges[_bitChange] = state;
            BitTimings[_bitChange] = time.Ticks;

            _bitChange++;
        }

How might I translate the states and timings into the 12 character sequence I’m expecting?

Tarannar

You need to use both the state and the duration to virtually recreate the “waveform” of the signal and find the bits to de-serialize

How about a parallel to serial chip? Maxim do a couple… TI do as well… Or an SPI to Serial splitter - You can often get up to 8 or so Serials out of one SPI splitter, as long as you’re not using them at a high duty cycle.

Depends on your situation I guess, but hardware does seem to be the easy and trouble-free way to go if you’re running out of serial ports.

Serial communications are using 8N1. The bits for character “F” would be:

F = ASCII 70 = 01000110

With a start bit and 1 stop bit, would the sequence of bits look like:

0 01000110 1

Taranar, if you are at TTL level, not RS232 level, the default level is high.
Then start bit is low, followed by bit 0 (LSB) to 7 (MSB), following by STOP bit at high
For example transmission of 0x62 would be :


_______     _       _._   _._______
       |_._| |_._._|   |_|
        S 0 1 2 3 4 5 6 7 s


At 2400 each bit duration should be 416 us

Use PinCapture with mode Read( false, …) to wait for the low state
So in theory the buffer should be :
832
416
1248
832
416

Now if you are waiting for 12 characters twice a day, you need to size your buffer and Read timeout accordingly.
Worst case is every bit is different from the previous one, so 12 characters ~= 120 values with a timeout of 120/2400= 50ms.
To be sure, take uint[150] and a timeout of 100ms and you should be fine.

However, take care : I’ve done some experiment lately to make a routine to automatically find the baudrate of a transmission using PinCapture. The values I retreived from Read()f or a single bit at 38400 were between 19 to 30 while in theory it shouldhave been 26.
So your code must take into account that you know the baudrate and should be resilient to approximative measurements.

Now with regards to suggestions for parallel to serial solutions this is certainly the safer solution. Take care that what you need is a UART. A basic shift register will not work.
A solution could be an UART with SPI interface such as the MAXIM MAX3100 Mixed-signal and digital signal processing ICs | Analog Devices
Or NXP SC16IS750IBS (available at Digikey)
This would be much more reliable than software UART

@ Barbudor

Thanks for the very thorough response. I’m pretty close to having the solution and your information is definitely helpful. I’m a software guy by trade which is why I was looking for a software solution. However, we’re bringing on board an electrical engineer this week, so we’ll also explore your suggested hardware solution.

Point taken that the hardware solution is more reliable than the software solution.

Thanks

I don’t think PinCapture will be good…

PinCapture blocks all managed threads until a number of pin toggles have been detected or a timeout occurs. What is going to happen to everything else that is going on when threading is blocked?

@ Mike

I’m using an InterruptPort for that reason since I don’t know when the data will come in, but the general operation of the communications that @ Barbudor provided was helpful.

Thanks

Using PinCapture and its read method, I’m able to receive the expected data 100% of the time. However, the blocking issue is a show stopper.

I’ve been working with the InterruptPort as well. I’m taking the difference between OnInterrupt ticks as a measure of the duration of the bit state. Unfortunately, I’m getting some strange results. I’m always getting the right amount of bits. However, bytes 6 and 7 of the expected 16 bytes (not 12 as mentioned above) are always incorrect. Strange thing is bytes 1-5 and 8-16 are always correct.

So, it’s looking like I’ll have to dive into the RLP world (or additional hardware) unless someone has an idea of the strange behavior I’m getting.

Seems like an interrupt-driven PinCapture with user specified timeout would be a nice feature request? Gus?

Basically a logic analyzer with a trigger that can be made into a protocol analyzer. I can think of a bunch of uses for that.

Maybe you could also catch the start bit with an interrupt port and then capture the rest of the sequence with PinCapture. This should work for low baud rates and get past the blocking problem. It will depend on how fast the interrupt handler is entered… You need to start capturing before the start of the first bit.

What really messes this stuff up is that there is no guaranteed transition between the start bit and the first bit. If your first bit is also 0, you’ll have to “guess” where the middle of the pulse is to sample - but with some known delays it should be possible to calculate it.

Possible but everyone would want it a bit different so we leave it out for RLP. Even PinCapture itself maybe taken out in favor of RLP.