rm-hull / luma.oled

Python module to drive a SSD1306 / SSD1309 / SSD1322 / SSD1325 / SSD1327 / SSD1331 / SSD1351 / SH1106 OLED
https://luma-oled.readthedocs.io
MIT License
805 stars 161 forks source link

GPIO errors wen using lib on a Jetson TX2 ARMv8 (ubuntu 16.04, SPI mode) - SUCCESS !!! #182

Closed elpimous closed 6 years ago

elpimous commented 6 years ago

Type of board = Jetson TX2 (aarch64, ARMv8) ubuntu 16.04 objective : control ssd1351 128x128 RGB oled

Hello all, I'm a real newbie in spi/gpio protocole, but I'd like to make your lib work on my board. the oled is wired correctly on my board : (spidev3.0)

tried this :

from luma.core.interface.serial import spi
from luma.oled.device import ssd1351
serial = spi(device=0, port=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/luma/core/interface/serial.py", line 253, in __init__
    bitbang.__init__(self, gpio, transfer_size, DC=gpio_DC, RST=gpio_RST)
  File "/usr/local/lib/python2.7/dist-packages/luma/core/interface/serial.py", line 148, in __init__
    self._gpio = gpio or self.__rpi_gpio__()
  File "/usr/local/lib/python2.7/dist-packages/luma/core/lib.py", line 30, in __rpi_gpio__
    'GPIO access not available')
luma.core.error.UnsupportedPlatform: GPIO access not available

Sure it's not a raspberry pi3, but perhaps there are just a few things to do to make it work ?! My project is a mobile social robot (https://plus.google.com/+vincentfoucault12) Using your libs, to animate it eyes. Please help ! Thanks a lot, Vincent

thijstriemstra commented 6 years ago

@elpimous looks like you do not have the RPi.GPIO library installed. Can you verify this? E.g.:

pip install RPi.GPIO
elpimous commented 6 years ago

hello thijstriemstra, already installed. tried this :

nvidia@tegra-ubuntu:~/Downloads/luma.oled-master$ python /home/nvidia/Downloads/luma.examples-master/examples/3d_box.py -d ssd1351 --width 128 --height 128 -i spi --spi-port 0 --spi-device 3 --gpio RPi.GPIO --gpio-data-command 31 --gpio-reset 29
Traceback (most recent call last):
  File "/home/nvidia/Downloads/luma.examples-master/examples/3d_box.py", line 129, in <module>
    device = get_device()
  File "/home/nvidia/Downloads/luma.examples-master/examples/demo_opts.py", line 51, in get_device
    device = cmdline.create_device(args)
  File "/usr/local/lib/python2.7/dist-packages/luma/core/cmdline.py", line 132, in create_device
    device = Device(Serial(), **vars(args))
  File "/usr/local/lib/python2.7/dist-packages/luma/core/cmdline.py", line 103, in spi
    GPIO = importlib.import_module(self.opts.gpio)
  File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module
    __import__(name)
  File "/usr/local/lib/python2.7/dist-packages/RPi/GPIO/__init__.py", line 23, in <module>
    from RPi._GPIO import *
RuntimeError: This module can only be run on a Raspberry Pi!

and this :

nvidia@tegra-ubuntu:~/Downloads/luma.oled-master$ python /home/nvidia/Downloads/luma.examples-master/examples/3d_box.py -d ssd1351 --width 128 --height 128 -i spi --spi-port 0 --spi-device 3 --gpio-data-command 31 --gpio-reset 29
usage: 3d_box.py [-h] [--config CONFIG] [--display] [--width WIDTH]
                 [--height HEIGHT] [--rotate] [--interface]
                 [--i2c-port I2C_PORT] [--i2c-address I2C_ADDRESS]
                 [--spi-port SPI_PORT] [--spi-device SPI_DEVICE]
                 [--spi-bus-speed SPI_BUS_SPEED] [--gpio GPIO]
                 [--gpio-data-command GPIO_DATA_COMMAND]
                 [--gpio-reset GPIO_RESET] [--gpio-backlight GPIO_BACKLIGHT]
                 [--block-orientation] [--mode] [--framebuffer] [--bgr]
                 [--h-offset H_OFFSET] [--v-offset V_OFFSET]
                 [--backlight-active]
3d_box.py: error: GPIO access not available

Well, don't know !!

thijstriemstra commented 6 years ago

@rm-hull looks like that board does support GPIO but I couldn't find a Python library for it. Here's the header pinout: http://www.jetsonhacks.com/nvidia-jetson-tx2-j21-header-pinout/

And a GPIO library written in Go: https://github.com/jetsonhacks/jetsonTX1GPIO

There's also this I2C library: https://github.com/jetsonhacks/goi2c

Thoughts?

elpimous commented 6 years ago

Hello friends, Yes it't this !! I need to be able to call a GPIO pin by it number, into a python code. And I don't find anything as python lib.

here is what I did :

echo 298 > /sys/class/gpio
echo 398 > /sys/class/gpio
ls  /sys/class/gpio

export gpio298 gpio398 unexport

GOOD !!

How to call this gpio298 in python ?? (gpio298 for oled SPI DC) and (gpio398 for oled reset) Thanks friends.

thijstriemstra commented 6 years ago

Until you find, or somebody writes, a Python library for Jetson TX2 GPIO: I don't think there's much we can do.

rm-hull commented 6 years ago

@elpimous I wrote another library called OPi.GPIO to interface with the Orange PI's GPIO ports. It does the orchestration to interface to /sys. I believe @sgjava has modified it to work on a NanoPi and other folks have made it work on other SBCs too, so there's a good chance that it could be modified for the Jetson too

sgjava commented 6 years ago

@rm-hull, it would be awesome if you dynamically loaded the pin mappings with OPi.GPIO, so I wouldn't need to fork just to change pin mappings. I have an app that dynamically loads modules using:

    def getPlugin(self, moduleName, **kwargs):
        """Dynamically load module"""
        # If package name passed then parse out class name
        moduleSplit = moduleName.split(".")
        if len(moduleSplit) > 1:
            moduleClass = moduleSplit[1]
        else:
            moduleClass = moduleName
        module = importlib.import_module(moduleName)
        moduleClass = getattr(module, moduleClass)
        return moduleClass(**kwargs)

Or if you have some other clever way to override at runtime?

rm-hull commented 6 years ago

@sgjava - perhaps we could just make the setMode(...) accept a GPIO.CUSTOM value and a second arg which is the pin mapping dict you want to use ?

Raise a feature request/issue in that project and we can discuss it further there instead of here?

sgjava commented 6 years ago

Haha, great minds think alike :) That's the road I started down. I'll post more over at RPi.GPIO project.

elpimous commented 6 years ago

Oh. Very good news !! Thanks a lot. I'll try it pretty soon and will report result.

thijstriemstra commented 6 years ago

I'll post more over at RPi.GPIO project.

Interesting to see how that'll go, with RPi.GPIO being hosted on sourceforge and having a single developer..

sgjava commented 6 years ago

@thijstriemstra this will only work with sysfs based GPIO access, so the SBC/kernel must support this. @elpimous take a look at http://www.jetsonhacks.com/nvidia-jetson-tx2-j21-header-pinout to get your mappings. You can see what I did at https://github.com/sgjava/OPi.GPIO/blob/master/OPi/pin_mappings.py

thijstriemstra commented 6 years ago

@sgjava cool, make sure to link any external tickets you open in here.

sgjava commented 6 years ago

I posted over at OPi.GPIO project my suggestion to add Duo mappings. Going forward others can add more SBC mappings.

CRImier commented 6 years ago

Spreaking about GPIOs, I use the gpio library for sysfs access, with great success. If, for somereason, OPi.GPIO integration doesn't work out, you could ensure compatibility with it (or even fork and change the interface a little bit if necessary), and then you'll get out-of-the-box compatibility with whatever GPIOs some board has.

@sgjava Offtopic-ish:

        moduleSplit = moduleName.split(".")
        if len(moduleSplit) > 1:
            moduleClass = moduleSplit[1]

Are you sure you want to use 1 instead of -1? The code won't work for paths longer than 2 elements

sgjava commented 6 years ago

I think we are going to take a different path using setmode. This was from one of my projects using OOP packaging, so it was only 1 level deep :) https://github.com/sgjava/motiondetector. The GPIO lib you mention has no pin mappings.

elpimous commented 6 years ago

Hello all, Trying the gpio lib...

On my board :

I import the lib in python : import OPi.GPIO as GPIO But I don't know how to assign a GPIO ?!

Could you give an example, for OLED DC, or RESET ?

Thanks a lot.

sgjava commented 6 years ago

What board do you have?

elpimous commented 6 years ago

Hi Sgjava. A Nvidia jetson tx2

sgjava commented 6 years ago

@elpimous you need to make your own pin mappings like I did for the Duo. Your pin outs are http://www.jetsonhacks.com/nvidia-jetson-tx2-j21-header-pinout. Then look at https://github.com/rm-hull/OPi.GPIO/tree/master/nanopi. So you need to:

Get it working locally inside the local OPi.GPIO. If you want it to become part of the project submit a PR after everything is working.

elpimous commented 6 years ago

hello sgjava, Thanks for quick answer. Sure, if it works, i'll submit a pr !

well, I searched for BCM (newbie !) I don't think that my J21 header pinout uses this functionality. Creating module : jetsontx2.py

# -*- coding: utf-8 -*-
# Copyright (c) 2018 Richard Hull & Contributors
# See LICENSE.md for details.

"""
Alternative pin mappings for NanoPi DUO board with/without Mini Shield (see
http://wiki.friendlyarm.com/wiki/index.php/NanoPi_Duo#Layout)
Usage:
.. code:: python
   import nanopi.duo
   from OPi import GPIO
   GPIO.setmode(nanopi.duo.BOARD)
"""
BOARD = {
    1: 298,  # DC
    2: 388,  # Reset
}

and, in my program, I call : import nanopi.duo import nanopi.duo.board as gpio_pins from OPi import GPIO

how to use it : GPIO.setmode(gpio_pins) here, ...(gpio=GPIO, gpio_DC=DC, gpio_RST=RESET)

Like it ? ...(gpio=GPIO, gpio_DC=1, gpio_RST=2)

Sorry for he (perhaps too silly) questions !

sgjava commented 6 years ago

It's just another mapping that is supposed to not change vs physical BOARD pin outs on various Pis. luma.examples used to use BCM, but can be overridden to use any mapping now. Take a look at the Pi 3 (40 pins) https://pinout.xyz/# The Pi 1A/B had 26 pins http://wiringpi.com/pins. Depends on what you are going for. It will only be an issue if a library has hard coded BOARD or BCM for the Pi. https://www.rs-online.com/designspark/interfacing-hardware-with-the-raspberry-pi is another good explanation.

Also, I'd map everything, not just the stuff Luma needs since OPi.GPIO is a general purpose library. Don't forget to change the Duo comments to your TX2 stuff :)

elpimous commented 6 years ago

Hello, I have errors with this piece of code :

import spidev
import nanopi.duo
from OPi import GPIO
from luma.core.interface.serial import spi
from luma.oled.device import ssd1351

# Import GPIO module
GPIO.setmode(nanopi.duo.BOARD) # recover gpio mapped key from BOARD dic

#spi
serial = spi(spi=spidev.SpiDev(), port=3, device=0, gpio=GPIO, gpio_DC=1, gpio_RST=2)

/usr/local/lib/python2.7/dist-packages/luma/core/interface/serial.py:164: UserWarning: Channel 1 is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings. self._gpio.setup(pin, self._gpio.OUT) /usr/local/lib/python2.7/dist-packages/luma/core/interface/serial.py:164: UserWarning: Channel 2 is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings. self._gpio.setup(pin, self._gpio.OUT)

About GPIO, I just feeded my own BOARD dic ! BOARD = {1: 298, 2: 388}, where 1 is gpio298...

About SPI, the oled is wired as needed, on the J21 pineouts (JETSON TX2) Pin 19 - SPI(3) MOSI Pin 21 - SPI(3) MISO Pin 23 - SPI(3) CLK Pin 24 - SPI(3) CS#0 The pins seems pre-affected, so I don't have to assign the CS pin (I think ?!)

It seems to cause problems : playing your luma.examples/examples/animated_gif.py, the oled lights on white, with multiple small color points, and I can see refresh rate ! Is it a GPIO error ?? What did I do wrong ?

sgjava commented 6 years ago

First errors are just warnings you can mask with GPIO.setwarnings(False). Your code should look something like (assumes you created top level package nvidia with jetsontx2.py locally as I instructed above):

import time
import nvidia.jetsontx2
from OPi import GPIO
from luma.core.interface.serial import spi
from luma.core.render import canvas
from luma.oled.device import ssd1306

GPIO.setmode(nvidia.jetsontx2.BOARD)
GPIO.setwarnings(False)
serial = spi(port=3, device=0, gpio=GPIO, gpio_DC=1, gpio_RST=2)
device = ssd1306(serial)

with canvas(device) as draw:
    draw.rectangle(device.bounding_box, outline="white")
    draw.text((3, 3), "Hello", fill="white")

time.sleep(10)

Show the contents of jetsontx2.py.

elpimous commented 6 years ago

IT works !!!! Awesome !!!!! And no more latency !! Big thanks from Alfred (my robot !)

sgjava commented 6 years ago

Now just get the eyes working https://www.youtube.com/watch?v=crMSpkif-k4

elpimous commented 6 years ago

Yes, exactly. Thanks again for your time.