Gaining Low-level SPI Access On The Raspberry Pi

Raspberry Pi - rpi

We’ve seen a ton of projects that interface hardware with the Raspberry Pi. But they usually depend on bit-banging. That means they toggle the pins in software to match a specific protocol. The thing is that the beefy Broadcom SoC that anchors the board has a lot of built-in peripherals that are just waiting to be used instead of bit banging. In this case, it’s the hardware SPI peripheral which can be accessed via the bcm2835 library for RPi.

One of the things that would have really complicated this process is the pin mapping between the Broadcom chip and the RPi GPIO header. Since not all pins are broken out, it was either luck or good design forethought that made all of the SPI0 pins from the chip available on the RPi breakout header. The library page (linked above) explains this well. But if you’re looking for more of a working example check out [EngineerByNight’s] project with adds an accelerometer using hardware SPI.

7 thoughts on “Gaining Low-level SPI Access On The Raspberry Pi

  1. @JC No doubt there are probably other ways to do this. If you find a way to successfully communicate with SPI accelerometer on the Raspberry Pi using “the linux input layer,” I’d like to know how you did it. I tried that route first, with little success… The linux drivers are out there, but little guidance (that I am capable of understanding) on how to use them.

    1. Well, the problem is that embedded developers rarely cooperate with upstream kernel developers. I’m afraid that maybe a proper input interface isn’t even there yet (?)

      That’s why I’d like to see HAD feature projects that do proper kernel work, preferably with stuff that made it upstream.

      Anyhow: here’s a very simple example on how it works in Freerunner (linux phone): http://wiki.openmoko.org/wiki/Accelerometer_data_retrieval

      Also nice:
      http://omappedia.org/wiki/Accelerometer

      Still not proper – uses ‘undocumented’ input events. But it at least goes through the linux event layer already.

      Even this has advantages already – you don’t need to poll the accelerometer, a platform driver can tie an interrupt to the accelerometer for example.

      For Freerunner (GP2X Caanoo – same problem): due to extremely common problem of ‘source page not up anymore and nothing related ever got upstream’, I’m sending a link to pastebin from my local git copy: http://pastebin.com/jr4ZzfAz

      First:

      static struct platform_device s3c_device_spi_acc1 = {
      .name = “lis302dl”,
      .id = 1,
      .dev = {
      .platform_data = &lis302_pdata_top,
      },
      };

      This is crucial – when you stick accelerometer on SPI bus, how is linux to know that it’s there? You’re basically ‘making your own board’. Don’t worry though – you can have both generic raspi platform data AND your own – and you can even compile it as a kernel module so that you don’t have to mess with replacing the kernel :)

      That piece there tells that theres an accelerometer present, handled by the lis302dl driver (your platform code should depend on that in kconfig ;P) and passes to it a pointer to already statically filled platform specific data structure.

      Lets look at that platform specific data that the accelerometer driver gets from your platform driver:

      struct lis302dl_platform_data lis302_pdata_top = {
      .name = “lis302-1 (top)”,
      .pin_chip_select= S3C2410_GPD(12),
      .pin_clk = S3C2410_GPG(7),
      .pin_mosi = S3C2410_GPG(6),
      .pin_miso = S3C2410_GPG(5),
      .interrupt = GTA02_IRQ_GSENSOR_1,
      ….
      (find the rest on pastebin)

      Well.. thanks to this, that accelerometer driver will have all it needs to know to register with the SPI bus driver and tell it how to prepare the SPI bus for it. And then the accel driver can work happily ever after, receiving interrupts and generating input event structures passed to the kernel and almost-proper magic happens :)

      Also look that there’s platform-specific interrupt handler code there too – very common. You can have multiple devices on single interrupt line, things that require special handling, etc.

      Basically, when you do an acceleromterer driver, only put functionality necessary for translating raw SPI data into xyz and other ‘logical’ things. Leave anything ‘not common to every platform that uses this accelerometer’ in the platform code.
      On the other hand: DON’T ever implement whole drivers in platform code. If anything could be reused, it should be a separate driver.

      You can see that the freerunner code is pretty ugly (bitbanging inside platform driver), the devs were on a tight schedule desperately trying to get it work right until the end. I haven’t seen a better one yey.

      PLEASE if anyone finds a better example, do share :)

  2. In a similar vein. I’ve been writing an i2c screen driver for my Raspberry Pi (part of a much larger project). It uses the kernel i2c driver model, so it might make a useful example to someone.

    I’ve uploaded the source to bitbucket:
    https://bitbucket.org/kernelcode/s4548/overview

    It presents a char device node for reading/writing or memory mapping, as well as ioctls for sending screen commands like on/off
    I’ll get a video up when I find another SD card – the one for my camera is running my Pi

Leave a Reply to kernelcodeCancel reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.