SSD1306 VHDL FPGA Implementation

I’ve been reading up as much VHDL as possible these last few days as I’ve recently found out that the majority of my summer is going to consist of writing it! After seeing loads of implementations for HD44780 16×2 character based LCDs, I couldn’t find any examples for the easy to get LCDs (by easy, I of course mean off eBay), SSD1306 based OLEDs, Nokia 5110 PCD8544 LCDs etc…

So, instead of cursing to myself why none exist, I decided to jump right in and get it done myself! The design process itself is quite simple when split into separate blocks and the first block I wrote was the SPI block because this was the easiest. SPI as I’ve mentioned before is a brilliant protocol consisting of a clock, a data out and data in line (named MISO and MOSI – Master In Slave Out, Master Out Slave In, in the industry), along with a chip select line. In my version, I have an SPI peripheral declared as a master, with a permanently low CS (a variable in the code selects whether CS toggles after every byte). The SPI peripheral I designed allows for CPHA and CPOL to be changed (though I’ve not really tested the other modes), along with a variable size data width and clock prescaler. A word of warning: The prescaler is an integer between 0 and 7. The actual amount of prescaling is equal to 2^(Presc+1) so if the prescaler is set to 1, the SPI clock out will be 4x slower than the master clock (or thereabouts). This allows for correct clocking of slower devices. The SPI peripheral has a parallel data load bus, along with a BUSY output signal and TRIG (trigger) input signal. On the falling edge of the TRIG signal, the parallel data is loaded into the shift register and the BUSY output is set high. Once the BUSY output goes high, the host can set the TRIG low again. Upon completion of the data shifting, the BUSY output goes low and the host controller should detect this falling edge and know the SPI peripheral is now free for more data transmission. As this application is only half duplex, the SPI MISO and parallel data out ports aren’t used.

The second block is the actual LCD controller. This block sends the correct SPI commands, along with reading the internal ROM and sending the graphic data to the LCD. This block controls the SPI peripheral and initializes the LCD before sending the graphic data, along with controlling the CD line on the LCD. This is where most of the magic happens!

The final block is the ROM itself. As I have an Altera FPGA, I’ll be using a single port RAM block. I’ve also designed the system using the block diagram method within Quartus and my simulations are done using the university vector waveform method.

Testing the SPI module
SPI driven LCDs generally support not having to use the CS pin during data transmission, allowing a continuous stream of data into the LCD without the host having to worry about toggling the chip select pin as theoretically, the chips already selected! For certain devices however, where the SPI input is merely a shift register without a data counter, the CS pin is needed to latch the data and indicate the end of a transmission.

Running a prescaler of 2, along with CS toggling being disabled.

The same prescaler however, CS is set after the transfer is complete.

The fastest prescaler. Four clock cycles are required per SPI clock cycle giving a maximum clock speed of 12.5MHz with a 50MHz system clock.

Zoomed out view of the above.

Obviously, it can be seen above that the SPI interface is working. on the falling edge of the TRG input (trigger), the SPI transaction is initiated and data is shifted out as expected. During this, the BSY (busy) line is set high, indicating an SPI transaction is currently happening.

Adding in the LCD controller
The LCD controller sends data and controls the SPI peripheral through the BSY and TRIG lines. Inside the LCD controller is an array containing all the instructions required to initialize the LCD, along with the code required to interface the internal ROM and write the pixel data to the LCD. The image (as ever!) was dithered and scaled in Matlab, the bits packed and written into a .MIF file (all within Matlab actually…), which can be ready directly by the Altera compiler. The image is of my landscape test scene as ever and from far away, looks… acceptable!

QSim2_Shifting out data
Attaching the LCD controller and shifting data out! As CPHA = CPOL = 0, the clock idles low and the data is valid on the rising edge.

As can be seen in the image above, the first command is 0xA8, shifted out of the SPI peripheral, as controlled by the LCD controller, wahoo!

For simulation purposes, the clock has been increased and the prescaler decreased. The initialization phase and graphics data write phases can easily be seen by the CD transition.

And just to prove it works…

Displaying my dithered test landscape scene on an SSD1306 OLED display!

I’m not cheating! It really is connected to my FPGA.

Thankfully, my FPGA development board features an easily interfaced IDC connector socket.

I’ve got the whole project up on Github for those who want to pick through my poor commentless VHDL…

2 thoughts on “SSD1306 VHDL FPGA Implementation

Leave a Reply to hshallcross Cancel reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s