Want the library? Find it at Github.
So we're always cooking up hot new hardware in the Grav Corp labs. Recently, we've been working on a project using a 128x64 OLED screen with the SSD1306 controller. Adafruit is a good source of these displays, with an excellent library written by Limor Fried. The Adafruit_SSD1306 library makes it simple to use these displays with a variety of Arduinos, using either software or hardware SPI. However, we wanted a speed boost, and the Due looked like it could deliver, with its DMA (Direct Memory Access) capability.
So what is DMA? Direct Memory Access, as simply stated by Wikipedia:
Direct memory access (DMA) is a feature of computerized systems that allows certain hardware subsystems to access main system memory independently of the central processing unit (CPU).
We wanted to use the DMA capabilities of the Arduino Due's SAM3X8E microcontroller to speed up calls to the display() function, which writes the display buffer to the OLED controller. With stock settings using hardware SPI, calls to display() take ~2ms on the Due. This is a long time to tie up our CPU, so what can we do to improve this?
Like all good endeavours, this began with research. We hunted for anything regarding the SSD1306 and DMA but came up short. After digging deeper, we found Marek Buriak's library for ILI9341-based TFT screens. Marek used code from William Greiman, who developed SD card libraries for the Arduino. William took advantage of the SAM3X8E's DMA capabilities to enable faster SD card transfers, and Marek then adapted this code to allow faster writes to ILI9341-based screens. This is particularly useful, as the ILI9341-based screens are full-colour TFT displays, which require large amounts of data to write to. It was then simple to find the code to send a buffer out over SPI using DMA in Marek's code and adapt that to the Adafruit library for the SSD1306.
There is one caveat: as we are configuring the SPI hardware completely differently than usual, it is likely that this code is incompatible with the stock Due SPI.h library (though we haven't tested). This makes it difficult if you want fast writes to an SSD1306 screen AND to use other SPI hardware in your project. There is a workaround - replace your calls to SPI.transfer() with calls to fastSPIwrite() and spiRead(), however this may be buggy at this stage in the library's development and your mileage may vary. Any feedback or testing is welcome!
What kind of speed boost does this library give? Well, running at the same SPI clock as the Adafruit library (clock divider of 5 for SPI), we speed writes up from 2ms down to approximately 0.5ms. This is great! We can then go even faster by increasing the SPI clock (set divider to 2) and a display() call will only take ~0.25ms for a 128x64 display!
So, if you fancy trying out the library, head over to the Github page here. You can also discuss this library on the Arduino forums! Due credit to Limor Fried, Marek Buriak, and William Greiman who did the hard yards on their respective code. The internet allows great collaboration, does it not?