r00x
Posts: 41
Joined: Mon Feb 04, 2013 11:05 am

Primary display via SPI?

Mon Feb 11, 2013 9:58 am

Hey all,

Apologies for the broad question. I've been reading and searching on this subject for over a week now and I'm lost. I find lots of information but can't quite seem to tie it together. Here's the situation:

- I know how to drive displays (very well in fact, I make demos for lots of them at work - character, graphic, OLED, TFT, various interfaces, etc). But I've always used microcontrollers or FPGAs to do this.

- Despite this I am an idiot when it comes to Linux. I don't think I've spent more than a year cumulatively on Linux-based platforms in my lifetime.

- I can already see how I might create a standalone application in C or Python which would drive a display. I will experiment with this first, as it's easier (also I need it for some specific projects anyway).

- But I want to create a proper 'display driver' which can be used to both (a) run the display from boot as the primary display and (b) run it as a secondary display I can point things like image viewers, games or video players to. This is where I'm getting lost! :D

- I know it won't perform like lightning and it can be resource intensive, that is fine.

- I'm not interested in X support or anything - would be a bonus, but I'm interested in displaying the command line, videos, games, images etc. Don't think I've ever plugged a mouse into my Pi, haha.

- I'd prefer not to use a 'library' file if possible and actually learn to implement everything myself. There are lots of cool displays I want to try with my Pi so I'll be doing this over and over again!

I could facilitate 50% of what I want to do without writing a 'driver' and using the display as a traditional display device. For example displaying images, text, bespoke graphics etc could all be done manually in my software. But I really want to achieve this final step! Having a display built into my Pi's casing would be awesome.

Please, does anyone know of a concise series of documents/threads which describe how one writes and installs a piece of software which will pipe everything to this display as if it were the normal HDMI/composite output? Perhaps it is not possible to get it to do that immediately from boot, but perhaps by the time it hits the bash login prompt it could be operational?

Am I correct in thinking this involves /dev/fb0 (or dev/fb1 as a 'secondary' display)?

notro
Posts: 695
Joined: Tue Oct 16, 2012 6:21 pm
Location: Drammen, Norway

Re: Primary display via SPI?

Mon Feb 11, 2013 4:21 pm

I have written a kernel module that tries to make it easy to write framebuffer drivers for small TFT LCD displays.
Source: https://github.com/notro/fbtft
Wiki: https://github.com/notro/fbtft/wiki
Video: http://youtu.be/0vfDifIU7gw

I have ordered these to be my next addons to the project:
* http://imall.iteadstudio.com/display/tf ... 19009.html (challenge: 8-bit bus)
* https://www.adafruit.com/products/338 (challenge: monochrome, 1 bpp)

I'm currently reworking the io part of the project, so there will be a major commit later today I hope.
This is to prepare for displays that has a parallel bus instead of SPI.
Am I correct in thinking this involves /dev/fb0 (or dev/fb1 as a 'secondary' display)?
Correct.

This is the default video driver

Code: Select all

# Show info about /dev/fb0
fbset -i

mode "656x416"
    geometry 656 416 656 416 16
    timings 0 0 0 0 0 0 0
    rgba 5/11,6/5,5/0,0/16
endmode

Frame buffer device information:
    Name        : BCM2708 FB
    Address     : 0x4c006000
    Size        : 545792
    Type        : PACKED PIXELS
    Visual      : TRUECOLOR
    XPanStep    : 0
    YPanStep    : 0
    YWrapStep   : 0
    LineLength  : 1312
    Accelerator : No
This the Adafruit 2.2" display supported by fbtft:

Code: Select all

fbset -i -fb /dev/fb1

mode "176x220"
    geometry 176 220 176 220 16
    timings 0 0 0 0 0 0 0
    nonstd 1
    rgba 5/11,6/5,5/0,0/0
endmode

Frame buffer device information:
    Name        : adafruit22fb
    Address     : 0
    Size        : 77440
    Type        : PACKED PIXELS
    Visual      : TRUECOLOR
    XPanStep    : 0
    YPanStep    : 0
    YWrapStep   : 0
    LineLength  : 352
    Accelerator : No
Some references:
* http://www.whence.com/rpi/
* http://spritesmods.com/?art=rpi_arcade&page=2
* http://duff.dk/wrt54gs/fb-lcd.c
* http://en.wikipedia.org/wiki/Linux_framebuffer
* http://www.kernel.org/doc/Documentation ... buffer.txt
* http://www.kernel.org/doc/Documentation ... red_io.txt

r00x
Posts: 41
Joined: Mon Feb 04, 2013 11:05 am

Re: Primary display via SPI?

Tue Feb 26, 2013 6:49 pm

Fascinating stuff! Thank you for all the info and links.

I've been cracking on with getting a little OLED to run via SPI and I have another question.

At present, I'm not implementing framebuffer support or anything - just simply initialising the display and filling it with colour.

What I'd like to know is, how fast are we supposed to be able to push hardware SPI for single byte transfers? Setting the speed is fine (currently running at 8MHz) however I'm finding it still takes about five seconds to fill a 160x128 pixel display with colour. Probing the SPI lines reveals large delays (fractions of a millisecond) between transmissions.

The transfers themselves are lightening fast but there seems to be massive overhead in the software. This is presently written in Python (and communicating via SPI with code written in C). Do you think Python introduces that much overhead? I've seen videos of smooth framerates on SPI displays on Raspberry Pi so I know I'm doing something wrong. Needless to say I will be writing the final software in C! :D

notro
Posts: 695
Joined: Tue Oct 16, 2012 6:21 pm
Location: Drammen, Norway

Re: Primary display via SPI?

Wed Feb 27, 2013 11:37 am

I've been cracking on with getting a little OLED to run via SPI
Do you have a link to that display?
What I'd like to know is, how fast are we supposed to be able to push hardware SPI for single byte transfers?
My tests have shown 32MHz to be the maximum loopback speed: http://www.raspberrypi.org/phpBB3/viewt ... 20#p282220
Probing the SPI lines reveals large delays (fractions of a millisecond) between transmissions.
I think this thread discusses the issue: http://www.raspberrypi.org/phpBB3/viewt ... 44&t=19489
Do you think Python introduces that much overhead?
I think single byte transfers is your performance problem. Try pushing larger chunks of data at a time. By default spidev can handle 4096 byte messages.

What Python SPI module are you using?

r00x
Posts: 41
Joined: Mon Feb 04, 2013 11:05 am

Re: Primary display via SPI?

Wed Feb 27, 2013 5:20 pm

Yes I should imagine it would be more convenient to use larger transfers! This may work well for putting content on the display, where it's just a sequential stream of pixel data. :)

Currently the display is configured for 8-bit transfers. The initial instructions and data used for init are always 8-bit transfers.

Those initial instructions -which must be 8-bits each- must be synchronised with one of the Pi's GPIO pins. There is a register select line which is used by the display to differentiate between incoming 'commands' (addresses in the index register) and incoming data).

Once ready to write pixels, the GPIO is set once (for 'data') and then never touched again (hopefully saves a little unnecessary CPU time seeing as all data thereafter will be 'data' and not commands).

For display data I have the option of up to 18-bit transfers (in which case the display would be approximately 3 times faster than it is currently, but still only one frame per second, maybe). It is possible that the display will even accept 16 or 18-bit transfers during initialisation if the remaining bits are just 0-padding, as hopefully they will just roll off the end of the buffer.

For display data, longer still transfers would be possible (the display should process every 16 or 18 bits if data keeps streaming in) but not recommended without toggling the CSB line. Still, being able to rattle out even just one line's worth of data (2880 bits) in a single transfer would result in several frames per second, I think.

I can configure the display to auto-increment and loop address pointers (already done) and easily stream oodles of pixels to the display by increasing the transfer size from the Pi.

Is it easy to shut down the SPI peripheral and start it back up in a mode which accepts longer transfers? So I could init the display with 8bits per transfer and synced GPIO before switching to ~2880 bits for the display data?

The display is a 160x128 OLED module I borrowed from the lab at work (shh) :lol: . It's based on the Syncoam SEPS525 IC, which is a really nice IC and quite easy to use. I have the option of parallel buses of various widths (18, 16, 9, 8-bit) as well as SPI, but I figured SPI would be least stressful on the Pi's CPU and it's certainly a lower wire count :D

notro
Posts: 695
Joined: Tue Oct 16, 2012 6:21 pm
Location: Drammen, Norway

Re: Primary display via SPI?

Wed Feb 27, 2013 6:39 pm

Is it easy to shut down the SPI peripheral and start it back up in a mode which accepts longer transfers?
I haven't tested this with code, but you can unload the driver and load it with the bufsiz parameter

Code: Select all

# modinfo spidev
[snip]
parm:           bufsiz:data bytes in biggest supported SPI message (uint)

# rmmod spidev
# modprobe spidev bufsiz=16384
I just remembered one thing: If the transfer takes longer than 150ms, it will abort with a timeout.
See the SPI Controller driver code: https://github.com/raspberrypi/linux/bl ... -bcm2708.c

Code: Select all

#define SPI_TIMEOUT_MS	150
So I could init the display with 8bits per transfer and synced GPIO before switching to ~2880 bits for the display data?
I'm not sure what you mean by this. 2880 bits is well within the 4096 bytes size.

r00x
Posts: 41
Joined: Mon Feb 04, 2013 11:05 am

Re: Primary display via SPI?

Wed Feb 27, 2013 7:26 pm

Thanks for the tip, I'll have a poke at that! :)

If I'm not mistaken, ~2880 bits should take less than a millisecond @ 8MHz, assuming the transfer is smooth and steady from start to finish. (2880/8000000 = 0.00036 seconds).
So I could init the display with 8bits per transfer and synced GPIO before switching to ~2880 bits for the display data?
I'm not sure what you mean by this. 2880 bits is well within the 4096 bytes size.
I see... This may be an artefact of the SPI module I'm using rather than the peripheral itself. Right now, I load the module and can define a bit depth when initialising SPI. So I would have to initialise at 8bits per transfer, then switch to 2880 bits (or the data will not be transferred).

Your comment suggests that this is not the way the peripheral itself works - if you're interfacing with SPI directly (in C I suppose) do you not need to tell the peripheral how many bits to expect for a given transfer? Will it just spew out however much data you chuck its way (up to 4096 bytes)?

The module I'm using is based on the code provided by this chap who, in turn, based his code on the spidev_test.c module provided by a certain Mr Torvalds on Github :lol:

I took the code and modified the crap out of it to speed it up (which worked significantly) but beyond that I haven't looked in too much detail at what it was actually doing (first and foremost I wanted that screen to run). So I guess I'll be looking over that a little more carefully now to really see how it's working :D

notro
Posts: 695
Joined: Tue Oct 16, 2012 6:21 pm
Location: Drammen, Norway

Re: Primary display via SPI?

Wed Feb 27, 2013 9:53 pm

So I would have to initialise at 8bits per transfer, then switch to 2880 bits
Looking at the Web page you referred to, I see a typo:

Code: Select all

spi.initialize(MODE, BITSperMESSAGE, SPEED, DELAY)
This should be bytesPerMessage according to the code on github.

The SPI hardware on the PI is only capable of 8 and 9 bits per word, and only 8 bits is supported by the SPI Controller driver spi_bcm2708.
So I guess I'll be looking over that a little more carefully now to really see how it's working
This is the chain of events when uing the Python module:
* transfer() is called with a tuple of 'bytes', copies this to a uint8_t buffer, constructs a spi_ioc_transfer and sends this to spidev using an IOCTL
* The spidev kernel module receives the message, copies the data from user space to kernel space and passes it to spi_bcm2708
* The SPI Controller driver, spi_bcm2708 sends it in 16 byte chunks to the SPI hardware FIFO using interrupts

I will suggest you start out with 16-bits per pixel as this is exactly 2 bytes. 18 bits requires a lot of bit shuffling to get into 8 bit boundries.

c.germaine
Posts: 1
Joined: Thu May 30, 2013 10:01 am

Re: Primary display via SPI?

Thu May 30, 2013 10:22 am

Hello r00x,

Did you finally write a framebuffer device for the SEPS525 using notro's fbtft drivers?

Cyril

Return to “Interfacing (DSI, CSI, I2C, etc.)”