Closed shaggygi closed 5 years ago
Awesome, yeah I saw the announcement yesterday. I'm almost sure that .net core should run just fine there, so we shouldn't have to worry but it is nice to have this to be able to track the documentation change.
Not working for me under netcore 3.0 preview6. The code is working fine on pi 3/3+/cm3+. Pi 4 (2GB) with Buster installed. Unless I forgot some dependancy for System.Device.Gpio.Driver on the Pi 4! nuget pkg are 0.1.0 pre-19310.5
Unhandled Exception: System.AggregateException: One or more errors occurred. (Error 0 initializing the Gpio driver.) ---> System.IO.IOException: Error 0 initializing the Gpio driver. at System.Device.Gpio.Drivers.RaspberryPi3Driver.Initialize() at System.Device.Gpio.Drivers.RaspberryPi3Driver.OpenPin(Int32 pinNumber) at System.Device.Gpio.GpioController.OpenPin(Int32 pinNumber) at System.Device.Gpio.GpioController.OpenPin(Int32 pinNumber, PinMode mode) at Device.BG96Iot.BG96Iot..ctor() in H:\PROJECTS.2019\RPITest\RpiBG96Test\ConsoleApp1\BG96Iot.cs:line 61 at RpiBG96Test.Program.MainSetup() in H:\PROJECTS.2019\RPITest\RpiBG96Test\ConsoleApp1\Program.cs:line 30 at RpiBG96Test.Program.MainLoop() in H:\PROJECTS.2019\RPITest\RpiBG96Test\ConsoleApp1\Program.cs:line 38 --- End of inner exception stack trace --- at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken) at System.Threading.Tasks.Task.Wait() at RpiBG96Test.Program.Main(String[] args) in H:\PROJECTS.2019\RPITest\RpiBG96Test\ConsoleApp1\Program.cs:line 24 ---> (Inner Exception #0) System.IO.IOException: Error 0 initializing the Gpio driver. at System.Device.Gpio.Drivers.RaspberryPi3Driver.Initialize() at System.Device.Gpio.Drivers.RaspberryPi3Driver.OpenPin(Int32 pinNumber) at System.Device.Gpio.GpioController.OpenPin(Int32 pinNumber) at System.Device.Gpio.GpioController.OpenPin(Int32 pinNumber, PinMode mode) at Device.BG96Iot.BG96Iot..ctor() in H:\PROJECTS.2019\RPITest\RpiBG96Test\ConsoleApp1\BG96Iot.cs:line 61 at RpiBG96Test.Program.MainSetup() in H:\PROJECTS.2019\RPITest\RpiBG96Test\ConsoleApp1\Program.cs:line 30 at RpiBG96Test.Program.MainLoop() in H:\PROJECTS.2019\RPITest\RpiBG96Test\ConsoleApp1\Program.cs:line 38<---
Aborted
mm interesting, I wonder if that has anything to do with buster being installed instead of Raspbian. Can you see the file /dev/gpiomem
? Are you running as sudo?
Hi @joperezr , I'm using official Pi Raspbian Buster distribution downloaded from the Raspberrypi site. The file /dev/gpiomem has root, gpio:
crw-rw---- 1 root gpio 247, 0 Jun 27 15:23 /dev/gpiomem
using sudo same exception. Maybe I need to grant "pi" user the "gpio" group . Edit: pi is in the gpio group already
If it can help, the problem is related to Pi 4. I compiled a blink test (iot/sample), and on Pi4 Buster I get the exception (user pi or root), but with the same Buster on a Pi3, it is working fine. I simply swaped the SD between boards.
private void Initialize()
{
if (_registerViewPointer != null)
{
return;
}
lock (s_initializationLock)
{
if (_registerViewPointer != null)
{
return;
}
int fileDescriptor = Interop.open(GpioMemoryFilePath, FileOpenFlags.O_RDWR | FileOpenFlags.O_SYNC);
if (fileDescriptor < 0)
{
throw new IOException($"Error {Marshal.GetLastWin32Error()} initializing the Gpio driver.");
}
IntPtr mapPointer = Interop.mmap(IntPtr.Zero, Environment.SystemPageSize, (MemoryMappedProtections.PROT_READ | MemoryMappedProtections.PROT_WRITE), MemoryMappedFlags.MAP_SHARED, fileDescriptor, GpioRegisterOffset);
if (mapPointer.ToInt32() < 0)
{
throw new IOException($"Error {Marshal.GetLastWin32Error()} initializing the Gpio driver.");
}
Interop.close(fileDescriptor);
_registerViewPointer = (RegisterView*)mapPointer;
}
}
The Interop.open and/or Interop.mmap is not working on Pi4.
Interesting. Can you try a couple of other scenarios as well:
using (GpioController controller = new GpioController(PinNumberingScheme.Logical, new SysFsDriver()))
{
//..
}
wget https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/libgpiod.sh
chmod +x libgpiod.sh
./libgpiod.sh
And after installing modify your controller so that it is newed up like this:
using (GpioController controller = new GpioController(PinNumberingScheme.Logical, new LibGpiodDriver()))
{
//..
}
Thanks in advance for trying this out 😄
Interesting. Can you try a couple of other scenarios as well:
1. What happens if you force the use of the sysfs driver, does that work?
using (GpioController controller = new GpioController(PinNumberingScheme.Logical, new SysFsDriver())) { //.. }
1. What happens if you install libgpiod library and then force the use of the libgpiod driver. To install libgpiod, run the following commands
wget https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/libgpiod.sh chmod +x libgpiod.sh ./libgpiod.sh
And after installing modify your controller so that it is newed up like this:
using (GpioController controller = new GpioController(PinNumberingScheme.Logical, new LibGpiodDriver())) { //.. }
Thanks in advance for trying this out 😄
I will do, and let youk know the result... but very very strange behaviour.
@joperezr using SysFsDriver() it works but only as "root" using sudo. As a user it does throw an exception:
Unhandled Exception: System.UnauthorizedAccessException: Setting a mode to a pin requires root permissions. ---> System.UnauthorizedAccessException: Access to the path '/sys/class/gpio/gpio27/direction' is denied. ---> System.IO.IOException: Permission denied --- End of inner exception stack trace --- at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirectory, Func`2 errorRewriter)
As a user "pi" I can execute 'echo "out" /sys/class/gpio/gpio27/direction' without any issue. NOTE: the first run as user "pi" it throws execption, but second run it works fine. Third exception again, fourth it run fine. 😄
After compiling libgpiod, and modified blink test it is working fine, no exception.
I am also seeing this issue. I haven't tried the libgpiod solution.
we need to update board detection logic and pick LibgpiodDriver automatically. cc: @buyaa-n I'll try to get us some RPi4s for testing (seems they might be out of stock already so we might need to wait with that unless someone who has it does the changes)
I am not sure that this is an issue with board detection as the stack trace indicates that the RaspberryPi3Driver is being chosen. As @dobova86 has indicated it looks like the issue is around the interrop calls into libc.
@krwq, @joperezr, @dobova86 I have had a think about this issue. The clue I believe is that Marshal.GetLastWin32Error()
is not actually indicating that an error occurred. I believe that what has happened is that the address returned by mmap is in the upper half of the address range and thus converting it to an Int32 and then testing for it being negative causes the exception to be thrown even though the mapped pointer is just fine.
A suggested fix would be as follows :
int fileDescriptor = Interop.open(GpioMemoryFilePath, FileOpenFlags.O_RDWR | FileOpenFlags.O_SYNC);
if (fileDescriptor != -1)
{
throw new IOException($"Error {Marshal.GetLastWin32Error()} initializing the Gpio driver.");
}
IntPtr mapPointer = Interop.mmap(IntPtr.Zero, Environment.SystemPageSize, (MemoryMappedProtections.PROT_READ | MemoryMappedProtections.PROT_WRITE), MemoryMappedFlags.MAP_SHARED, fileDescriptor, GpioRegisterOffset);
if (mapPointer.ToInt32() != -1)
{
throw new IOException($"Error {Marshal.GetLastWin32Error()} initializing the Gpio driver.");
}
I wonder if the larger size RaspberryPi's (mine is 4GB) are bringing out issues that we may have not seen before.
@Frankenslag I'd recommend to send a PR with above with quick summary and example of what didn't work before and works after.
Since we don't have RPi4s yet we will test if it doesn't break RPi3 and if someone else confirms RPi4 issue is fixed we can merge.
Once we get RPi4 we will likely quickly know if fix works
I haven't been able to test this as I don't have a RPi4 yet, but my hunch is that similar to what @Frankenslag suggests, the issue seems to be that the new BCM chip may have a different register distribution in order to interact with the pins. Once we are able to repro, it would be great if we can get our hands on the datasheet for this BCM chip in order to be able to see what is going on here, and if the theory of the shifted registers make sense.
@joperezr, @dobova86, @krwq PR #540 submitted. To confirm the theory I looked at the values being returned from mmap and in my case they were in the 0xB0000000 range so whatever the cause, be it buster or hardware, then this is clearly a value that the code wasn't expecting.
Will do some more confirmation testing but even if this isn't the whole story then the code from this PR follows the expected output of mmap.
@Frankenslag do the default options work with #540 merged or does it still require explicit LibGpiod driver? (i.e. will https://github.com/dotnet/iot/blob/master/samples/led-blink/Program.cs run without any modifications except for pin number?) cc: @RheaAyase
I used the Ssd1351 for testing which just creates a default device (_gpioDevice = new GpioController();
)
Also see resoponse to #557
(i.e. will https://github.com/dotnet/iot/blob/master/samples/led-blink/Program.cs run without any modifications except for pin number?)
Pretty much the code I used. I did not use this exact example but the important bits are the same.
Ok, updating the doc and closing this then
I have a similar issue to @dobova86 on RPi 2, Raspbian Buster, netcore 3.0, Device.Gpio 1.0.0.
Unhandled exception. System.UnauthorizedAccessException: Setting a mode to a pin requires root permissions.
---> System.UnauthorizedAccessException: Access to the path '/sys/class/gpio/gpio16/direction' is denied.
---> System.IO.IOException: Permission denied
--- End of inner exception stack trace ---
at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirectory, Func`2 errorRewriter)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode)
at System.IO.FileStream.OpenHandle(FileMode mode, FileShare share, FileOptions options)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.StreamWriter.ValidateArgsAndOpenPath(String path, Boolean append, Encoding encoding, Int32 bufferSize)
at System.IO.StreamWriter..ctor(String path)
at System.IO.File.WriteAllText(String path, String contents)
at System.Device.Gpio.Drivers.SysFsDriver.SetPinMode(Int32 pinNumber, PinMode mode)
--- End of inner exception stack trace ---
at System.Device.Gpio.Drivers.SysFsDriver.SetPinMode(Int32 pinNumber, PinMode mode)
at System.Device.Gpio.GpioController.SetPinMode(Int32 pinNumber, PinMode mode)
at System.Device.Gpio.GpioController.OpenPin(Int32 pinNumber, PinMode mode)
I have libgpiod built and in both cases:
GpioController(PinNumberingScheme.Logical, new SysFsDriver());
and
GpioController();
the same error.
For me, now it is working ok in 1.0.0, and I don't need to sudo my program. I use :
gpio = new GpioController(PinNumbering.Logical);
and no problem now using gpio.OpenPin(), gpio.Write(). I don't use lipgpiod becouse it needs sudo.
@dobova86 'GpioController(PinNumberingScheme.Logical);' doesn't seem to be helping. With or without libgpiod the same issue.
@pawelpetruch
does it work with sudo ?
If you just use GpioController() without specifying the device. is the exception stack exactly the same ? if not can we see it.
I think that this needs an issue of it's own as the current issue is about a fairly specific problem with where Pi4's have their IO mapped to.
@Frankenslag I can't run 'sudo dotnet ...' if that's what you mean ( sudo: dotnet: command not found).
Without specifying the device:
Unhandled exception. System.UnauthorizedAccessException: Setting a mode to a pin requires root permissions.
---> System.UnauthorizedAccessException: Access to the path '/sys/class/gpio/gpio16/direction' is denied.
---> System.IO.IOException: Permission denied
--- End of inner exception stack trace ---
at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirectory, Func`2 errorRewriter)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode)
at System.IO.FileStream.OpenHandle(FileMode mode, FileShare share, FileOptions options)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.StreamWriter.ValidateArgsAndOpenPath(String path, Boolean append, Encoding encoding, Int32 bufferSize)
at System.IO.StreamWriter..ctor(String path)
at System.IO.File.WriteAllText(String path, String contents)
at System.Device.Gpio.Drivers.SysFsDriver.SetPinMode(Int32 pinNumber, PinMode mode)
--- End of inner exception stack trace ---
at System.Device.Gpio.Drivers.SysFsDriver.SetPinMode(Int32 pinNumber, PinMode mode)
at System.Device.Gpio.Drivers.RaspberryPi3Driver.AddCallbackForPinValueChangedEvent(Int32 pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback)
at System.Device.Gpio.GpioController.RegisterCallbackForPinValueChangedEvent(Int32 pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback)
To get it running I need to firstly create gpio pins using:
sudo sh -c "echo 16 > /sys/class/gpio/export
@pawelpetruch
running something like below seems to solve the issue
sudo dotnet testprog.dll
I have had a look at this on a Pi3B and checked out the following to code snippets
Snippet A:
GpioController c1 = new GpioController(PinNumberingScheme.Logical, new SysFsDriver());
c1.OpenPin(16, PinMode.Input);
c1.RegisterCallbackForPinValueChangedEvent(16, PinEventTypes.Rising | PinEventTypes.Falling, (o, e) => { /* do nothing */ });
Snippet B:
GpioController c1 = new GpioController();
c1.OpenPin(16, PinMode.Input);
c1.RegisterCallbackForPinValueChangedEvent(16, PinEventTypes.Rising | PinEventTypes.Falling, (o, e) => { /* do nothing */ });
In both cases an exception is thrown in SetPinMode
. However if I try for a second time then both these snippets work without issue. (note that you have to reboot between tests so that you start from a known state).
I then tried using a VSDBG to debug and I got no errors at all.
I then changed snippet A to look like below
GpioController c1 = new GpioController(PinNumberingScheme.Logical, new SysFsDriver());
c1.OpenPin(16, PinMode.Input);
System.Threading.Thread.Sleep(1000);
c1.SetPinMode(16, PinMode.Input);
c1.RegisterCallbackForPinValueChangedEvent(16, PinEventTypes.Rising | PinEventTypes.Falling, (o, e) => { /* do nothing */ });
That worked just fine every time. But if I changed snippet B in the same fashion then it made no difference.
My guesses are that there is a delay in SYSFS between opening the pin with an export and the pin appearing with the correct permissions in the userland file system. Then when SetPinMode
is called the exception happens.
Snippet B doesn't work with the delay as it is using the /dev/gpiomem interface for general IO but when using GPIO eventing then falls back to SYSFS and you get the exception. I have found that the following code works but it's a bit horrid. Don't dispose c2 as long as you need the IO though
GpioController c1 = new GpioController();
GpioController c2 = new GpioController(PinNumberingScheme.Logical, new SysFsDriver());
c2.OpenPin(16);
System.Threading.Thread.Sleep(1000);
c2.SetPinMode(16, PinMode.Input);
c1.OpenPin(16);
c1.RegisterCallbackForPinValueChangedEvent(16, PinEventTypes.Rising | PinEventTypes.Falling, (o, e) => { /* do nothing */ });
@krwq @joperezr Have you any comments on this. It looks like we may have to check that the SYSFS gpio pin is really open before trying to manipulate the pin.
@Frankenslag can you open a new issue with a simple repro we can take a look whenever we got time? I currently don't have cycles to look at this at the moment and it will get lost on the closed issue.
I'm experiencing this issue too (System.UnauthorizedAccessException: Setting a mode to a pin requires root permissions.).
Hi All,
Since the last raspbian update on my Raspberry Pi 4, I also got this:
Unhandled exception. System.UnauthorizedAccessException: Setting a mode to a pin requires root permissions.
---> System.UnauthorizedAccessException: Access to the path '/sys/class/gpio/gpio25/direction' is denied.
---> System.IO.IOException: Permission denied
--- End of inner exception stack trace ---
at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirectory, Func`2 errorRewriter)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode)
at System.IO.FileStream.OpenHandle(FileMode mode, FileShare share, FileOptions options)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.StreamWriter.ValidateArgsAndOpenPath(String path, Boolean append, Encoding encoding, Int32 bufferSize)
at System.IO.StreamWriter..ctor(String path)
at System.IO.File.WriteAllText(String path, String contents)
at System.Device.Gpio.Drivers.SysFsDriver.SetPinMode(Int32 pinNumber, PinMode mode)
--- End of inner exception stack trace ---
at System.Device.Gpio.Drivers.SysFsDriver.SetPinMode(Int32 pinNumber, PinMode mode)
at System.Device.Gpio.GpioController.SetPinMode(Int32 pinNumber, PinMode mode)
at System.Device.Gpio.GpioController.OpenPin(Int32 pinNumber, PinMode mode)
at System.Device.Pwm.Drivers.SoftwarePwmChannel..ctor(Int32 pinNumber, Int32 frequency, Double dutyCycle, Boolean usePrecisionTimer, GpioController controller)
at RasPi.MotorController..ctor() in /home/pi/Desktop/RasPi/MotorController.cs:line 26
at RasPi.Program.Main() in /home/pi/Desktop/RasPi/Program.cs:line 11
I also tried to run the build with sudo
:
A fatal error occurred. The required library libhostfxr.so could not be found.
If this is a self-contained application, that library should exist in [/home/pi/Desktop/RasPi/bin/Debug/netcoreapp3.1/].
If this is a framework-dependent application, install the runtime in the global location [/usr/share/dotnet] or use the DOTNET_ROOT environment variable to specify the runtime location or register the runtime location in [/etc/dotnet/install_location].
So I installed dotnet to /usr/share/dotnet
, and now if I try to run the build as root it says:
Unhandled exception. System.IO.IOException: Device or resource busy
at System.IO.FileStream.WriteNative(ReadOnlySpan`1 source)
at System.IO.FileStream.FlushWriteBuffer()
at System.IO.FileStream.FlushInternalBuffer()
at System.IO.FileStream.Flush(Boolean flushToDisk)
at System.IO.FileStream.Flush()
at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
at System.IO.StreamWriter.Dispose(Boolean disposing)
at System.IO.TextWriter.Dispose()
at System.IO.File.WriteAllText(String path, String contents)
at System.Device.Gpio.Drivers.SysFsDriver.OpenPin(Int32 pinNumber)
at System.Device.Gpio.GpioController.OpenPin(Int32 pinNumber)
at System.Device.Gpio.GpioController.OpenPin(Int32 pinNumber, PinMode mode)
at RasPi.MotorController.InitMotors() in /home/pi/Desktop/RasPi/MotorController.cs:line 44
at RasPi.MotorController..ctor() in /home/pi/Desktop/RasPi/MotorController.cs:line 32
at RasPi.Program.Main() in /home/pi/Desktop/RasPi/Program.cs:line 11
Aborted
Btw, I did the OS upgrade, because between two release builds, my adafruit-blinka python library has crashed. Here's the repo related to this project: RasPi
Since the last raspbian update on my Raspberry Pi 4, I also got this
@MilanNemet, Maybe you should use the latest preview versions for System.Device.Gpio. See https://github.com/dotnet/iot#how-to-install You're using the latest release which for sure have issues with RPI4.
Also so far, you may need to force the usage of the RPI3 driver when creating the Gpiocontroller.
Most likely is supported, but needs to be verified and added to list.
https://www.raspberrypi.org/blog/raspberry-pi-4-on-sale-now-from-35/
EDIT (@krwq) Seems Raspberry Pi 4 is supported but we need to update board detection logic and pick LibgpiodDriver automatically