SPI over GPIO in OpenWrt

Warning:
This information is obsolete. Please look into Linux Device Tree instead.

The previous posts Controlling leds status in OpenWrt and Controlling GPIOs in OpenWrt were actually an introduction for this.

Introduction

What if you want to connect some kind of SPI device to your OpenWrt device? Perhaps a microcontroller (AVR/Arduino, PIC, etc).
I recently worked on a project where i needed to have a web user interface and control an IR led emitter to emulate a remote. I considered that using an Arduino + Ethernet shield + some kind of flash storage + power supply + container box would cost me more than a TP-LINK MR3020 plus a bunch of components.

It turns out that the Linux kernel already has some modules to bitbang an SPI over the GPIO pins (spi-gpio + spi-bitbang) and also a module to expose the SPI to userland so that it can be accessed by our programs or scripts (spi-dev).
BUT there’s a problem. This stuff is not “directly” usable: it is used by other kernel drivers. We don’t have a way to dynamically say “hey, i want an SPI on those pins”. Instead we would need to rebuild the kernel adding some custom code to declare this SPI bus and also devices connected to it.
I don’t like the idea to recompile the kernel for something like this. I probably want to use this small linux box for tests, POCs, different projects, and i don’t want to rebuild the kernel and flash a new image each time.
So, i made a kernel module that allows to configure on-the-fly an SPI bus and its nodes. You can use it on a stock Attitude Adjustment image, without reflashing or recompiling anything.

By the way, if you wonder how fast this SPI can be, my tests show that it can go something above 1 MHz. Not bad at all.

Installation

I have submitted a patch to the OpenWrt developers. They may add it to the next release (not sure honestly) and be installable with opkg. But in the meantime i have built the module for the various platforms on Attitude Adjustment and you can install it manually.

  1. Click here to download the kernel module.
  2. Copy the file spi-gpio-custom.ko for your platform in /lib/modules/<kernel version>/  (TP-Link is ar71xx – for other boards it’s the same of the image you have downloaded)
  3. Run opkg install kmod-spi-gpio
  4. Run opkg install kmod-spi-dev

UPDATE
the patch has been included in OpenWrt trunk, so it is now available in nightly builds and will be in future releases starting from Barrier Breaker.
The installation is straightforward:
#opkg install kmod-spi-gpio-custom

Usage

You can use the module to configure up to 4 buses with up to 8 devices each, according to the parameters that you use when loading the module.

The command you’ll use is:
#insmod spi-gpio-custom <parameters>

Here is the official doc from the source:

 *  The following parameters are adjustable:
 *
 *    bus0    These four arguments can be arrays of
 *    bus1    unsigned integers as follows:
 *    bus2
 *    bus3    <id>,<sck>,<mosi>,<miso>,<mode1>,<maxfreq1>,<cs1>,...   
 *
 *  where:
 *
 *  <id>       ID to used as device_id for the corresponding bus (required)
 *  <sck>      GPIO pin ID to be used for bus SCK (required)
 *  <mosi>     GPIO pin ID to be used for bus MOSI (required*)
 *  <miso>     GPIO pin ID to be used for bus MISO (required*)
 *  <modeX>    Mode configuration for slave X in the bus (required)
 *             (see /include/linux/spi/spi.h) 
 *  <maxfreqX> Maximum clock frequency in Hz for slave X in the bus (required)
 *  <csX>      GPIO pin ID to be used for slave X CS (required**)
 *
 *    Notes:
 *    *        If a signal is not used (for example there is no MISO) you need
 *             to set the GPIO pin ID for that signal to an invalid value.
 *    **       If you only have 1 slave in the bus with no CS, you can omit the
 *             <cs1> param or set it to an invalid GPIO id to disable it. When
 *             you have 2 or more slaves, they must all have a valid CS.

Your platform will have GPIOs numbered in a certain range, for example 0-50 or 400-900 (see the OpenWrt Wiki for your router). Anything outside that range is an “invalid value” per the notes above.

For each device a file on /dev will created, named spidev<bus id>.<dev id>. For example, /dev/spidev1.0

Admittedly, it’s not easy to remember. But reading that reference when you want to change something is still less annoying than rebuilding and reflashing everything, right?

Examples

We all know, examples make everything so much easier to understand. (examples are for a TP-Link MR3020)

Single bus with id 1, using gpio 7 as CLK, 29 as MOSI, no MISO and single device in spi mode 0, max 1Khz, with no CS:
#insmod spi-gpio-custom bus0=1,7,29,100,0,1000
This will result in:
/dev/spidev1.0

Single bus with id 1, using gpio 7 as CLK, 29 as MOSI, 26 as MISO, first device in spi mode 0, max 1Khz, with gpio 0 as CS, second device in spi mode 2, max 125Khz, with gpio 17 as CS:
#insmod spi-gpio-custom bus0=1,7,29,26,0,1000,0,2,125000,17
This will result in:
/dev/spidev1.0 and /dev/spidev1.1

Bus with id 1, using gpio 7 as CLK, 29 as MOSI, no MISO, with single device in spi mode 0, max 1Khz, with no CS and Bus with id 2 using gpio 26 as CLK, 17 as MOSI, no MISO with single device in spi mode 2, max 125Khz, with no CS:
#insmod spi-gpio-custom bus0=1,7,29,100,0,1000 bus1=2,26,17,100,2,125000
This will result in:
/dev/spidev1.0 and /dev/spidev2.0

Transferring data

Ok, now how do we transfer data?

Simplex communication is done by just writing and reading that /dev file.
For example,
#echo hello > /dev/spidev1.0
will send “hello\n”, where \n (LF) is added by echo.

For full duplex data transfer you need to use ioctl calls. See the spi-dev documentation. You can also see an example here.

Troubleshooting

If something fails, insmod will give you a description of the fault code, which is very generic and will usually tell you nothing about what happened.
To understand what’s wrong, see the kernel log running dmesg.

If you want to change your configuration, you need to unload the module and reload it with different parameters:
#rmmod spi-gpio-custom
#insmod spi-gpio-custom <new parameters>

Last, but not least, remember to unload other modules that may keep the gpio busy, for example leds_gpio:
#rmmod leds_gpio

Reference

<linux source>/Documentation/gpio.txt
<linux source>/Documentation/spi/spi-summary
<linux source>/Documentation/spi/spidev

82 thoughts on “SPI over GPIO in OpenWrt

  1. Pingback: Getting SPI on a router

    • You can use any GPIO, i personally used pins 7 and 29 for just CLK and MOSI (same pins used for i2c on the wiki) as they were free. You can use other pins, like those connected to the LEDs if you don’t need them, or those connected to the switch (but in this case you need to remove it).

  2. Pingback: » Possible Kernel Module for SPI on OpenWRT Fuzzy Hypothesis Online

  3. Do you think this could work with a TL-703N to control a WS2801 LED strip ? I’m wondering if preemption would prohibit such an endeavor. Bandwith required for my application is around 500 kbits/s, would that leave enough CPU to do other things ?

    • If you want to continuously stream data at that rate i’d say it’s not going to work.
      If the strip it’s not very long and you can stream data only for a part of the time (send a “frame”, wait, then send the next) while keeping a decent refresh rate you could leave enough cpu time to do other things.
      I think that the main problem is probably to get a smooth sequence of frames as OpenWrt is not compiled to be a realtime OS.

      If you’re adventurous and feel comfortable with recompiling the kernel yourself, you could give try the following:
      – enable PREEMT_RT in kernel config and run the process which will drive the spi in high priority
      – build a custom gpio driver with statically assigned GPIOs. This will be more efficient than spi-gpio which uses dynamically assigned GPIOs. It should also be easy to do, see notes above #ifndef DRIVER_NAME in spi-gpio.c

      I have a 10×10 array of these leds controlled with an AVR, i didn’t consider this option so far. I’ll probably do some math to see if it’s feasible or not.

      • Thanks for the reply and the cues. Recompiling the kernel would be fun but I would move away from my original purpose… I am comtemplating using the Raspberry Pi then since I believe it has a free hardware SPI port to work with although it lacks WiFi out of the box. However, it seems it is pretty easy to add. I want to build a 32×10 frame hooked up to WiFi and have my PC drive it once in a while with live content through UDP at >30 fps. When the PC is not driving it, it would revert to playing previously recorded frames on an external memory stick/card. So it will be pretty intense bandwidth and CPU wise.

  4. This is great, I really appreciate the post and the driver.

    I’m having some trouble getting it working with Attitude Adjustment. After an error-free insmod, I see the new spi entries in /sys/class/spidev, but nothing appears in /dev. Is this expected? No errors, apart from this in dmesg:

    [ 2762.960000] Custom GPIO-based SPI driver version 0.1
    [ 2762.970000] spi_gpio spi_gpio.3: master is unqueued, this is deprecated

    Any thoughts? Thanks!

  5. You are the best! I’m with ODROID-U3 and it don’t have the SPI GPIO lines, I believe I can now 😀 Great job, best regards.

  6. Hi! I know that this was designed to work with attitude adjustment, but is it possible for it to be even slightly functional with Backfire? I have a linksys wrt54g and I am nervous to try and flash Attitude adjustment to it, as I hear it might be unstable on that platform.

  7. Thank you! With this you could connect a sd memory and boot from there as they currently do from a usb memory? I need to set kmod-mmc-spi or kmod-mmc-over-gpio?

      • Thanks any way. I find that i can use any of the gpio pin’s avaible of the wr-3020.

    • Hey Dude, yes you can boot the sd as an SPI chip, you have to use a 2gb or less drive preferably, the easiest way is to connect the SPI of the orifinal flash in chain mode, you should connect all the pins of the spi except the Data Out, look around if you see a capacitor in this pin going to the cpu, if you find it then good, remove and save the capacitor and solder the the data out of original spi flash to the data in of the sd, and the data out of the sd to the data out going to the cpu via the bypass capacitor you removed, the cap value isn’t as critical if you loose orig one btw..
      If your circuit doesn’t countain the bypass capacitor, then you’ll have to lift a little the DO line in the SPI flash just enough to desolder it from the pad and solder the aftermentioned connections in the pad and in the spi DO

  8. randomcoderdude,

    Thanks for the contribution! I’m using this on a pogoplug mobile (the $10 device) and while it’s working fine in 8-bit mode I’m seeing different behavior using spidev-test when I set bits per word to 16 (the /CS line doesn’t seem to get released between transfers). Are you aware of any limitations using this driver for non-8bit transfers?

    Bob

  9. Hi Bob,
    my module only allows to dymanically create the SPI bus/devices and does not add any limitation on its own.
    I had a quick look but i can’t give you a precise answer, you probably need to play with the ‘bits_per_word’ and ‘len’ fields of the ‘struct spi_ioc_transfer’.

  10. Hi

    I tried to run this command:
    insmod spi-gpio-custom bus0=19,7,29,26,0,1000,0,2,125000,17

    After that in /dev folder I got this devices: spidev19.0 and spidev19.1
    According to https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/spi/spidev?id=refs/tags/v3.10.6 the naming of devices is like this: spidevB.C where B is the bus number and C is the chip select.

    As you can see only the bus number is ok (19). The chipselect for the first device is 0 and for the second device is 17 but according to the device names from /dev the chip selects are 0 and 1.
    Is there a way to see what GPIOs is every spidev device using after I created them?

    • Hi,
      I’m a bit rusty on the matter but i think the “chip select” on spidevB.C is just an “index” of the chips selects on that bus, not the actual GPIO number.
      I don’t know if there’s a way to see the used GPIOs given an existing spidev device. Technically an spidev could be using a hardware SPI instead of a bitbang one so i doubt the GPIOs are published somewhere as a “property” of that spidev.

  11. Hello randomcoderdude, thanks for your great job. But I have some problems when I use SPI module. First of all, I selected kmod-spi-bitbang, kmod-spi-dev,kmod-spi-gpio and kmod-spi-gpio-custom in menuconfig when I compiled the firmware, and then I did all the preparations just as your tutorial. But when I use the insmod spi-gpio-custom command it shows “kmod: module is already loaded – spi-gpio-custom”, and it has no spi file under /dev directory. I couldn’t find out what was wrong. Do you have any ideas about that? My platform is MT7620N ramips openwrt3.10.44.

    • If i remember correctly, you can either compile kernel extensions as “module” or “compiled-in”.
      Module means that a .ko file is produced and you can load/unload it in the kernel when you want using insmod/rmmod.
      Compiled-in means that the module is compiled directly in the kernel and thus permanently “loaded”. This won’t work of course because you want to load the module giving it the parameters.

      The whole idea of my module was to avoid recompiling the kernel: you should be able to use a stock OpenWrt image and just “opkg install kmod-spi-gpio-custom” (downloads the pre-compiled binaries for your platform).

      If you’re trying to save space by compiling stuff directly in the kernel, you can define the spi devices statically instead of using my module. Here’s an example: http://elinux.org/BeagleBoard/SPI
      I haven’t done this myself (it’s not what i wanted to do) so i can’t help you down this route. You should probably google “spi_board_info” and “spi_register_board_info”.

      Hope this helps.

  12. Hi,

    I want to cross compile your code again for mips instead of directly using the .ko file provided by you. Is it possible?

    Thank you.

    Regards,
    Malay

      • Hi dude,

        cross compiling your spi-gpio-custom.c driver for android source(kitkat,marshmallow and above) from linux host machine will it make spidev enabled on the board(qualcomm snapdragon)?

        If there is no issues then can you provide me the makefile for that..

        include $(TOPDIR)/rules.mk
        include $(INCLUDE_DIR)/Kernel.mk
        include $(INCLUDE_DIR)/package.mk

        which PATH i need to assign for above three .mk files with respective andriod kerenl.

        Thanks,
        Praveen.

      • I don’t know… I’ve done this long ago and I’m not familiar with android at all.
        Plus, I’d bet on full-featured platforms there are better and more flexible solutions like device tree.

  13. Hi,

    I have successfully cross compiled this for mips. Now I am installing this module at command line but I am getting this error : “spi-gpio-custom: bus 0 already exists” in dmesg.

    Regards,
    Malay

    • Well, as the message says that bus already exists apparently. Your board might already have a hardware spi bus and be given that id. You should try to specify a different when you insmod.

  14. I am trying to use your module in raspberry pi (raspbian 3.18.13+). I wanted to install it since hardware SPI (spidev0.0 and spidev0.1) is already taken by lcd+touchscreen and I want to connect more devices via SPI. I have succesfully compiled it for my kernel version, however anytime I try to install it:
    sudo insmod spi-gpio-custom.ko bus1:1,0,5,6,0,100000,4
    or
    sudo modprobe spi-gpio-custom bus1:1,0,5,6,0,100000,4
    ( spi-gpio-custom.ko is in /lib/modules/3.18.13+/)
    I get this error:
    could not insert module spi-gpio-custom.k0: No such device

    Any ideas what am I doing wrong?

    • The insmod should use “bus0=” not “bus1:”. The number is just the number of the bus you’re defining within the command itself. The first number after the ‘=’ is the actual bus id. And i don’t think it can be replaced with ‘:’.

      • Thank you for your quick response. I tried many different commands. With bus0 instead of bus1, I get exactly the same error. When I change ‘:’ to ‘=’, the error message changes to:
        could not insert spi-gpio-custom.ko: Invalid parameters

        Since I am a total newbie in any unix systems, maybe I made some mistakes while compiling the module for my kernel vesion (I am not really sure how to do it correctly). Actually I am assuming that since I managed to compile it, it should be working. However, maybe that’s the case.

        To compile it I edited Makefile (in src/package/spi-gpio-custom/src):

        obj-m += spi-gpio-custom.o
        all:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
        clean
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

        and then I used ‘sudo make’. I had a lot of problems due to missing linux headers, but in the end I managed to compile it. Without changing the Makefile I get a message ‘nothing to make’. I am assuming this is because I did not add CONFIG_SPI_GPIO_CUSTOM to config.txt, and Makefile in this form does not require adding it.

        If that helps – right now I am running raspbian 3.18.13+ kernel (somehow) compiled by myself using the default config.txt for raspberry pi (B+).

        Is it the case that I did not compile it alongside with other modules while building my kernel ?

      • I’m not an expert either, but I think you compiled it properly if you get just errors instead of kernel panics.

        As suggested in the Troubleshooting paragraph, you should look at the kernel log for more info on what’s going wrong.
        I can’t look at the source code right now but it looks like some of the gpio pins you specified are not valid. I have no direct experience with the Rpi but a quick Google search shows that there are different numbering schemes:
        http://wiringpi.com/pins/
        I /think/ that the kernel uses the BCM numbering. That can be different depending on the hardware revision of the Rpi so you should double check you chose the correct values.

  15. Sorry, I forgot about dmesg. What I am getting after using insmod (with bus0=1,…) is ‘unable to get master for bus 1’ which means spi_busnum_to_master function fails. I tried running insmod with different pin sets with no luck so far (I assume BCM numbering is correct, but I also tried insmod with different numberings).

  16. Ow wow, thank you! I managed to load it. You were right – modules spi-gpio and spi-bitbang were not present (they are not enabled in the default raspbian .config). I have recompiled it and now everything works like a charm!!
    I stupidly assumed they must be somewhere since hardware spi is working and they are in the default raspbian source and I am just lacking knowledge how to find them. So stupid :/ Well, we are learning everyday:)
    Thank you for your time and help!

  17. I can not see the point to have bitbanged SPI, every OpenWrt driven router has hardware SPI, this is were the flash firmware is read – write. Can’t we just use a single gpio for chip select “CS” and attach any SPI device?

    • I can think of a few reasons…You might need more than one SPI port or need an SPI port that’s slow enough that it would significantly affect the performance of the hardware SPI port used by another device (like the flash)…

      • OpenWrt read the flash SPI only on boot time, after that we seldom use read-write op on SPI chip. But the free gpio are rare on routers, we shoul use the wisely.

  18. anyway randomcoderdude did exelent job! We need more dudes like him 🙂
    I mention hardware SPI to encurage him to think in this direction…and who knows…maybe we get lucky and have “kmod-hardware-spi”…just dreaming 😉

    • Wups, i didn’t notice your message until now…
      Sorry, i don’t plan to do another module to add SPI devices at runtime on an existing bus.
      But if you really want to do it i think you should be able to a new entry in the SPI bus definition on the machine hardware definition and recompile the kernel. Not a 5 minute job of course.

      For reference, the MR3020 hardware registration is in
      /target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3020.c
      and it calls ath79_register_m25p80() defined in
      /target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.c
      which defines the SPI for the flash.

      I can’t tell you exactly what to do because i honestly don’t remember much about it but if you want to experiment this is where you want to look.

  19. Hi randomcoderdude,
    Thank you for your job, it’s very nice!
    I read the comments above and I could add an answer at why would we not use spi from hardware? Hardware spi for the Ralink MT7628 is designed for flash as you said but when you want to connect a transceiver (at86rf230 for instance), the spi is not designed to send a message of 127 Bytes! So it is impossible to use (messages are limited to 32 Bytes by hardware)
    I tend to use your work to connect the at86rf230 to my board. My concern is that I’m wondering how to connect the at86rf230 driver with the fresh created spi driver?
    I mean that I used the dts to connect the at86rf230 to the hardware spi bus before. How should I do now?

    • I’ll start saying that I’m not sure what “dts” stands for… “device tree” related?
      If i understand correctly you want to create the software SPI and use it with another driver instead of spi-dev.
      This can’t be done with the module described in this page as it will always bind the device to spi-dev.

      • Yes dts was for Device Tree Source file. I found a way to make it work. Thank you anyway, you job is great! Continue in this way

  20. Hi, this is excellent work, and very very helpful for all those chipsets out there without an available hardware SPI (or a SPI that doesn’t support your mode). Great job!

    I’m having trouble loading the module on the Vocore (3 different OpenWRT bases, vocore “stock”, barrier breaker, and current working Chaos Calmer snapshot compiled for “Target System (Ralink RT288x/RT3xxx)”, “Subtarget (RT3x5x/RT5350 based boards)”, “Target Profile (VoCore)”). I’ve selected the spi-bitbang, spi-gpio compiled in, and spi-gpio-custom as module, I’ve also removed any other module using gpios, and selected gpios that appear to be available in /sys/class/gpio/. However, when I load with various command line options (different pins, bus/id, etc), I always get an error when inserting, like so:

    root@OpenWrt:/tmp# insmod spi-gpio-custom bus0=1,12,13,14,0,1000

    And dmesg gives:
    [ 125.570000] spi_gpio spi_gpio.1: no of_node; not parsing pinctrl DT
    [ 125.570000] spi_gpio: probe of spi_gpio.1 failed with error -16
    [ 125.580000] spi-gpio-custom: unable to get master for bus

    I’ll post this on the Vocore board as well as there is a good chance its device-specific. Has you seen this error or have any pointers?

    • I’m not sure what the problem could be unfortunately. My only comment is that -16 is probably -EBUSY.
      Can you control those pins manually using /sys/class/gpio? If they’re already there maybe you need to unexport them to let them be used exclusively for the spi.

      • Thanks for the hint, this is really helpful. I had done some work with GPIOs (I can change direction on the exported ones, change values and read values) but hadn’t checked whether I could unexport those pins, and that appears to be a problem. I should be able to unexport these if they’re not being used, right? Here’s what I get (no kernel messages) when I try to unexport an available (and unused) GPIO pin:

        root@OpenWrt:~# cd /sys/class/gpio
        root@OpenWrt:/sys/class/gpio# echo “12” > unexport
        ash: write error: Invalid argument

        This seems like a device tree issue, so I went to modify target/linux/ramips/dts/VOCORE.dts to get this to work. I simply removed the explicitly defined GPIOs I wanted to use and it works now. Thanks again!

  21. Hi randomcoderdude!

    I would like to use kmod-spi-gpio-custom. For my SPI RTC I have executed the following command successfully:

    insmod spi-gpio-custom bus0=1,3,4,5,0,1000000,1

    /dev/spidev1.0 is available.

    Now my question is if there is a way to connect it to the available driver at /sys/bus/spi/drivers/rtc-pcf2123 (Linux/drivers/rtc/rtc-pcf2123.c) ?

    Maybe this is a stupid question but I am new to this kind of playing around….

    Thanks in advance!

    • Hi, you can’t do that with my module, it was only meant to give direct access to the SPI bus to userland processes. But if you have a look above you’ll find that another user (Tist) managed to do what you want with device tree. I have no idea how that works though.

  22. Can you give me the source code? (or where can i find it)
    Also under which license is the code?
    I want to create some modules like yours (i2c, UART, AVR programmer)

    • The source code is in the downloads in this page and on the OpenWRT repository.
      The license is GPL, see the source code.
      In OpenWRT there’s already a module for i2c. I don’t think you can do an UART on GPIO because you can’t guarantee the timing.

  23. HI. I connect my tp-link mr3020 (firmware OpenWrt Attitude Adjustment r33482) with 7 segemnt display on max7219 over SPI (gpio: 7-CLK, 29-MOSI, 10-CS).
    Copy you spi-gpio-custom.ko from folder bin\ar71xx (it`s right?).
    Make insmod spi-gpio-custom bus0=1,7,29,9,0,1000,10 and see
    Where error?

  24. Hi. Thanks for this great article. I am trying to program an SPI flash of another device connected to my TL-MR13U router.

    I’ve successfully built an image with disabled UART and used 3 other free GPIOs along with RX pin as CS:

    insmod spi-gpio-custom bus0=1,16,14,0,0,1000000,9

    However there is not much info on SPI flash programming via GPIO, most of the tutorials are about controlling other devices so I’m stuck at trying to read data from and write back to flash chip.

    First I’ve tried read flash using dd command but the resulted file was empty, with all zeroes. Writing bootloader to device the same way finished much faster and of course it didn’t boot because probably nothing was written.

    Any idea how to interact with SPI flash?

    • The SPI allows to talk to the flash chip but you need to implement its protocol to actually do stuff. You should find the protocol on the datasheet.
      If the chip is already supported in Linux, you should probably just load its driver instead of spi-dev.
      To do that you’ll need to statically define a config in the kernel or use device-tree. The latter is probably you best option, unfortunately I’ve never tried it and I’ve been out of the loop for a while so I don’t have anything more to tell you. This is the best advice I can offer…

  25. Hey I am trying to connect AR9331 with PIC18 using this SPI package. I am able to get communication between 2 devices but not the way I want. Both device are not able to read each other correctly. For example if I send a character ‘a’ from 1 device to another, the other device outputs it as garbage or some unknown decimal number.
    Can U help me on this?

      • Hey I have checked it on Oscilloscope. Turned out that my AR9331 module is not generating the clock which I want it too. How can I make it to generate a clock of 4MHz? As according to this blog I use to command
        “insmod spi-gpio-custom bus0=1,18,19,20,0,4000000” but the Clock appears on Osciloscope is around 500KHz.
        Any suggestion???

      • That parameter is the *maximum* clock frequency. The bitbanging module will make sure not to exceed that frequency but, as it’s not a real hardware SPI, it can’t go too fast. Any way, that’s not likely to be your problem as your device will probably work just fine at 500 kHz too. Check the SPI mode instead.

      • Hey sorry to bother U again…. I have tried with different modes of SPI and this time I tried to get communication between two same AR9331 modules, but same result… In between garbage values I recieve the exact what I sent but most of the time its garbage… I am sending data using echo command manually, is it something that I am missing, like controlling the CS pin of slave or some other option???

      • The kernel modules mentioned in this page only support SPI as master, so I’m not sure how you’re trying to communicate between two Linux master devices.
        If the SPI slave has a CS then you probably need to drive it as well. Everything you need to know will be in the datasheet. Other than that I can only suggest again to check the signals with an oscilloscope.
        Sorry if I can’t be very helpful but your problem is quite specific to your setup.

  26. Hey randomcoderdude,

    I’ve been following your work for sometime. I’m a bit at loss however with something. There seem to be some questions similar to mine, however there is no definitive answer, so I decided to ask you.

    If I’m working with a hardware SPI I can write a DTS (device tree source) file where I can essentially describe my SPI connected device (let’s say it is a transceiver of sorts) and disable the corresponding spidevX.X device. If there is a kernel module for my SPI peripheral I’ll modprobe it and the device will be visible to the kernel and OS. Is there a way to do that with your bitbanged SPI. If there isn’t however, do you think that there is even a way to implement that in case we are lacking either a hardware SPI device or access to the hardware SPI.

    Also another question. Let’s say I have a device that I can can connect through SPI and I bitbanged spidev0.0. This device does not have a kernel driver or can be used through the spidev0.0. In my source code for communicating with this SPI device I need to define pins/GPIOs where my MISO, MOSI, CLK, CS are. In that case do I supply the ones I used for bitbanging or is this code and device specific. I’m not sure if my question makes any sense. When communicating with such devices on RPi, I need the spidev visible in the kernel, but I also define the where my signals are either with WiringPI or in my source code for specific pin assignments like CS for example.

    All of the above I can easily do on a RPi or even on devices that have hardware SPIs, even on MIPS, however I’m interested in doing at least some of those on home routers like the TP-Link Atheros ones.

    • I’ll try my best to answer the 2 questions:

      1) It should definitely be possible use DT to load spi-gpio-spi-bitbang as the SPI for another module that uses this kind of bus.
      I don’t have any direct experience with DT but this seems to be what you need to do in a RPi: http://www.sciencegizmo.com.au/?p=105

      2) I’m not sure I understand the question. The bitbanged spi we described so far is a “proper” Linux SPI bus and it’s instantiated either with a DT or some other way in kernel mode. You source code does not need to know which pins are used, it should only be told to use the resulting SPI. If you have direct references to the GPIO pins in the source code it sounds like the code is doing the bitbanging “manually”, in which case you don’t need any kernel stuff. This second case might be ok if you don’t need to transfer much data but generally speaking the performance is worse than an SPI in kernel mode (depends on how the GPIOs are accessed).
      Perhaps if you point me to the source code I can see what you’re talking about.

      Talking about the OpenWrt, you might have less freedom then in the RPi or BBB. Those are development platforms and, since it’s expected that the user will attach some custom hardware, I’m pretty sure they support DT.
      Last time I looked into this stuff I didn’t see DT support in this TP-Link router. You should check now.
      If there’s no DT support then my kernel module allows to instantiate the SPI but it also automatically binds it to an spidev, which I’m still not sure if it’s what you want or not.

  27. Hey randomcoderdude,
    I really appreciate your work.
    I have the following problem working with Dragino:
    1- device files under /dev aren’t created
    2- [ 730.460000] Custom GPIO-based SPI driver version 0.1
    [ 730.470000] spi_gpio spi_gpio.2: master is unqueued, this is deprecated

    And i have one more doubt: when I opkg install spi-dev no .ko file is added to /lib/modules/… is added so how does it work?

    Thanks

  28. I’m new to using openwrt. I was trying to set up my P99 module (with Atheros AR9344) which has openwrt LEDE running on it to communicate with another microcontroller. I tried using your SPI GPIO custom module.I ran the insmod command as per the directions provided in here and a corresponding device was created as”/dev/spidev1.0″.I then proceeded to probe the configured GPIO pins and noticed a total absence of signals in all the configured pins. Even the CS Pin is not low. I’m assuming that I missed some configuration setting. I have the following doubts:
    While running the insmod command, I specified GPIO numbers. As per the code documentation, it mentions “gpio pin IDs”. Is this the same thing?
    My module uses it’s default SPI band for communicating with the flash internally. Will this cause any sort of problems? I’m using GPIO pins other than the default SPI pins of the module which are marked software configurable in the datasheet.That should do the job, right?
    Any sort of help would be really helpful. Thanks in advance

    • Hi, it’s been ages since I did this so I don’t remember everything. If you don’t get any error, I suppose you might be using the wrong GPIO IDs. These are defined for each specific platform and might not be the same as the numbers on the SOC data sheet or board. Unfortunately I’m not sure where you can find these definitions.
      You probably want to look into device trees anyway, seems like they’re the modern approach.
      The hardware SPI used for flash is completely separate.

Leave a reply to blackketter Cancel reply