The display

I was keen to have a small LCD display on my MinnowBoard Max based computer. Adafruit have a wide range of LCDs1 including a fine 320×240 version.2

The LCD is controlled by a ILI93403 chip, which includes a framebuffer, so the MinnowBoard doesn’t have to send data in real time. Instead it sends commands over SPI which update the framebuffer.

The display PCB also contains a microSD card slot, but we can ignore that.


The display has ten pins, of which we use eight:

LCD LegendSignalMinnowBoard Max
BLBacklightpin 21GPIO 338
SCKSPI clockpin 11
CSDisplay selectpin 5
SDCDSD card selectunused
RSTResetpin 23GPIO 339
D/CDisplay modepin 25GPIO 340
VINVccpin 35V
GNDGroundpin 10V

Userspace ILI9340 drivers

Adafruit have written a python library for the ILI93404 which you can (in principle) use with the MinnowBoard Max with my (crude) port of the Adafruit Python GPIO library5

However, the code does not install or compile cleanly. If you are really interested, contact me.

The guts of the python library have been ported to C6 which is easier to use:

$ git clone
$ cd max-ILI9341-C-Driver-port/

Now edit the GPIO and SPI device numbers. Here are the changes I made:

$ git diff								
diff --git a/testprogram.c b/testprogram.c				
index 4be10e8..e2e3e3a 100644						
— a/testprogram.c							
+++ b/testprogram.c							
@@ -36,9 +36,9 @@ int main (int argc, const char *argv[])		
 #define INTERLACE 3							
-    data_command_select_fd = init_output_gpio (82);			
-    reset_fd = init_output_gpio (83);					
-    display_fd = init_spidev (32766, 0);				
+    data_command_select_fd = init_output_gpio (340);			
+    reset_fd = init_output_gpio (339);					
+    display_fd = init_spidev (0, 0);					
     ili_reset ();							
     ili_init ();

Now compile and run, but don’t forget to load the module to create the SPI userspace devices:7

$ make										
cc -std=c99 -g -Ofast -Wall -Wextra   -c -o testprogram.o testprogram.c		
testprogram.c: In function ‘main’:						
testprogram.c:29:15: warning: unused parameter ‘argc’ [-Wunused-parameter]	
 int main (int argc, const char *argv[])					
testprogram.c:29:33: warning: unused parameter ‘argv’ [-Wunused-parameter]	
 int main (int argc, const char *argv[])					
cc -std=c99 -g -Ofast -Wall -Wextra   -c -o ILI9341.o ILI9341.c			
cc   testprogram.o ILI9341.o  -lm -o testprogram				
$ sudo insmod .../low-speed-spidev.ko	
$ sudo ./testprogram 								

The FBTFT driver

On the Raspberry Pi, SPI driven displays are well supported. A chap called notro has written a fine framebuffer device8 for many different LCD displays.9

Compiling this device for the MinnowBoard Max was easy: I just followed the instructions. The only problem was that DMA didn’t work. I think I ought to be able to disable this from the command line, but I did not manage to get that to work. So I just patched fbtft-core.c:

— a/fbtft-core.c						
+++ b/fbtft-core.c						
@@ -52,7 +52,7 @@ static unsigned long debug;			
 module_param(debug, ulong , 0);				
 MODULE_PARM_DESC(debug, "override device debug level");	
-static bool dma = true;					
+static bool dma = false;					
 module_param(dma, bool, 0);					
 MODULE_PARM_DESC(dma, "Use DMA buffer");			

Module arguments

In principle one could write a board-specific kernel module to describe the LCD in use, and bind it to a specific SPI device.

Happily there is an alternative. The fbtft_device10 accomodates many configurations by suitable choices of its (many) module arguments. For my setup the magic runes are:

sudo modprobe fbtft_device name=adafruit22a speed=15000000 \
  gpios=reset:339,dc:338,led:340 rotate=270

The fbtft device supports a simple binary backlight: it is either on or off. Given the PWM possibilities of the MinnowBoard Max it is easy to have quasi-continuous control of the backlight, just not within the fbtft framework.

A Cairo example

Having created a suitable /dev/fb1 device (/dev/fb0 being the MinnowBoard Max’s main display) we will need something to drive it.

Cairo11 is a popular and featureful library for generating 2D images, and happily it’s easy to make it work with the framebuffer.

I found working code from Andrea Rossignoli12 on the Cairo mailing list which dates back to 2010. The only change I needed to make was to change /dev/fb0 to /dev/fb1.

Thank you Andrea.

Lest it disappear, I’ve put a copy of the code on github.13