NanoPI M1/Neo - GPIO - Permission issues


lordofduct
 Share

0

Recommended Posts

So I have a nanopi m1 and a neo. I'm running Ubuntu Xenial on them:


 

I'm attempting to access the gpio, when I attempt to echo to /sys/class/gpio/export I get permission denied (sudo or not, even if logged in as root).

 

I've also found this library for python to handle gpio on the nanopi:


 

But when I use it, it says:

 

as root

 


root@nanopineo:/home/admin# python test.py
Traceback (most recent call last):
  File "test.py", line 7, in <module>
    gpio.gpio_init(16, 1)
  File "build/bdist.linux-armv7l/egg/fgpio/fgpio.py", line 85, in gpio_init
  File "build/bdist.linux-armv7l/egg/fgpio/fgpio.py", line 465, in _mem_open
mmap.error: [Errno 1] Operation not permitted

 

as user

 


admin@nanopineo:~$ sudo python test.py
Traceback (most recent call last):
  File "test.py", line 7, in <module>
    gpio.gpio_init(16, 1)
  File "build/bdist.linux-armv7l/egg/fgpio/fgpio.py", line 85, in gpio_init
  File "build/bdist.linux-armv7l/egg/fgpio/fgpio.py", line 465, in _mem_open
mmap.error: [Errno 1] Operation not permitted
admin@nanopineo:~$ python test.py
Traceback (most recent call last):
  File "test.py", line 7, in <module>
    gpio.gpio_init(16, 1)
  File "build/bdist.linux-armv7l/egg/fgpio/fgpio.py", line 85, in gpio_init
  File "build/bdist.linux-armv7l/egg/fgpio/fgpio.py", line 461, in _mem_open
OSError: [Errno 13] Permission denied: '/dev/mem'

 

Permission denied is what I expect as user.

 

But not sure what Operation not permitted is for when root/sudo.

 

...

 

I'm just wondering what is the easiest way to actually access the gpio on this thing. My googling is for not so far.

Link to post
Share on other sites

Armbian is a community driven open source project. Do you like to contribute your code?

Well I haven't resolved my issue of not being able to access /dev/mem.

 

But I got around it by using /sys/class/gpio.

 

I wrote up my own code to drive the gpio through this interface using C# (my preferred language):

 




    public class FileGpioDriver : IGpioDriver
    {
 
        public const string GPIO_ROOT = "/sys/class/gpio/";
        public const string GPIO_EXPORT = "/sys/class/gpio/export";
        public const string GPIO_UNEXPORT = "/sys/class/gpio/unexport";
 
        #region Fields
 
        private static readonly Dictionary<int, FileHandle> _handles = new Dictionary<int, FileHandle>();
 
        #endregion
 
        #region CONSTRUCTOR
 
        #endregion
 
        #region Methods
 
        public void Allocate(int pin, PinDirection mode)
        {
            this.Release(pin);
 
            using (var writer = new StreamWriter(GPIO_EXPORT, false))
            {
                writer.Write(pin);
            }
 
            var handle = new FileHandle()
            {
                Path = GuessGpioPath(pin),
                Mode = mode
            };
 
            var dirPath = Path.Combine(handle.Path, "direction");
            try
            {
                using (var writer = new StreamWriter(dirPath, false))
                    writer.Write(mode == PinDirection.Input ? "in" : "out");
            }
            catch(UnauthorizedAccessException ex)
            {
                // program hasn't been started as root, give it a second to correct file permissions
                System.Threading.Thread.Sleep(1000);
                using (var writer = new StreamWriter(dirPath, false))
                    writer.Write(mode == PinDirection.Input ? "in" : "out");
            }
 
            handle.Stream = new FileStream(Path.Combine(handle.Path, "value"), FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
            _handles[pin] = handle;
        }
 
        public void Release(int pin)
        {
            FileHandle handle;
            string path;
            if(_handles.TryGetValue(pin, out handle))
            {
                path = handle.Path;
                if (handle.Stream != null) handle.Stream.Close();
                _handles.Remove(pin);
            }
            else
            {
                path = GuessGpioPath(pin);
            }
 
            if(Directory.Exists(path))
            {
                using (var writer = new StreamWriter(GPIO_UNEXPORT, false))
                {
                    writer.Write(pin);
                }
            }
        }
 
        public void Write(int pin, bool value)
        {
            FileHandle handle;
            if(_handles.TryGetValue(pin, out handle))
            {
                if (handle.Mode != PinDirection.Output) throw new InvalidOperationException("Can only write to output pins.");
                handle.Stream.Seek(0, SeekOrigin.Begin);
                handle.Stream.WriteByte(value ? (byte)'1' : (byte)'0');
                handle.Stream.Flush();
            }
        }
 
        public bool Read(int pin)
        {
            FileHandle handle;
            if(_handles.TryGetValue(pin, out handle))
            {
                handle.Stream.Seek(0, SeekOrigin.Begin);
                var c = (char)handle.Stream.ReadByte();
                handle.Stream.Flush();
                return c == '1';
            }
 
            return false;
        }
 
        #endregion
        
        #region Static Utils
        
        private static string GuessGpioPath(int pin)
        {
            string gpioId = string.Format("gpio{0}", pin);
            string path = Path.Combine(GPIO_ROOT, gpioId);
 
            if(!Directory.Exists(path))
            {
                foreach(var d in Directory.GetDirectories(GPIO_ROOT))
                {
                    if(d.StartsWith("_"))
                    {
                        return d;
                    }
                }
            }
 
            return path;
        }
 
        #endregion
 
        #region Special Types
 
        private struct FileHandle
        {
            public string Path;
            public PinDirection Mode;
            public Stream Stream;
        }
 
        #endregion
 
    }



 

This has got me up and running turning gpio pins on or off.

 

Next I want to get pwm working, I've read around that there is a /sys/class/pwm, but this doesn't exist on my machine. I also noticed its through this that the python library from my previous post attempts to access it as well.

 

I looked in the fex and noticed some entries relating to pwm:

 



[pwm0_para]
pwm_used = 0
pwm_positive = port:PA05<3><0><default><default>
 
[pwm1_para]
pwm_used = 0
pwm_positive = port:PA06<3><0><default><default>


 

I've changed the pwm_used flag to 1, but nothing changes.

 

I've also attempted creating a software pwm based on a blog post I found... but it was far to inaccurate to use.

 

Is there any c api I could use to access the pwm, or something I'm issing to get /sys/class/pwm?

 

...

 

also, I notice when I submit posts, the last few lines of my post get removed... what's up with that? I've had to edit this multiple times because it kept deleting it.

Link to post
Share on other sites

I don't use python but do C and C#.

Suggest you take a look at the matrix example for GPIO.

See if you can get that running first.

The makefiles work out of the box for GPIO.

The demo uses the shared library.

The part of the shared library that does all the work is

https://github.com/friendlyarm/matrix/blob/master/lib/gpio.c

 

The demo is https://github.com/friendlyarm/matrix/blob/master/demo/matrix-gpio_out/Matrix-gpio_out.c

download from git on you neo and follow the instructions here.

http://wiki.friendlyarm.com/wiki/index.php/Matrix_-_LED

 

If that runs try using C# to follow the same steps.

I haven't tried that particular pin I have only tried pin6.

pwm seems broken or at least I can't get it working.

I also have to be root.

Good Luck

Allan

Link to post
Share on other sites

pwm I could not get working on either armbian or lichee

https://forum.armbian.com/index.php/topic/2344-pwm-on-allwinner-h3/

 

one option would be to bypass the pwm driver and use mmap to map the registers into address space and write to the registers directly using the data sheet.

The datasheet shows the PWM module is pretty basic.

either a square wave or period/duty cycle with some scaling options and active high /low

Link to post
Share on other sites

So yeah, I got the fex to enable pwm1 on pin 6 (not sure where on the board pwm0 is, but it's not on the gpio header).

 

Still didn't work though, in the code when 'ioctl' is called to actually set the frequency, it fails.

 

Anyways... off to other things.

 

...

 

I was able to get something in /sys/class for pwm. By adding the module 'pwm-sunxi', while having pwm configured in the fex:



modprobe pwm-sunxi


I am able to find a grouping /sys/class/sunxi_pwm, but unfortunately the structure of this doesn't match anything like what I expect... heck, the name alone isn't what I expected.

 

I expect something like this from what I've read on the internet:



- /sys/class/pwm-sunxi
|
+----pwmX
|
+---duty
+---duty_percent
+---period
+---polarity
+---pulse
+---pin
+---run


 

but instead get something like:

 



- /sys/class/sunxi_pwm
|
+----sunxi_pwm
|
+----dev
+----uevent
+----subsystem //symlink to /sys/class/sunxi_pwm
+----power
|
+----
... a bunch of junk

Link to post
Share on other sites

I think were basically at the same place now.

pwm is also a linux known thing with a controller managing access to numerous pwm devices.

This allows board developers to dynamically add pwm channels possibly as peripheral chips controled by i2c or otherwise.

I'm not convinced pwm driver is working on FA matrix.

I note that there wiki doesn't include it but it is in their examples.

Puzzling that it behaves differently on Armbian and Lichee tho.

even more puzzling is that on Lichee from a code perspective it looks to be working.

 

I think maybe my next attempt would be to mmap the registers and see if I can get it  to output the square wave just to convince myself the hardware can do this on lichee.

TBH. There is only one PWM  available and this is an embedded board so I am unlikely to ever share the pwm with anything else so not a terrible solution for custom applications

 

Device Driver development is high on my list and PWM is very basic on this chip so it might be a candidate for a first driver.

Christmas is coming so maybe over the break.

 

If anyone out there has pwm working on an H3 (not bit banged) using the pwm driver I would love to hear about it.

Link to post
Share on other sites

Guest
This topic is now closed to further replies.
 Share

0