none
completion of UART write on raspberry v3 RRS feed

  • Question

  • i am trying to write a program for the PI3, running windows core IOT, which communicates via the UART.

    I would like to connect the PI to a bussed network.

    because of timing constraints I can't enable and disable the UART from the pin quick enough therefor i use a bus buffer.

    the driver enable of the buffer can be controlled fast enough.

    however with the code example below the await finishes before the uart is done sending the bytes and the driver enable (OePin) is written too soon.

    i can't find a solution to properly wait until all bytes are sent.

                            OePin.Write(GpioPinValue.Low);
                            byte[] reply = new byte[] {0x6A,0xAA,0x55,0x55,0xA6,0x95};
                            uint bytesWritten = await UartDev.OutputStream.WriteAsync(reply.AsBuffer());
                            OePin.Write(GpioPinValue.High);             


    • Edited by wallage1216 Wednesday, November 6, 2019 2:33 PM
    Wednesday, November 6, 2019 2:32 PM

All replies

  • Hello wallage1216,

    Please try with following code.

                    OePin.Write(GpioPinValue.Low);
                    byte[] reply = new byte[] { 0x6A, 0xAA, 0x55, 0x55, 0xA6, 0x95 };
    
                    using (var dataWriteObj = new DataWriter(serialPort.OutputStream))
                    {
                        dataWriteObj.WriteBytes(reply);
    
                        bytesWritten = await dataWriteObj.StoreAsync();
                        if (bytesWritten > 0)
                        {
                            OePin.Write(GpioPinValue.High);
                        }
                    }   


    Best Regards,

    Michael


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, November 7, 2019 2:22 AM
    Moderator
  • hi michael,

    thanks for the help.

    i tried your suggestion but that makes my app crash.

    below is my source code.

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using Windows.Devices.Enumeration;
    using Windows.Devices.Gpio;
    using Windows.Devices.SerialCommunication;
    using Windows.Storage.Streams;
    using Windows.UI.Xaml.Controls;
    
    // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
    
    namespace UartApp
    {
        /// <summary>
        /// An empty page that can be used on its own or navigated to within a Frame.
        /// </summary>
        public sealed partial class MainPage : Page
        {
            private static readonly byte[] reply = new byte[] { 0x6A, 0xAA, 0x55, 0x55, 0xA6, 0x95 };
    
            private SerialDevice UartDev;
            private DataWriter dataWriter;
            private Timer uartTimer;
            GpioController gpio;
            GpioPin OePin;
    
            public MainPage()
            {
                this.InitializeComponent();
                RunTask();
            }
    
            private async Task RunTask()
            {
    
                await InitGpio();
    
                await InitUart();
    
                /* Now that everything is initialized, create a timer so we send data every 100mS */
                uartTimer = new Timer(this.TimerCallback, null, 0, 100);
            }
    
            private async void TimerCallback(object state)
            {
                Task<UInt32> storeAsyncTask;
    
                OePin.Write(GpioPinValue.Low);
    
                // Load the data to the dataWriter object
                dataWriter.WriteBytes(reply);
    
                // Launch an async task to complete the write operation
                storeAsyncTask = dataWriter.StoreAsync().AsTask();
    
                UInt32 bytesWritten = await storeAsyncTask;
                
                OePin.Write(GpioPinValue.High);
            }
    
            private async Task InitUart()
            {
                string aqs = SerialDevice.GetDeviceSelector("UART0");
                var dis = await DeviceInformation.FindAllAsync(aqs);
                UartDev = await SerialDevice.FromIdAsync(dis[0].Id);
                UartDev.WriteTimeout = TimeSpan.FromMilliseconds(1000);
                UartDev.ReadTimeout = TimeSpan.FromMilliseconds(2);
                UartDev.BaudRate = 38400;
                UartDev.Parity = SerialParity.None;
                UartDev.StopBits = SerialStopBitCount.One;
                UartDev.DataBits = 8;
                dataWriter = new DataWriter(UartDev.OutputStream);
            }
    
            private async Task InitGpio()
            {
                gpio = await GpioController.GetDefaultAsync();
                OePin = gpio.OpenPin(23);
                OePin.Write(GpioPinValue.High); //default to high state before activating the pin
                OePin.SetDriveMode(GpioPinDriveMode.Output); //OE en low active thus disabling the buffer.
            }
    
        }
    
    }
    


    • Edited by wallage1216 Thursday, November 7, 2019 7:11 AM
    Thursday, November 7, 2019 7:09 AM
  • Hello wallage1216,

    I tested your code on my device, it works fine without crash. My Windows IoT Core version is build 17763.

    Have you debugged the app when running on the device?If possible, please provide the exception information.

    Best Regards,

    Michael


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, November 7, 2019 8:36 AM
    Moderator
  • hi michael,

    my code runs ok on my PI3, but the await is too short.

    i am also running build 17763.

     await storeAsyncTask;

    with your proposed code the application crashes without an exception which i also don't understand.

    it does say "program exited with code -1073741811 (0xc000000d)

    i tried putting all of it in a try/catch

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using Windows.Devices.Enumeration;
    using Windows.Devices.Gpio;
    using Windows.Devices.SerialCommunication;
    using Windows.Storage.Streams;
    using Windows.UI.Xaml.Controls;
    
    // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
    
    namespace UartApp
    {
        /// <summary>
        /// An empty page that can be used on its own or navigated to within a Frame.
        /// </summary>
        public sealed partial class MainPage : Page
        {
            private static readonly byte[] reply = new byte[] { 0x6A, 0xAA, 0x55, 0x55, 0xA6, 0x95 };
    
            private SerialDevice UartDev;
            private DataWriter dataWriter;
            private Timer uartTimer;
            GpioController gpio;
            GpioPin OePin;
    
            public MainPage()
            {
                this.InitializeComponent();
                RunTask();
            }
    
            private async Task RunTask()
            {
    
                await InitGpio();
    
                await InitUart();
    
                /* Now that everything is initialized, create a timer so we send data every 100mS */
                uartTimer = new Timer(this.TimerCallback, null, 0, 100);
            }
    
            private async void TimerCallback(object state)
            {
                OePin.Write(GpioPinValue.Low);
                byte[] reply = new byte[] { 0x6A, 0xAA, 0x55, 0x55, 0xA6, 0x95 };
                try
                {
                    using (var dataWriteObj = new DataWriter(UartDev.OutputStream))
                    {
                        dataWriteObj.WriteBytes(reply);
    
                        var bytesWritten = await dataWriteObj.StoreAsync();
                        if (bytesWritten > 0)
                        {
                            OePin.Write(GpioPinValue.High);
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
    
            private async Task InitUart()
            {
                string aqs = SerialDevice.GetDeviceSelector("UART0");
                var dis = await DeviceInformation.FindAllAsync(aqs);
                UartDev = await SerialDevice.FromIdAsync(dis[0].Id);
                UartDev.WriteTimeout = TimeSpan.FromMilliseconds(1000);
                UartDev.ReadTimeout = TimeSpan.FromMilliseconds(2);
                UartDev.BaudRate = 38400;
                UartDev.Parity = SerialParity.None;
                UartDev.StopBits = SerialStopBitCount.One;
                UartDev.DataBits = 8;
                dataWriter = new DataWriter(UartDev.OutputStream);
            }
    
            private async Task InitGpio()
            {
                gpio = await GpioController.GetDefaultAsync();
                OePin = gpio.OpenPin(23);
                OePin.Write(GpioPinValue.High); //default to high state before activating the pin
                OePin.SetDriveMode(GpioPinDriveMode.Output); //OE en low active thus disabling the buffer.
            }
    
        }
    
    }



    • Edited by wallage1216 Thursday, November 7, 2019 12:29 PM
    Thursday, November 7, 2019 11:17 AM
  • You mentioned that you are using a bus...RS485 or RS422? Check your hardware connections and make sure that your UART is not causing a short when transmitting.

    Dan DeMerchant

    Friday, November 8, 2019 2:22 AM
  • i have a logic analyzer connected to the output_enable signal for the bus buffer and as you can see below it goes low before the message starts but it goes back high before the message is done.

    this makes me think the await finishes too soon.

    as can be seen on the TX line the message is coming out of the UART completely.

    

    Friday, November 8, 2019 6:22 AM
  • Hello wallage1216,

    As far as i know, there is no Callback or API to indicate the bus buffer is clear. Can you accept a way of waiting some milliseconds after writing? Or if possible, you can add ACK communication protocol for that.

    Best Regards,

    Michael


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, November 8, 2019 9:25 AM
    Moderator
  • hi michael,

    thanks for the support.

    i was hoping there was another solution but i'll guess i have to accept a delay.

    Friday, November 8, 2019 11:25 AM
  • I might have a code solution for you... checking it out this morning. Additionally, have you considered using the RP’s flow control pin for the GPIO signal?

    Dan DeMerchant

    Friday, November 8, 2019 1:11 PM
  • I tried a bunch of methods on my setup as well and it seems that the task for writing characters to the port returns as soon as the port buffer is loaded.  I could only solve the problem by either (1) adding a small delay to the GPIO raise function or (2) increasing the baud rate.  I could not get the RTS function working on the P3I either...it just seems to stay low all of the time.  Whomever was involved writing the serialDevice part of Core hates blocking calls and buffer Peeks it seems.  Problems came up in other threads with the lack of actual implementation of ReadTimeout and WriteTimeout...

    Dan DeMerchant


    • Edited by danoplus Friday, November 8, 2019 5:20 PM
    Friday, November 8, 2019 5:19 PM