To work with SPI in ODROID XU4

Moderators: odroid, mdrjr

To work with SPI in ODROID XU4

Unread postby gopakumarkm » Thu Oct 11, 2018 4:07 pm

Hi.
I developed a GUI using python code in the ODROID module for controlling a hardware device.
So my next task is, while clicking a button in the GUI i need to send/ receive a 8bit data using SPI protocol.
So please help me for creating a python code for performing SPI communication in ODROID XU4 module.
gopakumarkm
 
Posts: 14
Joined: Wed Sep 05, 2018 7:24 pm
languages_spoken: english
ODROIDs: ODROID XU4, ODROID VU8, ODROID VU7

Re: To work with SPI in ODROID XU4

Unread postby odroid » Thu Oct 11, 2018 4:13 pm

We have used the SPI with only pure C code. I don't know whether the wiringpi-python wrapper can support the SPI driver or not.
https://wiki.odroid.com/odroid-xu4/appl ... e/gpio/spi
https://wiki.odroid.com/odroid-xu4/appl ... o/wiringpi

I hope other people can answer for the question.
User avatar
odroid
Site Admin
 
Posts: 29098
Joined: Fri Feb 22, 2013 11:14 pm
languages_spoken: English
ODROIDs: ODROID

Re: To work with SPI in ODROID XU4

Unread postby gopakumarkm » Fri Nov 23, 2018 1:31 pm

Any people have an idea to do the SPI communication on ODROID XU4?
gopakumarkm
 
Posts: 14
Joined: Wed Sep 05, 2018 7:24 pm
languages_spoken: english
ODROIDs: ODROID XU4, ODROID VU8, ODROID VU7

Re: To work with SPI in ODROID XU4

Unread postby joshua.yang » Tue Nov 27, 2018 5:36 pm

Hi @gopakumarkm,

Sorry for late reply,

We've tested with our WiringPi and WiringPi Python Wrapper on XU4 + Dot Matrix (https://wiki.odroid.com/accessory/displ ... rix_shield)
Dot Matrix may not be what you will use, but this instructions and sample code would help you. :)

This guides you getting used WiringPi Python Wrapper properly, from the scratch.
1. Install required packages and clone WiringPi Python Wrapper.
Refer to https://wiki.odroid.com/odroid-xu4/appl ... on_wrapper,
Code: Select all
$ sudo apt install git python-dev python-setuptools python3-dev python3-setuptools swig
$ git clone --recursive https://github.com/hardkernel/WiringPi2-Python
$ cd WiringPi2-Python


2. Comment out RPi SPI function.
Very important step. You have to comment SPI function RPi uses out before installing WiringPi Python Wrapper.
Target file names "WiringPi/wiringPi/wiringPiSPI.c". Open this file with your favorite editor.
Code: Select all
$ vi WiringPi/wiringPi/wiringPiSPI.c


Then find out a condition for checks defining "BOARD_ODROID".
In this point, you have to comment out this condition itself and leaves only the function for ODROID boards.
This is the results. Check /* and */.
Code: Select all
/*
#if defined(BOARD_ODROID)
*/

#include "wiringOdroid.h"

int wiringPiSPISetupMode (int channel, int speed, int mode)
{
   int fd ;
   int model, rev, mem, maker, overVolted ;
   const char *device ;

   piBoardId (&model, &rev, &mem, &maker, &overVolted) ;

   mode    &= 3 ;   // Mode is 0, 1, 2 or 3
   channel &= 1 ;   // Channel is 0 or 1

   if (channel || model == MODEL_ODROID_C2) {
      return wiringPiFailure (WPI_ALMOST,
         "Can't support spi device. check model or spi channel.\n");
   }

   switch(model)   {
   case MODEL_ODROID_C1:
      device = "/dev/spidev0.0";
   break;
   case MODEL_ODROID_XU3:
   case MODEL_ODROID_N1:
      device = "/dev/spidev1.0";
   break;
   }

   if ((fd = open (device, O_RDWR)) < 0)
      return wiringPiFailure (WPI_ALMOST,
         "Unable to open SPI device: %s\n", strerror (errno));

   spiSpeeds [channel] = speed ;
   spiFds    [channel] = fd ;

   // Set SPI parameters.
   if (ioctl (fd, SPI_IOC_WR_MODE, &mode) < 0)
      return wiringPiFailure (WPI_ALMOST,
         "SPI Mode Change failure: %s\n", strerror (errno)) ;

   if (ioctl (fd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0)
      return wiringPiFailure (WPI_ALMOST,
         "SPI BPW Change failure: %s\n", strerror (errno)) ;

   if (ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0)
      return wiringPiFailure (WPI_ALMOST,
         "SPI Speed Change failure: %s\n", strerror (errno)) ;
   return fd ;
}

/*
#else

int wiringPiSPISetupMode (int channel, int speed, int mode)
{
  int fd ;

  mode    &= 3 ;   // Mode is 0, 1, 2 or 3
  channel &= 1 ;   // Channel is 0 or 1

  if ((fd = open (channel == 0 ? spiDev0 : spiDev1, O_RDWR)) < 0)
    return wiringPiFailure (WPI_ALMOST, "Unable to open SPI device: %s\n", strerror (errno)) ;

  spiSpeeds [channel] = speed ;
  spiFds    [channel] = fd ;

// Set SPI parameters.

  if (ioctl (fd, SPI_IOC_WR_MODE, &mode)            < 0)
    return wiringPiFailure (WPI_ALMOST, "SPI Mode Change failure: %s\n", strerror (errno)) ;
 
  if (ioctl (fd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0)
    return wiringPiFailure (WPI_ALMOST, "SPI BPW Change failure: %s\n", strerror (errno)) ;

  if (ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed)   < 0)
    return wiringPiFailure (WPI_ALMOST, "SPI Speed Change failure: %s\n", strerror (errno)) ;

  return fd ;
}

#endif   // #defined(BOARD_ODROID)
*/


3. Install WiringPi Python Wrapper.
Install it for Python3 which is recommended.
Code: Select all
$ python3 setup.py install


4. Use it for controlling SPI device referring to the example.
WiringPi has 4 basic functions for controlling SPI functionalities.
- wiringPiSPISetup
- wiringPiSPISetupMode
- wiringPiSPIDataRW
- wiringPiSPIGetFd
Python Wrapper supports them too.

In this example, it only uses Setup and DataRW functions.

- wiringPiSPISetup
This needs two parameters: a channel, speed.
Channel for ODROID boards always to be 0.
And in speed, it depends on the board you use.
So, to setup SPI functionality, it could be "wiringPiSPISetup(0, 500000)"
Then SPI initialized with SPI mode 0 by default.

- wiringPiSPIDataRW
This needs two parameters: a file descriptor for SPI device, a byte data.
A file descriptor comes with as the return value of setup function.
And your data have to be passed as a bytes object using "bytes([your data here])" function.

See this codes for better understanding.
Code: Select all
#!/usr/bin/env python3
 
import wiringpi as wpi
import time

CHANNEL         = 0
SPEED           = 500000
CHAR_MAX_ROW    = 36
CHAR_MAX_COLUMN = 8

disp = [
    [0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x3C],# 0
    [0x10,0x30,0x50,0x10,0x10,0x10,0x10,0x7C],# 1
    [0x3E,0x02,0x02,0x3E,0x20,0x20,0x3E,0x00],# 2
    [0x00,0x7C,0x04,0x04,0x7C,0x04,0x04,0x7C],# 3
    [0x08,0x18,0x28,0x48,0xFE,0x08,0x08,0x08],# 4
    [0x3C,0x20,0x20,0x3C,0x04,0x04,0x3C,0x00],# 5
    [0x3C,0x20,0x20,0x3C,0x24,0x24,0x3C,0x00],# 6
    [0x3E,0x22,0x04,0x08,0x08,0x08,0x08,0x08],# 7
    [0x00,0x3E,0x22,0x22,0x3E,0x22,0x22,0x3E],# 8
    [0x3E,0x22,0x22,0x3E,0x02,0x02,0x02,0x3E],# 9
    [0x08,0x14,0x22,0x3E,0x22,0x22,0x22,0x22],# A
    [0x3C,0x22,0x22,0x3E,0x22,0x22,0x3C,0x00],# B
    [0x3C,0x40,0x40,0x40,0x40,0x40,0x3C,0x00],# C
    [0x7C,0x42,0x42,0x42,0x42,0x42,0x7C,0x00],# D
    [0x7C,0x40,0x40,0x7C,0x40,0x40,0x40,0x7C],# E
    [0x7C,0x40,0x40,0x7C,0x40,0x40,0x40,0x40],# F
    [0x3C,0x40,0x40,0x40,0x40,0x44,0x44,0x3C],# G
    [0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x44],# H
    [0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x7C],# I
    [0x3C,0x08,0x08,0x08,0x08,0x08,0x48,0x30],# J
    [0x00,0x24,0x28,0x30,0x20,0x30,0x28,0x24],# K
    [0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7C],# L
    [0x81,0xC3,0xA5,0x99,0x81,0x81,0x81,0x81],# M
    [0x00,0x42,0x62,0x52,0x4A,0x46,0x42,0x00],# N
    [0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x3C],# O
    [0x3C,0x22,0x22,0x22,0x3C,0x20,0x20,0x20],# P
    [0x1C,0x22,0x22,0x22,0x22,0x26,0x22,0x1D],# Q
    [0x3C,0x22,0x22,0x22,0x3C,0x24,0x22,0x21],# R
    [0x00,0x1E,0x20,0x20,0x3E,0x02,0x02,0x3C],# S
    [0x00,0x3E,0x08,0x08,0x08,0x08,0x08,0x08],# T
    [0x42,0x42,0x42,0x42,0x42,0x42,0x22,0x1C],# U
    [0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x18],# V
    [0x00,0x49,0x49,0x49,0x49,0x2A,0x1C,0x00],# W
    [0x00,0x41,0x22,0x14,0x08,0x14,0x22,0x41],# X
    [0x41,0x22,0x14,0x08,0x08,0x08,0x08,0x08],# Y
    [0x00,0x7F,0x02,0x04,0x08,0x10,0x20,0x7F],# Z
]

def transfer(addr1, data1, addr2, data2):
    buffer = [ addr1, data1, addr2, data2 ]
    wpi.wiringPiSPIDataRW(CHANNEL, bytes(buffer))
 
if __name__ == '__main__':
    # Initialize SPI device
    fd = wpi.wiringPiSPISetup(CHANNEL, SPEED)

    # Initialize Dot Matrix
    transfer(0x09,0x00,0x09,0x00)
    transfer(0x0a,0x03,0x0a,0x03)
    transfer(0x0b,0x07,0x0b,0x07)
    transfer(0x0c,0x01,0x0c,0x01)
    transfer(0x0f,0x00,0x0f,0x00)
   
    # Display characters
    while True:
        for j in range(0, CHAR_MAX_ROW - 1):
            for i in range(1, CHAR_MAX_COLUMN + 1):
                transfer(i, disp[j + 1][i - 1], i, disp[j][i - 1])
            time.sleep(1)


Additionally, this is an instruction for SPI, from official WiringPi Python Wrapper README.md.
Code: Select all
**SPI:**

The `wiringPiSPIDataRW()` function needs to be passed a `bytes` object in Python 3.  In Python 2, it takes a string.  The following should work in either Python 2 or 3:
```python
wiringpi.wiringPiSPISetup(channel, speed)
buf = bytes([your data here])
retlen, retdata = wiringpi.wiringPiSPIDataRW(0, buf)
```
Now, `retlen` will contain the number of bytes received/read by the call.  `retdata` will contain the data itself, and in Python 3, `buf` will have been modified to contain it as well (that won't happen in Python 2, because then `buf` is a string, and strings are immutable).



Unfortunately, it cannot be used without something "update by yourself" due to the "macro" problem.
The necessary macro named "BOARD_ODROID" defines in Makefile, and it affects when WiringPi builds but doesn't when building Python Wrapper. So if you use these SPI functions without "the update", it always returns that "SPI device not found".
We will update our WiringPi source code very soon.

Thanks.
joshua.yang
 
Posts: 107
Joined: Fri Sep 22, 2017 5:54 pm
languages_spoken: English
ODROIDs: XU4, XU4Q + Cloudshell2

Re: To work with SPI in ODROID XU4

Unread postby gopakumarkm » Wed Nov 28, 2018 2:48 pm

Hai Joshua
Thanks for your great reply...
I will definitely work with it and update you .....
gopakumarkm
 
Posts: 14
Joined: Wed Sep 05, 2018 7:24 pm
languages_spoken: english
ODROIDs: ODROID XU4, ODROID VU8, ODROID VU7

Re: To work with SPI in ODROID XU4

Unread postby gopakumarkm » Wed Nov 28, 2018 3:29 pm

But When i run just a simple python code for SPI, in the terminal it shows an error like this:
Unable to open SPI device: No such file or directory
gopakumarkm
 
Posts: 14
Joined: Wed Sep 05, 2018 7:24 pm
languages_spoken: english
ODROIDs: ODROID XU4, ODROID VU8, ODROID VU7

Re: To work with SPI in ODROID XU4

Unread postby gopakumarkm » Wed Nov 28, 2018 3:55 pm

Thank Joshua
Now it works
gopakumarkm
 
Posts: 14
Joined: Wed Sep 05, 2018 7:24 pm
languages_spoken: english
ODROIDs: ODROID XU4, ODROID VU8, ODROID VU7

Re: To work with SPI in ODROID XU4

Unread postby joshua.yang » Thu Nov 29, 2018 4:24 pm

Now you can do without "the update". :)

Just do,
Code: Select all
$ sudo apt install git python-dev python-setuptools python3-dev python3-setuptools swig
$ git clone --recursive https://github.com/hardkernel/WiringPi2-Python
$ cd WiringPi2-Python
$ python3 setup.py install

Then you can use SPI functions with Python3.
joshua.yang
 
Posts: 107
Joined: Fri Sep 22, 2017 5:54 pm
languages_spoken: English
ODROIDs: XU4, XU4Q + Cloudshell2


Return to General Chat

Who is online

Users browsing this forum: No registered users and 4 guests