1

I'm trying to setup a simple connection over SPI, but when trying to get a SpiDevice, the SpiDevice.FromIdAsync method never finishes. This happens almost always, with a few rare exceptions that seem random.

spi = await SpiDevice.FromIdAsync(dis[0].Id, settings);

The code used to setup the connection comes from https://learn.microsoft.com/en-us/windows/iot-core/learn-about-hardware/pinmappings/pinmappingsrpi#spi-bus.

In the example, I output a single byte to a LED driver working as a shift register. I use a Raspberry Pi 3 as target device and Visual Studio Community 2017 as my IDE.

MainPage.xaml.cs

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.Devices.Gpio;
using Windows.Devices.Spi;
using Windows.Devices.Enumeration;
using System.Threading.Tasks;

namespace SPI_Test
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();

            try
            {
                InitGPIO();
                InitSpi().Wait();

                timer = new DispatcherTimer();
                timer.Interval = TimeSpan.FromMilliseconds(500);
                timer.Tick += Timer_Tick;
            }
            catch (Exception)
            {

            }
        }

        GpioPin enablePin;
        SpiDevice spi;

        private void InitGPIO()
        {
            var gpio = GpioController.GetDefault();

            //create pin to control the output of the LED driver
            //the outputs are active when the pin is low
            enablePin = gpio.OpenPin(12);
            enablePin.Write(GpioPinValue.High); //disable outputs at first
            enablePin.SetDriveMode(GpioPinDriveMode.Output);
        }

        private async Task InitSpi()
        {
            try
            {
                // Use chip select line CS0
                var settings = new SpiConnectionSettings(0);
                // Set clock to 10MHz 
                settings.ClockFrequency = 10000000;

                // Get a selector string that will return our wanted SPI controller
                string aqs = SpiDevice.GetDeviceSelector("SPI0");

                // Find the SPI bus controller devices with our selector string
                var dis = await DeviceInformation.FindAllAsync(aqs);

                spi = await SpiDevice.FromIdAsync(dis[0].Id, settings);  /* Create an SpiDevice with our bus controller and SPI settings */

            }
            /* If initialization fails, display the exception and stop running */
            catch (Exception ex)
            {
                throw new Exception("SPI Initialization Failed", ex);
            }
        }

        private DispatcherTimer timer;
        private byte value = 0;
        private void Timer_Tick(object sender, object e)
        {
            enablePin.Write(GpioPinValue.High); //disable outputs
            spi.Write(new byte[] { value++ }); //send the current value to the LEDs and increase by 1
            enablePin.Write(GpioPinValue.Low); //re-enable outputs
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            timer.Start();
        }
    }
}

MainPage.xaml

<Page
    x:Class="SPI_Test.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:SPI_Test"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button Click="Button_Click" Content="Start" Margin="15" />
        </StackPanel>
    </Grid>
</Page>
branbu28
  • 58
  • 6

1 Answers1

1

You are experiencing a deadlock because of the mixing of blocking calls .Wait() and asynchronous calls. I would suggest moving that logic to an event handler. Like Loaded

public MainPage() {
    this.InitializeComponent();
    this.Loaded += async (sender, e) => {
        try {
            InitGPIO();
            await InitSpi();

            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(500);
            timer.Tick += Timer_Tick;
        } catch (Exception) {

        }
    };
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • Thanks for your answer. It now works. I never really heard about deadlocks. I found this article http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html and it helped me to understand the problem. – branbu28 Sep 22 '17 at 16:39