Comments (8)
+1 for this issue.
from lightning.
I haven't had a chance to try modifying yet but for some reason with the UWP section Exclusive mode is set when creating the device: DmapSupport.cpp#L162
I expected that line to use shareMode instead as I can't see a comment explaining why it is explicitly set.
from lightning.
That does resolve it. I tried it a few days ago and confirmed.
from lightning.
Interesting to hear that. I just tried changing it to DeviceSharingMode::Sharing which still works fine for one device but as soon as I try to create the second I get a blue screen error.
Would you mind sharing the changes you did to make this work?
from lightning.
I literally changed the word "Exclusive" on that line you linked to "Shared". Sounds like there might be something else going on in your case. Could you post some sample code that recreates your specific scenario?
from lightning.
Sure hopefully this code snippet will be enough to show what I'm doing at the moment.
I'm registering this class as a service and using it throughout my project (though in this case only one viewmodel is using it).
I have a few INA219 boards so I figured I'd build it as a library for Adafruit components for future use.
It's a simple class to use. To get a device call await _controller.GetDeviceAsync(address, i2cChannel);
and it will give back a class which stores the address and channel with a helper function to retrieve the dictionary reference when reading / writing to the device.
After that you use the Read, ReadPartial, Write, WritePartial functions as you would normally to communicate with the devices. This was done because I tried to change the SlaveAddress of a single device to get the desired effect. The class could be restored now to return the I2cDevice instead but for the moment that isn't my problem.
Try calling e.g. await _controller.GetDeviceAsync(address.GetHashCode(), channel);
with two different address' and the second one will cause a bluescreen to occur.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Microsoft.IoT.Lightning.Providers;
using Windows.Devices;
using Windows.Devices.I2c;
namespace Adafruit
{
public class I2cController : II2cController
{
// I2c Controllers
private Dictionary<int, Windows.Devices.I2c.I2cController> _controllers;
// I2c Devices
private Dictionary<Tuple<int, int>, Windows.Devices.I2c.I2cDevice> _devices;
public I2cController()
{
_controllers = new Dictionary<int, Windows.Devices.I2c.I2cController>();
_devices = new Dictionary<Tuple<int, int>, Windows.Devices.I2c.I2cDevice>();
}
/// <summary>
/// Initialize the I2C Bus
/// </summary>
/// <param name="i2cChannel">Channel of i2C output</param>
/// <returns>True if port opened successfully</returns>
private async Task InitializeControllerAsync(int i2cChannel = 1)
{
if (_controllers.ContainsKey(i2cChannel)) return;
if (LightningProvider.IsLightningEnabled)
{
if (LowLevelDevicesController.DefaultProvider == null)
LowLevelDevicesController.DefaultProvider = LightningProvider.GetAggregateProvider();
var controller = (await Windows.Devices.I2c.I2cController.GetControllersAsync(LightningI2cProvider.GetI2cProvider()))[i2cChannel - 1];
if (controller == null) throw new IndexOutOfRangeException("i2C channel doesn't exist.");
_controllers.Add(i2cChannel, controller);
}
}
/// <summary>
/// Try to register and return a device. Will also pass and return the details of the device if it's already registered
/// </summary>
/// <param name="address">Address of the device</param>
/// <returns>I2c device</returns>
public async Task<I2cDeviceDetails> GetDeviceAsync(int address, int i2cChannel = 1)
{
var deviceAddress = new Tuple<int, int>(i2cChannel, address);
await InitializeControllerAsync(i2cChannel);
if (_devices.ContainsKey(deviceAddress)) return new I2cDeviceDetails(i2cChannel, address);
var settings = new I2cConnectionSettings(address) { SharingMode = I2cSharingMode.Shared };
// Direct Memory Mapped (Lightning) Driver
if (Microsoft.IoT.Lightning.Providers.LightningProvider.IsLightningEnabled)
{
var newDevice = _controllers[i2cChannel].GetDevice(settings);
if (newDevice == null) throw new ArgumentOutOfRangeException("Failed to get i2C device.");
_devices.Add(deviceAddress, newDevice);
}
// Inbox Driver - not tested
else
{
var aqs = Windows.Devices.I2c.I2cDevice.GetDeviceSelector(string.Format("I2C{0}", i2cChannel));
var deviceInformation = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(aqs, null);
settings.SharingMode = I2cSharingMode.Shared;
var newDevice = await Windows.Devices.I2c.I2cDevice.FromIdAsync(deviceInformation[0].Id, settings);
if (newDevice == null) throw new ArgumentOutOfRangeException("Failed to get i2C device.");
_devices.Add(deviceAddress, newDevice);
}
return new I2cDeviceDetails(i2cChannel, address);
}
/// <summary>
/// Reads data from the inter-integrated circuit (I2C) bus on which the device is
/// connected into the specified buffer.
/// </summary>
/// <param name="device">Device to Write then Read from.</param>
/// <param name="buffer">
/// The buffer to which you want to read the data from the I2C bus. The length of
/// the buffer determines how much data to request from the device.
/// </param>
public void Read(I2cDeviceDetails device, [Range(0, int.MaxValue)] byte[] buffer)
{
if (!_devices.ContainsKey(device.GetDeviceAddress())) throw new NullReferenceException(string.Format("I2C Controller {0} isn't initialized.", device.Channel));
_devices[device.GetDeviceAddress()].Read(buffer);
}
/// <summary>
/// Reads data from the inter-integrated circuit (I2C) bus on which the device is
/// connected into the specified buffer, and returns information about the success
/// of the operation that you can use for error handling.
/// </summary>
/// <param name="device">Device to Write then Read from.</param>
/// <param name="buffer">
/// The buffer to which you want to read the data from the I2C bus. The length of
/// the buffer determines how much data to request from the device.
/// </param>
/// <returns>
/// A structure that contains information about the success of the read operation
/// and the actual number of bytes that the operation read into the buffer.
/// </returns>
public I2cTransferResult ReadPartial(I2cDeviceDetails device, [Range(0, int.MaxValue)] byte[] buffer)
{
if (!_devices.ContainsKey(device.GetDeviceAddress())) throw new NullReferenceException(string.Format("I2C Controller {0} isn't initialized.", device.Channel));
return _devices[device.GetDeviceAddress()].ReadPartial(buffer);
}
/// <summary>
/// Writes data to the inter-integrated circuit (I2C) bus on which the device is
/// connected, based on the bus address specified in the I2cConnectionSettings object
/// that you used to create the I2cDevice object.
/// </summary>
/// <param name="device">Device to Write then Read from.</param>
/// <param name="buffer">A buffer that contains the data that you want to write to the I2C device. This
/// data should not include the bus address.
/// </param>
public void Write(I2cDeviceDetails device, byte[] buffer)
{
if (!_devices.ContainsKey(device.GetDeviceAddress())) throw new NullReferenceException(string.Format("I2C Controller {0} isn't initialized.", device.Channel));
_devices[device.GetDeviceAddress()].Write(buffer);
}
/// <summary>
/// Writes data to the inter-integrated circuit (I2C) bus on which the device is
/// connected, and returns information about the success of the operation that you
/// can use for error handling.
/// </summary>
/// <param name="device">Device to Write then Read from.</param>
/// <param name="buffer">
/// A buffer that contains the data that you want to write to the I2C device. This
/// data should not include the bus address.
/// </param>
/// <returns>
/// A structure that contains information about the success of the write operation
/// and the actual number of bytes that the operation wrote into the buffer.
/// </returns>
public I2cTransferResult WritePartial(I2cDeviceDetails device, byte[] buffer)
{
if (!_devices.ContainsKey(device.GetDeviceAddress())) throw new NullReferenceException(string.Format("I2C Controller {0} isn't initialized.", device.Channel));
return _devices[device.GetDeviceAddress()].WritePartial(buffer);
}
/// <summary>
/// Performs an atomic operation to write data to and then read data from the inter-integrated
/// circuit (I2C) bus on which the device is connected, and sends a restart condition
/// between the write and read operations.
/// </summary>
/// <param name="device">Device to Write then Read from.</param>
/// <param name="writeBuffer">
/// A buffer that contains the data that you want to write to the I2C device. This
/// data should not include the bus address.
/// </param>
/// <param name="readBuffer">
/// The buffer to which you want to read the data from the I2C bus. The length of
/// the buffer determines how much data to request from the device.
/// </param>
public void WriteRead(I2cDeviceDetails device, byte[] writeBuffer, [Range(0, int.MaxValue)] byte[] readBuffer)
{
if (!_devices.ContainsKey(device.GetDeviceAddress())) throw new NullReferenceException(string.Format("I2C Controller {0} isn't initialized.", device.Channel));
_devices[device.GetDeviceAddress()].WriteRead(writeBuffer, readBuffer);
}
/// <summary>
/// Performs an atomic operation to write data to and then read data from the inter-integrated
/// circuit (I2C) bus on which the device is connected, and returns information about
/// the success of the operation that you can use for error handling.
/// </summary>
/// <param name="device">Device to Write then Read from.</param>
/// <param name="writeBuffer">
/// A buffer that contains the data that you want to write to the I2C device. This
/// data should not include the bus address.
/// </param>
/// <param name="readBuffer">
/// The buffer to which you want to read the data from the I2C bus. The length of
/// the buffer determines how much data to request from the device.
/// </param>
/// <returns>
/// A structure that contains information about whether both the read and write parts
/// of the operation succeeded and the sum of the actual number of bytes that the
/// operation wrote and the actual number of bytes that the operation read.
/// </returns>
public I2cTransferResult WriteReadPartial(I2cDeviceDetails device, byte[] writeBuffer, [Range(0, int.MaxValue)] byte[] readBuffer)
{
if (!_devices.ContainsKey(device.GetDeviceAddress())) throw new NullReferenceException(string.Format("I2C Controller {0} isn't initialized.", device.Channel));
return _devices[device.GetDeviceAddress()].WriteReadPartial(writeBuffer, readBuffer);
}
}
}
from lightning.
Just to keep things simple using my own local build of the lightning provider which references a local copy of Microsoft.IoT.Lightning and Microsoft.IoT.SDKFromArduino which are fully up to date. The only change done is to the Microsoft.IoT.Lightning to set to Shared.
decimal _flowOne = 0m;
public decimal FlowOne { get { return _flowOne; } set { Set(ref _flowOne, value); } }
decimal _flowTwo = 0m;
public decimal FlowTwo { get { return _flowTwo; } set { Set(ref _flowTwo, value); } }
private async Task MonitorSensorsAsync()
{
if(Microsoft.IoT.Lightning.Providers.LightningProvider.IsLightningEnabled)
{
if(Windows.Devices.LowLevelDevicesController.DefaultProvider == null)
{
Windows.Devices.LowLevelDevicesController.DefaultProvider = Microsoft.IoT.Lightning.Providers.LightningProvider.GetAggregateProvider();
var controller = (await Windows.Devices.I2c.I2cController.GetControllersAsync(Microsoft.IoT.Lightning.Providers.LightningI2cProvider.GetI2cProvider()))[0];
var deviceOne = controller.GetDevice(new Windows.Devices.I2c.I2cConnectionSettings(40) { SharingMode = Windows.Devices.I2c.I2cSharingMode.Shared });
var deviceTwo = controller.GetDevice(new Windows.Devices.I2c.I2cConnectionSettings(41) { SharingMode = Windows.Devices.I2c.I2cSharingMode.Shared });
FlowOne = await ReadRegisterAsync(deviceOne, 0x01);
FlowTwo = await ReadRegisterAsync(deviceTwo, 0x01);
}
}
}
private void WriteRegister(Windows.Devices.I2c.I2cDevice device, byte register, int value)
{
device.WritePartial(
new byte[] {
register,
(byte)((value >> 8) & 0xFF),
(byte)(value & 0xFF)
});
}
private async Task<int> ReadRegisterAsync(Windows.Devices.I2c.I2cDevice device, byte register)
{
device.Write(new byte[] { register });
await Task.Delay(100); // Max 12-bit conversion time is 586us per sample (default 128 samples = 69ms)
var readBuffer = new byte[2];
var result = device.ReadPartial(readBuffer);
return readBuffer[0] << 8 | readBuffer[1];
}
Still having the same issue when the second device is created using GetDevice it blue screens with "SYSTEM_SERVICE_EXCEPTION"
I'm running into this problem on a Raspberry Pi 2 (with the official display connected). Windows Core is fully up to date.
from lightning.
Just to follow up as @sidwarkd said changing that value to Shared works fine. My problem was due to a wiring error.
Thanks for your help.
from lightning.
Related Issues (20)
- `VirtualShield::Hash()` function does not work as intended. HOT 2
- #define PROGMEM HOT 4
- analogRead - case where ioPin is not initialized on invalid pin value. HOT 1
- analogRead(A0) results in uninitialized ioPin HOT 1
- PWM does not initialize correctly for pin A1-A8 HOT 1
- Why RPi2 hardware PWM is not utilized? HOT 5
- Performance Document Refresh HOT 1
- I2C Device disabled when using DMMD, enabled with Inbox Driver. HOT 2
- DebounceTimeout has no effect HOT 4
- The ValueChanged-event of a GPIO Pin with MinnowBoard MAX not working HOT 4
- The library does not work with console APP HOT 1
- Custom GpioProvider HOT 1
- GpioChangeReader not working with Direct Memory Mapped Driver
- DMAP error - interface specification -- where is it? HOT 1
- Is this dead?
- Missing paren in PSTR definition. HOT 1
- Raspberry Pi Gpio Input Modes HOT 3
- Raspberry Pi PWM HOT 1
- Interrupts using identical code does not work with Lightning drivers for RPi 3B HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from lightning.