Search code examples
c#serial-portuwpserial-communicationwindowsiot

UWP app slows, then crashes after certain number of serial writes


I am making an application using Windows IoT Core on the Raspberry Pi 3.

I am trying to communicate with an Arduino using serial communication. I have used most of the methods shown in this example on GitHub for creating the serial device and writing to it: https://github.com/ms-iot/samples/tree/develop/SerialSample/CS.

The program runs fine for the first 130 bytes or so, but then will begin to slow down dramatically after that and crash around the 135th byte or so.

Sometimes it causes the Raspberry Pi to display the Windows 10 "blue screen of death" saying that it needs to restart.

I've tried rewriting the code many ways and using different variations of async, task, and await, but can't seem to get it to work.

Here's the code I use to initialize the serial device:

private async void setup()
{
    serialPort = await initializeSerial();
}

private async Task<SerialDevice> initializeSerial()
{
    try
    {
        string aqs = SerialDevice.GetDeviceSelector();
        var dis = await DeviceInformation.FindAllAsync(aqs);

        for (int i = 0; i < dis.Count; i++)
        {
            if (dis[i].Name.Contains("Arduino Uno"))
            {
                var serialPort = await SerialDevice.FromIdAsync(dis[i].Id);

                /* Configure serial settings */
                serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
                serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
                serialPort.BaudRate = 9600;
                serialPort.Parity = SerialParity.None;
                serialPort.StopBits = SerialStopBitCount.One;
                serialPort.DataBits = 8;
                serialPort.Handshake = SerialHandshake.None;

                // Display configured settings
                //Debug.WriteLine("Serial port configured successfully.");

                // Create cancellation token object to close I/O operations when closing the device
                ReadCancellationTokenSource = new CancellationTokenSource();


                return serialPort;
            }
        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.Message);
    }

    return null;
}

and here's the code I use to write to the serial device:

private async void sendString(string stringToSend)
{
    try
    {
        if (serialPort != null)
        {
            // Create the DataWriter object and attach to OutputStream
            dataWriteObject = new DataWriter(serialPort.OutputStream);

            //Launch the WriteAsync task to perform the write
            await WriteAsync(stringToSend);
        }
        else
        {
            status.Text = "Select a device and connect";
        }
    }
    catch (Exception ex)
    {
        status.Text = "sendString: " + ex.Message;
    }
    finally
    {
            // Cleanup once complete
            if (dataWriteObject != null)
            {
                dataWriteObject.DetachStream();
                dataWriteObject = null;
            }
    }
}

/// <summary>
/// WriteAsync: Task that asynchronously writes data from the input text box 'sendText' to the OutputStream 
/// </summary>
/// <returns></returns>
private async Task WriteAsync(string stringToWrite)
{
    Task<UInt32> storeAsyncTask;

    dataWriteObject.WriteString(stringToWrite);                

    // Launch an async task to complete the write operation
    storeAsyncTask = dataWriteObject.StoreAsync().AsTask();

    UInt32 bytesWritten = await storeAsyncTask;
    if (bytesWritten > 0)
    {
        counter++;
        status.Text = stringToWrite + ", ";
        status.Text += "bytes written successfully! (" + counter + ")";
    }       
}

Any help/advice would be appreciated.

Update

I rewrote my sendString method as this and simplified it using a using statement:

private async void sendString(string stringToSend)
{
    using (DataWriter dataWriter = new DataWriter(serialPort.OutputStream))
    {
        dataWriter.WriteString(stringToSend);
        await dataWriter.StoreAsync();
        //await dataWriter.FlushAsync();
        dataWriter.DetachStream();

        counter++;
        status.Text = stringToSend + ", ";
        status.Text += "bytes written successfully! (" + counter + ")";
    }
}

However, the problem still persists.


Solution

  • I tried using the UART pins instead of the USB cable to write data, and experienced no more issues. Here's the code I used to initialize the UART bus on the Pi and I used the same function to write as I used above:

    private async Task<SerialDevice> initializeSerial()
    {
        try
        {
            string aqs = SerialDevice.GetDeviceSelector("UART0");
            var dis = await DeviceInformation.FindAllAsync(aqs);
    
            SerialDevice serialPort = await SerialDevice.FromIdAsync(dis[0].Id);
    
            /* Configure serial settings */
            serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
            serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
            serialPort.BaudRate = 9600;
            serialPort.Parity = SerialParity.None;
            serialPort.StopBits = SerialStopBitCount.One;
            serialPort.DataBits = 8;
            serialPort.Handshake = SerialHandshake.None;
    
            status.Text = "Serial port configured succesfully.";
    
            return serialPort;
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
    
        status.Text = "Serial port not configured successfully. Are you sure a serial device is connected?";
        return null;
    }
    

    This doesn't exactly answer the problem with sending data over the USB cable, but I'm posting it here in case anyone has a similar problem with using the USB port and would like to try this instead.